diff --git a/config b/config index dfdf395a..3ac98e38 100644 --- a/config +++ b/config @@ -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() diff --git a/design/idle.txt b/design/idle.txt index 33aceb34..0bb44baa 100644 --- a/design/idle.txt +++ b/design/idle.txt @@ -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 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 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 - 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). diff --git a/include/idle.h b/include/idle.h new file mode 100644 index 00000000..ff412236 --- /dev/null +++ b/include/idle.h @@ -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 IdleTask : public IdleBase { + private: + void (*func)(T &); + T data; + public: + IdleTask(void (*)(T &), T); + ~IdleTask(); + void run(); + }; + + + template + static inline void schedule(void (*func)(T &), T param) + { + new IdleTask(func, param); + } + + bool run_task(); + float get_progress(); + +}; + +#include "idle.hpp" + +#endif /* OCARINA_IDLE_H */ diff --git a/include/idle.hpp b/include/idle.hpp new file mode 100644 index 00000000..3099da58 --- /dev/null +++ b/include/idle.hpp @@ -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 +idle :: IdleTask :: IdleTask(void (*fn)(T &), T param) + : func(fn), data(param) +{ + IdleBase :: schedule(); +} + +template +idle :: IdleTask :: ~IdleTask() +{ +} + +template +void idle :: IdleTask :: run() +{ + func(data); +} + +#endif /* OCARINA_IDLE_HPP */ diff --git a/lib/Sconscript b/lib/Sconscript index e6c6e38a..d53aea10 100644 --- a/lib/Sconscript +++ b/lib/Sconscript @@ -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") ] diff --git a/lib/idle.cpp b/lib/idle.cpp new file mode 100644 index 00000000..d0b1c65b --- /dev/null +++ b/lib/idle.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2013 (c) Anna Schumaker. + */ +#include + +#include + +static std::queue 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; +} diff --git a/tests/Sconscript b/tests/Sconscript index 3342b79d..0d270e63 100644 --- a/tests/Sconscript +++ b/tests/Sconscript @@ -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 diff --git a/tests/idle/Sconscript b/tests/idle/Sconscript new file mode 100644 index 00000000..68405f4e --- /dev/null +++ b/tests/idle/Sconscript @@ -0,0 +1,6 @@ +#!/usr/bin/python +Import("Test", "CONFIG") + +CONFIG.IDLE = True + +Test("idle", "idle.cpp") diff --git a/tests/idle/idle.cpp b/tests/idle/idle.cpp new file mode 100644 index 00000000..b2025294 --- /dev/null +++ b/tests/idle/idle.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2013 (c) Anna Schumaker. + */ +#include +#include + +#include + +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; +} diff --git a/tests/idle/idle.good b/tests/idle/idle.good new file mode 100644 index 00000000..2faa0247 --- /dev/null +++ b/tests/idle/idle.good @@ -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