idle: Add an idle queue
The idle queue is used to schedule tasks ... later. This code was mostly adoted from a reference TDD experiment by Josh Larson (themutatedshrimp@gmail.com). Thanks Josh! Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
parent
5f30a71c55
commit
f417b48df8
3
config
3
config
|
@ -28,6 +28,7 @@ class Config:
|
||||||
self.FILE = False
|
self.FILE = False
|
||||||
self.FILTER = False
|
self.FILTER = False
|
||||||
self.GROUP = False
|
self.GROUP = False
|
||||||
|
self.IDLE = False
|
||||||
self.INDEX = False
|
self.INDEX = False
|
||||||
self.TEST = False
|
self.TEST = False
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ class Config:
|
||||||
if self.FILE: env.Append( CCFLAGS = [ "-DCONFIG_FILE" ])
|
if self.FILE: env.Append( CCFLAGS = [ "-DCONFIG_FILE" ])
|
||||||
if self.FILTER: env.Append( CCFLAGS = [ "-DCONFIG_FILTER" ])
|
if self.FILTER: env.Append( CCFLAGS = [ "-DCONFIG_FILTER" ])
|
||||||
if self.GROUP: env.Append( CCFLAGS = [ "-DCONFIG_GROUP" ])
|
if self.GROUP: env.Append( CCFLAGS = [ "-DCONFIG_GROUP" ])
|
||||||
|
if self.IDLE: env.Append( CCFLAGS = [ "-DCONFIG_IDLE" ])
|
||||||
if self.INDEX: env.Append( CCFLAGS = [ "-DCONFIG_INDEX" ])
|
if self.INDEX: env.Append( CCFLAGS = [ "-DCONFIG_INDEX" ])
|
||||||
if self.TEST: env.Append( CCFLAGS = [ "-DCONFIG_TEST" ])
|
if self.TEST: env.Append( CCFLAGS = [ "-DCONFIG_TEST" ])
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ class Config:
|
||||||
self.FILE = False
|
self.FILE = False
|
||||||
self.FILTER = False
|
self.FILTER = False
|
||||||
self.GROUP = False
|
self.GROUP = False
|
||||||
|
self.IDLE = False
|
||||||
self.INDEX = False
|
self.INDEX = False
|
||||||
self.TEST = False
|
self.TEST = False
|
||||||
self.reconfigure()
|
self.reconfigure()
|
||||||
|
|
|
@ -13,8 +13,17 @@ Idle queue: (lib/idle.cpp)
|
||||||
tasks must inherit from the IdleBase class so that multiple templated
|
tasks must inherit from the IdleBase class so that multiple templated
|
||||||
IdleTask pointers can be placed on the same idle queue.
|
IdleTask pointers can be placed on the same idle queue.
|
||||||
|
|
||||||
|
Creating an idle queue in idle.hpp will create a new queue for every
|
||||||
|
file that idle.h is included in. I want to have a single, shared
|
||||||
|
idle queue used by the entire application so to get around this the
|
||||||
|
IdleBase class is used and implemented in lib/idle.cpp.
|
||||||
|
|
||||||
- IdleBase:
|
- IdleBase:
|
||||||
class IdleBase {
|
class IdleBase {
|
||||||
|
private:
|
||||||
|
schedule();
|
||||||
|
|
||||||
|
public:
|
||||||
IdleBase();
|
IdleBase();
|
||||||
~IdleBase();
|
~IdleBase();
|
||||||
virtual void run() = 0;
|
virtual void run() = 0;
|
||||||
|
@ -24,30 +33,34 @@ Idle queue: (lib/idle.cpp)
|
||||||
template <class T>
|
template <class T>
|
||||||
class IdleTask : IdleBase {
|
class IdleTask : IdleBase {
|
||||||
private:
|
private:
|
||||||
void (*func)(T *);
|
void (*func)(T &);
|
||||||
T *data;
|
T &data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdleTask(void (*)(T *), T *);
|
IdleTask(void (*)(T &), T);
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
- Queue:
|
- Queue:
|
||||||
deque(IdleBase *> idle_queue;
|
queue<IdleBase *> idle_queue;
|
||||||
float queued = 0.0
|
float queued = 0.0
|
||||||
float serviced = 0.0
|
float serviced = 0.0
|
||||||
|
|
||||||
- API:
|
- API:
|
||||||
|
void IdleBase :: schedule();
|
||||||
|
Add the idle task to the idle queue. This should be called
|
||||||
|
by the IdleTask constructor.
|
||||||
|
queued++;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void idle :: schedule(void (*)(T *), T *);
|
static inline void idle :: schedule(void (*)(T &), T);
|
||||||
Schedule a function to run later (queued++). This should
|
Create a new IdleTask to run the function later.
|
||||||
be written in the idle.hpp file since it is a function
|
|
||||||
template.
|
|
||||||
|
|
||||||
bool idle :: run_task()
|
bool idle :: run_task()
|
||||||
If there are tasks on the queue:
|
If there are tasks on the queue:
|
||||||
run the next task
|
run the next task
|
||||||
scheduled++
|
scheduled++
|
||||||
|
If there are still tasks on the queue:
|
||||||
return true
|
return true
|
||||||
else:
|
else:
|
||||||
queued = 0
|
queued = 0
|
||||||
|
@ -56,4 +69,5 @@ Idle queue: (lib/idle.cpp)
|
||||||
|
|
||||||
float idle :: get_progress()
|
float idle :: get_progress()
|
||||||
Return (serviced / queued) to the caller. If there are no
|
Return (serviced / queued) to the caller. If there are no
|
||||||
tasks, return 1.0 to indicate that the queue is finished.
|
tasks, return 1.0 to indicate that the queue is finished (and
|
||||||
|
to avoid a divide-by-zero error).
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 (c) Anna Schumaker.
|
||||||
|
*/
|
||||||
|
#ifndef OCARINA_IDLE_H
|
||||||
|
#define OCARINA_IDLE_H
|
||||||
|
|
||||||
|
namespace idle
|
||||||
|
{
|
||||||
|
|
||||||
|
class IdleBase {
|
||||||
|
protected:
|
||||||
|
void schedule();
|
||||||
|
public:
|
||||||
|
IdleBase();
|
||||||
|
virtual ~IdleBase();
|
||||||
|
virtual void run() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class IdleTask : public IdleBase {
|
||||||
|
private:
|
||||||
|
void (*func)(T &);
|
||||||
|
T data;
|
||||||
|
public:
|
||||||
|
IdleTask(void (*)(T &), T);
|
||||||
|
~IdleTask();
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline void schedule(void (*func)(T &), T param)
|
||||||
|
{
|
||||||
|
new IdleTask<T>(func, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool run_task();
|
||||||
|
float get_progress();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "idle.hpp"
|
||||||
|
|
||||||
|
#endif /* OCARINA_IDLE_H */
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 (c) Anna Schumaker.
|
||||||
|
*
|
||||||
|
* DO NOT INCLUDE THIS FILE DIRECTLY. THIS IS A TEMPLATE DEFINITION FILE
|
||||||
|
* AND ONLY MEANT TO BE INCLUDED BY include/idle.h!
|
||||||
|
*/
|
||||||
|
#ifndef OCARINA_IDLE_HPP
|
||||||
|
#define OCARINA_IDLE_HPP
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
idle :: IdleTask<T> :: IdleTask(void (*fn)(T &), T param)
|
||||||
|
: func(fn), data(param)
|
||||||
|
{
|
||||||
|
IdleBase :: schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
idle :: IdleTask<T> :: ~IdleTask()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void idle :: IdleTask<T> :: run()
|
||||||
|
{
|
||||||
|
func(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* OCARINA_IDLE_HPP */
|
|
@ -27,6 +27,10 @@ if CONFIG.FILE:
|
||||||
CONFIG.package("glib-2.0")
|
CONFIG.package("glib-2.0")
|
||||||
build += [ env.Object("file.cpp") ]
|
build += [ env.Object("file.cpp") ]
|
||||||
|
|
||||||
|
if CONFIG.IDLE:
|
||||||
|
build += [ env.Object("idle.cpp") ]
|
||||||
|
|
||||||
|
####################
|
||||||
|
|
||||||
if CONFIG.TEST:
|
if CONFIG.TEST:
|
||||||
build += [ env.Object("test.cpp") ]
|
build += [ env.Object("test.cpp") ]
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 (c) Anna Schumaker.
|
||||||
|
*/
|
||||||
|
#include <idle.h>
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
static std::queue<idle :: IdleBase *> idle_queue;
|
||||||
|
static float queued = 0;
|
||||||
|
static float serviced = 0;
|
||||||
|
|
||||||
|
idle :: IdleBase :: IdleBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
idle :: IdleBase :: ~IdleBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void idle :: IdleBase :: schedule()
|
||||||
|
{
|
||||||
|
idle_queue.push(this);
|
||||||
|
queued++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool idle :: run_task()
|
||||||
|
{
|
||||||
|
if (idle_queue.size() > 0) {
|
||||||
|
idle_queue.front()->run();
|
||||||
|
delete idle_queue.front();
|
||||||
|
idle_queue.pop();
|
||||||
|
serviced++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idle_queue.size() > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
queued = 0;
|
||||||
|
serviced = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float idle :: get_progress()
|
||||||
|
{
|
||||||
|
if (idle_queue.size() == 0)
|
||||||
|
return 1;
|
||||||
|
return serviced / queued;
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ Export("Test")
|
||||||
|
|
||||||
|
|
||||||
# Read SConscript files
|
# Read SConscript files
|
||||||
scripts = [ "basic", "database", "file", "filter", "group", "index" ]
|
scripts = [ "basic", "database", "file", "filter", "group", "idle", "index" ]
|
||||||
for s in scripts:
|
for s in scripts:
|
||||||
CONFIG.reset()
|
CONFIG.reset()
|
||||||
CONFIG.TEST = True
|
CONFIG.TEST = True
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
Import("Test", "CONFIG")
|
||||||
|
|
||||||
|
CONFIG.IDLE = True
|
||||||
|
|
||||||
|
Test("idle", "idle.cpp")
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 (c) Anna Schumaker.
|
||||||
|
*/
|
||||||
|
#include <idle.h>
|
||||||
|
#include <print.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct TestStruct {
|
||||||
|
int i;
|
||||||
|
unsigned int u;
|
||||||
|
char c;
|
||||||
|
std::string s;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_0(unsigned int &i)
|
||||||
|
{
|
||||||
|
print("Test 0: %u\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_1(int &i)
|
||||||
|
{
|
||||||
|
print("Test 1: %d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_2(char &i)
|
||||||
|
{
|
||||||
|
print("Test 2: %c\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_3(std::string &str)
|
||||||
|
{
|
||||||
|
print("Test 3: %s\n", str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_4(TestStruct &struc)
|
||||||
|
{
|
||||||
|
print("Test 4: %d %u %c %s\n", struc.i, struc.u, struc.c, struc.s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_5(TestStruct *&struc)
|
||||||
|
{
|
||||||
|
print("Test 5: %d %u %c %s\n", struc->i, struc->u, struc->c, struc->s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
std::string string = "This is a string";
|
||||||
|
TestStruct struc1 = { -4, 4, 'd', "This is another string", };
|
||||||
|
TestStruct struc2 = { -5, 5, 'e', "This is yet another string", };
|
||||||
|
|
||||||
|
idle :: schedule(test_0, (unsigned int) 0);
|
||||||
|
idle :: schedule(test_1, 1);
|
||||||
|
idle :: schedule(test_2, 'b');
|
||||||
|
idle :: schedule(test_3, string);
|
||||||
|
idle :: schedule(test_4, struc1);
|
||||||
|
idle :: schedule(test_5, &struc2);
|
||||||
|
|
||||||
|
do {
|
||||||
|
print("Idle queue progress: %f\n", idle :: get_progress());
|
||||||
|
} while (idle :: run_task() == true);
|
||||||
|
print("Idle queue progress: %f\n", idle :: get_progress());
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
Idle queue progress: 0.000000
|
||||||
|
Test 0: 0
|
||||||
|
Idle queue progress: 0.166667
|
||||||
|
Test 1: 1
|
||||||
|
Idle queue progress: 0.333333
|
||||||
|
Test 2: b
|
||||||
|
Idle queue progress: 0.500000
|
||||||
|
Test 3: This is a string
|
||||||
|
Idle queue progress: 0.666667
|
||||||
|
Test 4: -4 4 d This is another string
|
||||||
|
Idle queue progress: 0.833333
|
||||||
|
Test 5: -5 5 e This is yet another string
|
||||||
|
Idle queue progress: 1.000000
|
Loading…
Reference in New Issue