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:
Anna Schumaker 2013-09-01 10:55:13 -04:00 committed by Anna Schumaker
parent 5f30a71c55
commit f417b48df8
10 changed files with 236 additions and 10 deletions

3
config
View File

@ -28,6 +28,7 @@ class Config:
self.FILE = False
self.FILTER = False
self.GROUP = False
self.IDLE = False
self.INDEX = False
self.TEST = False
@ -40,6 +41,7 @@ class Config:
if self.FILE: env.Append( CCFLAGS = [ "-DCONFIG_FILE" ])
if self.FILTER: env.Append( CCFLAGS = [ "-DCONFIG_FILTER" ])
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.TEST: env.Append( CCFLAGS = [ "-DCONFIG_TEST" ])
@ -48,6 +50,7 @@ class Config:
self.FILE = False
self.FILTER = False
self.GROUP = False
self.IDLE = False
self.INDEX = False
self.TEST = False
self.reconfigure()

View File

@ -13,8 +13,17 @@ Idle queue: (lib/idle.cpp)
tasks must inherit from the IdleBase class so that multiple templated
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:
class IdleBase {
private:
schedule();
public:
IdleBase();
~IdleBase();
virtual void run() = 0;
@ -24,30 +33,34 @@ Idle queue: (lib/idle.cpp)
template <class T>
class IdleTask : IdleBase {
private:
void (*func)(T *);
T *data;
void (*func)(T &);
T &data;
public:
IdleTask(void (*)(T *), T *);
IdleTask(void (*)(T &), T);
void run();
};
- Queue:
deque(IdleBase *> idle_queue;
queue<IdleBase *> idle_queue;
float queued = 0.0
float serviced = 0.0
- API:
void IdleBase :: schedule();
Add the idle task to the idle queue. This should be called
by the IdleTask constructor.
queued++;
template <class T>
void idle :: schedule(void (*)(T *), T *);
Schedule a function to run later (queued++). This should
be written in the idle.hpp file since it is a function
template.
static inline void idle :: schedule(void (*)(T &), T);
Create a new IdleTask to run the function later.
bool idle :: run_task()
If there are tasks on the queue:
run the next task
scheduled++
If there are still tasks on the queue:
return true
else:
queued = 0
@ -56,4 +69,5 @@ Idle queue: (lib/idle.cpp)
float idle :: get_progress()
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).

45
include/idle.h Normal file
View File

@ -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 */

28
include/idle.hpp Normal file
View File

@ -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 */

View File

@ -27,6 +27,10 @@ if CONFIG.FILE:
CONFIG.package("glib-2.0")
build += [ env.Object("file.cpp") ]
if CONFIG.IDLE:
build += [ env.Object("idle.cpp") ]
####################
if CONFIG.TEST:
build += [ env.Object("test.cpp") ]

49
lib/idle.cpp Normal file
View File

@ -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;
}

View File

@ -43,7 +43,7 @@ Export("Test")
# Read SConscript files
scripts = [ "basic", "database", "file", "filter", "group", "index" ]
scripts = [ "basic", "database", "file", "filter", "group", "idle", "index" ]
for s in scripts:
CONFIG.reset()
CONFIG.TEST = True

6
tests/idle/Sconscript Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/python
Import("Test", "CONFIG")
CONFIG.IDLE = True
Test("idle", "idle.cpp")

64
tests/idle/idle.cpp Normal file
View File

@ -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;
}

13
tests/idle/idle.good Normal file
View File

@ -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