diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 24 | ||||
-rw-r--r-- | includes/Local.h | 21 | ||||
-rw-r--r-- | includes/Task.h | 38 | ||||
-rw-r--r-- | includes/TaskMan.h | 21 | ||||
m--------- | libcoro | 0 | ||||
-rw-r--r-- | src/Local.cc | 4 | ||||
-rw-r--r-- | src/Printer.cc | 29 | ||||
-rw-r--r-- | src/Task.cc | 46 | ||||
-rw-r--r-- | src/TaskMan.cc | 21 | ||||
-rw-r--r-- | tests/test-Tasks.cc | 13 |
11 files changed, 192 insertions, 28 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..55cf452 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libcoro"] + path = libcoro + url = git.grumpycoder.net:/pub/repo.git/libcoro @@ -15,6 +15,7 @@ AR = ar rcs CPPFLAGS = -O3 ifeq ($(SYSTEM),Darwin) + LIBCORO_CFLAGS = -DCORO_SJLJ ARCH_FLAGS = -arch i386 LIBS = -liconv LD = g++ -arch i386 @@ -27,6 +28,7 @@ ifeq ($(SYSTEM),Darwin) AS = i686-apple-darwin-as -arch i386 endif else + LIBCORO_CFLAGS = -DCORO_ASM ARCH_FLAGS = -march=i686 -m32 ASFLAGS = -march=i686 --32 STRIP = strip --strip-unneeded @@ -34,30 +36,38 @@ else LDFLAGS += -flto -O3 endif -INCLUDES = -Iincludes +INCLUDES = -Iincludes -Ilibcoro -CPPFLAGS_NO_ARCH += $(INCLUDES) -g -DSTDC_HEADERS -fexceptions -DWORDS_LITTLEENDIAN $(HAVES) +CPPFLAGS_NO_ARCH += $(INCLUDES) -g -DSTDC_HEADERS -fexceptions -DWORDS_LITTLEENDIAN $(HAVES) $(LIBCORO_CFLAGS) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) LDFLAGS += $(ARCH_FLAGS) $(LIBS) vpath %.cc src:tests +vpath %.c libcoro BALAU_SOURCES = \ BString.cc \ Local.cc \ Main.cc \ Printer.cc \ +Task.cc \ +TaskMan.cc \ + +LIBCORO_SOURCES = \ +coro.c \ TEST_SOURCES = \ test-String.cc \ +test-Tasks.cc \ LIB = libBalau.a -WHOLE_SOURCES = $(BALAU_SOURCES) $(TEST_SOURCES) +BALAU_OBJECTS = $(addsuffix .o, $(notdir $(basename $(BALAU_SOURCES) $(LIBCORO_SOURCES)))) + +WHOLE_SOURCES = $(BALAU_SOURCES) $(LIBCORO_SOURCES) $(TEST_SOURCES) TESTS = $(notdir $(basename $(TEST_SOURCES))) -BALAU_OBJECTS = $(addsuffix .o, $(notdir $(basename $(BALAU_SOURCES)))) ALL_OBJECTS = $(addsuffix .o, $(notdir $(basename $(WHOLE_SOURCES)))) ALL_DEPS = $(addsuffix .dep, $(notdir $(basename $(WHOLE_SOURCES)))) @@ -77,11 +87,17 @@ libBalau.a: $(BALAU_OBJECTS) test-String: test-String.o $(LIB) $(LD) $(LDFLAGS) -o $@ $< ./$(LIB) +test-Tasks: test-Tasks.o $(LIB) + $(LD) $(LDFLAGS) -o $@ $< ./$(LIB) + dep: $(ALL_DEPS) %.dep : %.cc $(CXX) $(CPPFLAGS_NO_ARCH) -M -MF $@ $< +%.dep : %.c + $(CC) $(CPPFLAGS_NO_ARCH) -M -MF $@ $< + -include $(ALL_DEPS) clean: diff --git a/includes/Local.h b/includes/Local.h index f3b7250..a3405ca 100644 --- a/includes/Local.h +++ b/includes/Local.h @@ -8,6 +8,7 @@ class TLSManager { public: virtual void * getTLS(); virtual void * setTLS(void * val); + void * createTLS(); }; extern TLSManager * tlsManager; @@ -32,6 +33,26 @@ class Local : public AtStart { int m_idx; static int s_size; static void ** m_globals; + + friend class TLSManager; +}; + +template<class T> +class DefaultTmpl : public AtStart { + public: + DefaultTmpl(int pri) : AtStart(pri) { } + protected: + virtual void doStart() { new T; } +}; + +template<class T> +class LocalTmpl : public Local { + public: + LocalTmpl() { } + T * getGlobal() { return reinterpret_cast<T *>(Local::getGlobal()); } + T * get() { return reinterpret_cast<T *>(Local::get()); } + void setGlobal(T * obj) { Local::setGlobal(obj); } + void set(T * obj) { Local::set(obj); } }; }; diff --git a/includes/Task.h b/includes/Task.h new file mode 100644 index 0000000..314532b --- /dev/null +++ b/includes/Task.h @@ -0,0 +1,38 @@ +#pragma once + +#include <stdlib.h> +#include <coro.h> + +namespace Balau { + +class TaskMan; + +class Task { + public: + enum Status { + STARTING, + RUNNING, + IDLE, + STOPPED, + FAULTED, + }; + Task(); + ~Task() { free(stack); free(tls); } + virtual void Do() = 0; + virtual const char * getName() = 0; + Status getStatus() { return status; } + protected: + void suspend(); + private: + size_t stackSize() { return 128 * 1024; } + void switchTo(); + static void coroutine(void *); + void * stack; + coro_context ctx; + TaskMan * taskMan; + Status status; + void * tls; + friend class TaskMan; +}; + +}; diff --git a/includes/TaskMan.h b/includes/TaskMan.h new file mode 100644 index 0000000..05e5fa8 --- /dev/null +++ b/includes/TaskMan.h @@ -0,0 +1,21 @@ +#pragma once + +#include <coro.h> + +namespace Balau { + +class Task; + +class TaskMan { + public: + TaskMan(); + ~TaskMan(); + void mainLoop(); + + private: + static TaskMan * getTaskMan(); + coro_context returnContext; + friend class Task; +}; + +}; diff --git a/libcoro b/libcoro new file mode 160000 +Subproject 128d4e8c4a9103fe5a02682de89c6a660ff2a5d diff --git a/src/Local.cc b/src/Local.cc index 1262179..c354db9 100644 --- a/src/Local.cc +++ b/src/Local.cc @@ -13,6 +13,10 @@ void * Balau::TLSManager::setTLS(void * val) { return r; } +void * Balau::TLSManager::createTLS() { + return Local::create(); +} + static Balau::TLSManager dummyTLSManager; Balau::TLSManager * Balau::tlsManager = &dummyTLSManager; diff --git a/src/Printer.cc b/src/Printer.cc index fda9952..cb94084 100644 --- a/src/Printer.cc +++ b/src/Printer.cc @@ -2,14 +2,8 @@ #include "Main.h" #include "Local.h" -class PrinterLocal : public Balau::Local { - public: - PrinterLocal() { } - Balau::Printer * getGlobal() { return reinterpret_cast<Balau::Printer *>(Local::getGlobal()); } - Balau::Printer * get() { return reinterpret_cast<Balau::Printer *>(Local::get()); } - void setGlobal(Balau::Printer * printer) { Local::setGlobal(printer); } - void set(Balau::Printer * printer) { Local::set(printer); } -} printerLocal; +static Balau::DefaultTmpl<Balau::Printer> defaultPrinter(10); +static Balau::LocalTmpl<Balau::Printer> localPrinter; static const char * prefixes[] = { "(DD) ", @@ -21,11 +15,11 @@ static const char * prefixes[] = { }; Balau::Printer::Printer() : m_verbosity(M_STATUS | M_WARNING | M_ERROR) { - if (!printerLocal.getGlobal()) - printerLocal.setGlobal(this); + if (!localPrinter.getGlobal()) + localPrinter.setGlobal(this); } -Balau::Printer * Balau::Printer::getPrinter() { return printerLocal.get(); } +Balau::Printer * Balau::Printer::getPrinter() { return localPrinter.get(); } void Balau::Printer::_log(uint32_t level, const char * fmt, va_list ap) { if (!(level & m_verbosity)) @@ -45,16 +39,3 @@ void Balau::Printer::_log(uint32_t level, const char * fmt, va_list ap) { void Balau::Printer::_print(const char * fmt, va_list ap) { vfprintf(stderr, fmt, ap); } - -class DefaultPrinter : public Balau::AtStart { - public: - DefaultPrinter() : AtStart(10) { } - protected: - virtual void doStart(); -}; - -static DefaultPrinter defaultPrinter; - -void DefaultPrinter::doStart() { - new Balau::Printer(); -} diff --git a/src/Task.cc b/src/Task.cc new file mode 100644 index 0000000..d41f088 --- /dev/null +++ b/src/Task.cc @@ -0,0 +1,46 @@ +#include "Task.h" +#include "TaskMan.h" +#include "Exceptions.h" +#include "Printer.h" +#include "Local.h" + +Balau::Task::Task() { + size_t size = stackSize(); + stack = malloc(size); + coro_create(&ctx, coroutine, this, stack, size); + taskMan = TaskMan::getTaskMan(); + tls = tlsManager->createTLS(); + status = STARTING; +} + +void Balau::Task::coroutine(void * arg) { + Task * task = reinterpret_cast<Task *>(arg); + Assert(task); + try { + task->status = RUNNING; + task->Do(); + task->status = STOPPED; + } + catch (GeneralException & e) { + Printer::log(M_WARNING, "Task %s caused an exception: `%s' - stopping.", task->getName(), e.getMsg()); + task->status = FAULTED; + } + catch (...) { + Printer::log(M_WARNING, "Task %s caused an unknown exception - stopping.", task->getName()); + task->status = FAULTED; + } + coro_transfer(&task->ctx, &task->taskMan->returnContext); +} + +void Balau::Task::switchTo() { + status = RUNNING; + void * oldTLS = tlsManager->getTLS(); + tlsManager->setTLS(tls); + coro_transfer(&taskMan->returnContext, &ctx); + tlsManager->setTLS(oldTLS); + status = IDLE; +} + +void Balau::Task::suspend() { + coro_transfer(&ctx, &taskMan->returnContext); +} diff --git a/src/TaskMan.cc b/src/TaskMan.cc new file mode 100644 index 0000000..783c683 --- /dev/null +++ b/src/TaskMan.cc @@ -0,0 +1,21 @@ +#include "TaskMan.h" +#include "Main.h" +#include "Local.h" + +static Balau::DefaultTmpl<Balau::TaskMan> defaultTaskMan(50); +static Balau::LocalTmpl<Balau::TaskMan> localTaskMan; + +Balau::TaskMan::TaskMan() { + coro_create(&returnContext, 0, 0, 0, 0); + if (!localTaskMan.getGlobal()) + localTaskMan.setGlobal(this); +} + +Balau::TaskMan * Balau::TaskMan::getTaskMan() { return localTaskMan.get(); } + +Balau::TaskMan::~TaskMan() { + Assert(localTaskMan.getGlobal() != this); +} + +void Balau::TaskMan::mainLoop() { +} diff --git a/tests/test-Tasks.cc b/tests/test-Tasks.cc new file mode 100644 index 0000000..bb7c795 --- /dev/null +++ b/tests/test-Tasks.cc @@ -0,0 +1,13 @@ +#include <Main.h> +#include <Task.h> +#include <TaskMan.h> + +BALAU_STARTUP; + +using namespace Balau; + +int Application::startup() throw (Balau::GeneralException) { + Printer::log(M_STATUS, "Test::Tasks running."); + Printer::log(M_STATUS, "Test::Tasks passed."); + return 0; +} |