Skip to content

Commit

Permalink
Use a singly linked list for yield()ed tasks to avoid memory allocati…
Browse files Browse the repository at this point in the history
…ons.
  • Loading branch information
s-ludwig committed Nov 19, 2013
1 parent 777ab24 commit c5a9025
Showing 1 changed file with 60 additions and 13 deletions.
73 changes: 60 additions & 13 deletions source/vibe/core/core.d
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,13 @@ private void runWorkerTaskDist_unsafe(void delegate() del)
*/
void yield()
{
auto t = Task.getThis();
auto t = CoreTask.getThis();
if (t != Task.init) {
s_yieldedTasks ~= Task.getThis();
// it can happen that a task with the same fiber was
// terminated while it was yielded.
assert(!t.m_queue || t.m_queue is &s_yieldedTasks);
if (!t.m_queue)
s_yieldedTasks.insertBack(CoreTask.getThis());
rawYield();
}
}
Expand Down Expand Up @@ -396,6 +400,12 @@ void enableWorkerThreads()
}


/**
The number of worker threads.
*/
@property size_t workerThreadCount() { return st_workerThreads.length; }


/**
Sets the effective user and group ID to the ones configured for privilege lowering.
Expand Down Expand Up @@ -546,6 +556,8 @@ private class CoreTask : TaskFiber {
import std.bitmanip;
private {
static CoreTask ms_coreTask;
CoreTask m_nextInQueue;
CoreTaskQueue* m_queue;
void delegate() m_taskFunc;
Exception m_exception;
Task[] m_yielders;
Expand All @@ -570,6 +582,8 @@ private class CoreTask : TaskFiber {
super(&run, s_taskStackSize);
}

@property size_t taskCounter() const { return m_taskCounter; }

private void run()
{
try {
Expand Down Expand Up @@ -599,7 +613,7 @@ private class CoreTask : TaskFiber {
}
resetLocalStorage();

s_yieldedTasks ~= m_yielders;
foreach (t; m_yielders) s_yieldedTasks.insertBack(cast(CoreTask)t.fiber);
m_yielders.length = 0;

// make the fiber available for the next task
Expand Down Expand Up @@ -690,7 +704,11 @@ private class VibeDriverCore : DriverCore {
void resumeTask(Task task, Exception event_exception, bool initial_resume)
{
assert(initial_resume || task.running, "Resuming terminated task.");
CoreTask ctask = cast(CoreTask)task.fiber;
resumeCoreTask(cast(CoreTask)task.fiber, event_exception);
}

void resumeCoreTask(CoreTask ctask, Exception event_exception = null)
{
assert(ctask.thread is Thread.getThis(), "Resuming task in foreign thread.");
assert(ctask.state == Fiber.State.HOLD, "Resuming fiber that is " ~ to!string(ctask.state));

Expand All @@ -699,10 +717,10 @@ private class VibeDriverCore : DriverCore {
ctask.m_exception = event_exception;
}

auto uncaught_exception = task.call(false);
auto uncaught_exception = ctask.call(false);
if( uncaught_exception ){
extrap();
assert(task.state == Fiber.State.TERM);
assert(ctask.state == Fiber.State.TERM);
logError("Task terminated with unhandled exception: %s", uncaught_exception.toString());
}
}
Expand All @@ -715,12 +733,12 @@ private class VibeDriverCore : DriverCore {
again = s_idleHandler();
else again = false;

Task[] tmp;
swap(s_yieldedTasks, tmp);
foreach(t; tmp)
if (t.running)
resumeTask(t);
if (s_yieldedTasks.length > 0)
while (!s_yieldedTasks.empty) {
auto tf = s_yieldedTasks.front;
s_yieldedTasks.popFront();
resumeCoreTask(tf);
}
if (!s_yieldedTasks.empty)
again = true;
if (again && !processEvents()) {
m_exit = true;
Expand Down Expand Up @@ -763,7 +781,7 @@ private {

bool delegate() s_idleHandler;
__gshared debug void function(TaskEvent, Fiber) s_taskEventCallback;
Task[] s_yieldedTasks;
CoreTaskQueue s_yieldedTasks;
bool s_eventLoopRunning = false;
Variant[string] s_taskLocalStorageGlobal; // for use outside of a task
CoreTask[] s_availableFibers;
Expand Down Expand Up @@ -997,3 +1015,32 @@ version(Posix)
}
}

private struct CoreTaskQueue {
CoreTask first, last;

@disable this(this);

@property bool empty() const { return first is null; }

@property CoreTask front() { return first; }

void insertBack(CoreTask task)
{
assert(task.m_queue == null);
assert(task.m_nextInQueue is null);
task.m_queue = &this;
if (last) last.m_nextInQueue = task;
else first = last = task;
}

void popFront()
{
if (first == last) last = null;
assert(first && first.m_queue == &this);
auto next = first.m_nextInQueue;
first.m_nextInQueue = null;
first.m_queue = null;
first = next;
}
}

1 comment on commit c5a9025

@MartinNowak
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this introduced #401.

Please sign in to comment.