From 2cb2961c9f6062e867b6ccc3d9067f55c7b81ea4 Mon Sep 17 00:00:00 2001 From: Pixel Date: Thu, 17 Nov 2011 11:17:57 -0800 Subject: Cleaning some code, redesigning a bit the stack allocation problem from the task manager, and actually implementing it properly. --- includes/Task.h | 6 +++--- includes/TaskMan.h | 4 +++- includes/Threads.h | 2 +- src/Task.cc | 6 ++++-- src/TaskMan.cc | 32 ++++++++++++++++++++++++++++---- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/includes/Task.h b/includes/Task.h index 5865831..2e52747 100644 --- a/includes/Task.h +++ b/includes/Task.h @@ -5,7 +5,7 @@ #include #endif #include -#include +#include #include #include @@ -136,7 +136,7 @@ class Task { TaskMan * getMyTaskMan() { return m_taskMan; } private: static size_t stackSize() { return 64 * 1024; } - void setup(TaskMan * taskMan); + void setup(TaskMan * taskMan, void * stack); static bool needsStacks(); void switchTo(); static void CALLBACK coroutineTrampoline(void *); @@ -152,7 +152,7 @@ class Task { void * m_tls; friend class TaskMan; friend class Events::TaskEvent; - typedef std::vector waitedByList_t; + typedef std::list waitedByList_t; waitedByList_t m_waitedBy; bool m_okayToEAgain; }; diff --git a/includes/TaskMan.h b/includes/TaskMan.h index b944f09..c63695a 100644 --- a/includes/TaskMan.h +++ b/includes/TaskMan.h @@ -6,7 +6,7 @@ #endif #include #include -#include +#include #include #include @@ -55,6 +55,8 @@ class TaskMan { struct ev_loop * m_loop; bool m_allowedToSignal; ev::async m_evt; + std::queue m_stacks; + int m_nStacks; }; template diff --git a/includes/Threads.h b/includes/Threads.h index a1f270e..256e8e3 100644 --- a/includes/Threads.h +++ b/includes/Threads.h @@ -41,7 +41,7 @@ template class Queue { public: Queue() { pthread_cond_init(&m_cond, NULL); } - ~Queue() { pthread_cond_destroy(&m_cond); } + ~Queue() { while (size()) pop(); pthread_cond_destroy(&m_cond); } void push(T & t) { m_lock.enter(); m_queue.push(t); diff --git a/src/Task.cc b/src/Task.cc index d72decc..440ed0e 100644 --- a/src/Task.cc +++ b/src/Task.cc @@ -21,12 +21,14 @@ bool Balau::Task::needsStacks() { #endif } -void Balau::Task::setup(TaskMan * taskMan) { +void Balau::Task::setup(TaskMan * taskMan, void * stack) { size_t size = stackSize(); #ifndef _WIN32 - m_stack = taskMan->getStack(); + Assert(stack); + m_stack = stack; coro_create(&m_ctx, coroutineTrampoline, this, m_stack, size); #else + Assert(!stack); m_stack = NULL; m_fiber = CreateFiber(size, coroutineTrampoline, this); #endif diff --git a/src/TaskMan.cc b/src/TaskMan.cc index e9e3485..3a5cc1c 100644 --- a/src/TaskMan.cc +++ b/src/TaskMan.cc @@ -19,6 +19,8 @@ const char * Stopper::getName() { static Balau::DefaultTmpl defaultTaskMan(50); static Balau::LocalTmpl localTaskMan; +static const int TOO_MANY_STACKS = 1024; + namespace Balau { class TaskScheduler : public Thread, public AtStart, public AtExit { @@ -109,6 +111,8 @@ Balau::TaskMan::TaskMan() : m_stopped(false), m_allowedToSignal(false) { m_evt.set(); m_evt.start(); s_scheduler.registerTaskMan(this); + + m_nStacks = 0; } #ifdef _WIN32 @@ -129,21 +133,40 @@ Balau::TaskMan * Balau::TaskMan::getDefaultTaskMan() { return localTaskMan.get() Balau::TaskMan::~TaskMan() { Assert(localTaskMan.getGlobal() != this); + while (m_stacks.size() != 0) { + free(m_stacks.front()); + m_stacks.pop(); + } s_scheduler.unregisterTaskMan(this); // probably way more work to do here in order to clean up tasks from that thread ev_loop_destroy(m_loop); } void * Balau::TaskMan::getStack() { - return malloc(Task::stackSize()); + void * r = NULL; + if (m_nStacks == 0) { + if (Task::needsStacks()) + r = malloc(Task::stackSize()); + } else { + r = m_stacks.front(); + m_stacks.pop(); + m_nStacks--; + } + return r; } void Balau::TaskMan::freeStack(void * stack) { - free(stack); + if (!stack) + return; + if (m_nStacks >= TOO_MANY_STACKS) { + free(stack); + } else { + m_stacks.push(stack); + m_nStacks++; + } } void Balau::TaskMan::mainLoop() { - // We need at least one round before bailing :) do { taskHash_t::iterator iH; Task * t; @@ -200,7 +223,7 @@ void Balau::TaskMan::mainLoop() { while (((m_pendingAdd.size() != 0) || (m_tasks.size() == 0)) && !m_stopped) { t = m_pendingAdd.pop(); Assert(m_tasks.find(t) == m_tasks.end()); - t->setup(this); + t->setup(this, getStack()); m_tasks.insert(t); } @@ -212,6 +235,7 @@ void Balau::TaskMan::mainLoop() { t = *iH; if (((t->getStatus() == Task::STOPPED) || (t->getStatus() == Task::FAULTED)) && (t->m_waitedBy.size() == 0)) { + freeStack(t->m_stack); delete t; m_tasks.erase(iH); didDelete = true; -- cgit v1.2.3