summaryrefslogtreecommitdiffstats
path: root/src/fiber.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-11-27 18:42:11 +0200
committerTimo Teras <timo.teras@iki.fi>2009-11-27 18:42:11 +0200
commit959645020619f02d6ab8bb4026b0e0121b3971da (patch)
treed87a0ef5bf3b50dae70dc7c5c1688b446f8e559b /src/fiber.c
parentaa530f352b0410150bfe94c821ae32c1378b9d02 (diff)
downloadlibtf-959645020619f02d6ab8bb4026b0e0121b3971da.tar.bz2
libtf-959645020619f02d6ab8bb4026b0e0121b3971da.tar.xz
libtf: implement x86 assembly fiber switching
it's faster and has smaller context in the beginning of the fiber. it's also required since setjmp() seems to use mangled pointers in glibc so we could not schedule fibers in non-creation threads. additionally the setjmp() setup code has a race condition.
Diffstat (limited to 'src/fiber.c')
-rw-r--r--src/fiber.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/fiber.c b/src/fiber.c
index 3f8bb15..6ddde1b 100644
--- a/src/fiber.c
+++ b/src/fiber.c
@@ -29,7 +29,7 @@ struct tf_fiber {
char data[TF_EMPTY_ARRAY];
};
-#include "uctx-setjmp.h"
+#include "uctx.h"
/* FIXME: should be in thread local storage */
struct tf_scheduler *__tf_scheduler;
@@ -91,12 +91,13 @@ static void run_fiber(struct tf_scheduler *sched, struct tf_fiber *f)
struct tf_fiber *schedf = container_of((void*) tf_get_scheduler(), struct tf_fiber, data);
sched->active_fiber = f;
- switch (tf_uctx_transfer(schedf, f, f->wakeup_type)) {
+ tf_uctx_transfer(schedf, f);
+ switch (f->wakeup_type) {
case TF_WAKEUP_KILL:
tf_fiber_put(f->data);
sched->num_fibers--;
break;
- case TF_WAKEUP_IMMEDIATE:
+ case TF_WAKEUP_NONE:
break;
default:
TF_BUG_ON("bad scheduler call from fiber");
@@ -222,15 +223,19 @@ int tf_schedule(void)
struct tf_fiber *f = sched->active_fiber;
if (unlikely(f->timeout_change)) {
- if (f->timeout_change & TF_TIMEOUT_CHANGE_NEW_VALUE)
+ if (f->timeout_change & TF_TIMEOUT_CHANGE_NEW_VALUE) {
+ if (tf_mtime_diff(f->timeout, tf_mtime()) <= 0) {
+ f->timeout_change = TF_TIMEOUT_CHANGE;
+ return TF_WAKEUP_TIMEOUT;
+ }
tf_heap_change(&f->heap_node, &sched->heap, f->timeout);
- else
+ } else
tf_heap_delete(&f->heap_node, &sched->heap);
f->timeout_change = 0;
}
f->wakeup_type = TF_WAKEUP_NONE;
-
- return tf_uctx_transfer(f, schedf, TF_WAKEUP_IMMEDIATE);
+ tf_uctx_transfer(f, schedf);
+ return f->wakeup_type;
}
void tf_wakeup(struct tf_fiber *fiber, int wakeup_type)
@@ -250,7 +255,8 @@ void tf_exit(void)
struct tf_fiber *schedf = container_of((void*) sched, struct tf_fiber, data);
tf_heap_delete(&f->heap_node, &sched->heap);
- tf_uctx_transfer(f, schedf, TF_WAKEUP_KILL);
+ f->wakeup_type = TF_WAKEUP_KILL;
+ tf_uctx_transfer(f, schedf);
TF_BUG_ON(1);
}