Created
June 1, 2011 23:49
-
-
Save eholk/1003627 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp | |
index 77008fd..f01ac30 100644 | |
--- a/src/rt/rust.cpp | |
+++ b/src/rt/rust.cpp | |
@@ -93,9 +93,13 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { | |
DLOG(dom, dom, "startup: arg[%d] = '%s'", i, args->argv[i]); | |
} | |
+ /* | |
uintptr_t main_args[4] = {0, 0, 0, (uintptr_t)args->args}; | |
dom->root_task->start(main_fn, | |
(uintptr_t)&main_args, sizeof(main_args)); | |
+ */ | |
+ dom->root_task->start(main_fn, | |
+ (uintptr_t)args->args, sizeof(args->args)); | |
int ret = dom->start_main_loop(); | |
delete args; | |
diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp | |
index 6a5c463..9be7547 100644 | |
--- a/src/rt/rust_dom.cpp | |
+++ b/src/rt/rust_dom.cpp | |
@@ -50,7 +50,17 @@ extern "C" void new_rust_activate_glue(rust_task *) | |
void | |
rust_dom::activate(rust_task *task) { | |
curr_task = task; | |
- new_rust_activate_glue(task); | |
+ //new_rust_activate_glue(task); | |
+ | |
+ static ucontext_t ctx; | |
+ int res = getcontext(&ctx); | |
+ if(!res) { | |
+ // TODO: handle this error | |
+ } | |
+ | |
+ task->context.uc_link = &ctx; | |
+ swapcontext(&ctx, &task->context); | |
+ | |
curr_task = NULL; | |
} | |
@@ -308,10 +318,14 @@ rust_dom::start_main_loop() { | |
scheduled_task->state->name, | |
scheduled_task->rust_sp); | |
+ /* | |
+ // These invariants are no longer valid, as rust_sp is not | |
+ // updated. | |
I(this, scheduled_task->rust_sp >= | |
(uintptr_t) &scheduled_task->stk->data[0]); | |
I(this, scheduled_task->rust_sp < scheduled_task->stk->limit); | |
- | |
+ */ | |
+ | |
reap_dead_tasks(); | |
} | |
diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp | |
index 3c2ad01..f72da48 100644 | |
--- a/src/rt/rust_kernel.cpp | |
+++ b/src/rt/rust_kernel.cpp | |
@@ -187,8 +187,11 @@ rust_kernel::~rust_kernel() { | |
KLOG("freeing handles"); | |
free_handles(_task_handles); | |
+ KLOG("..task handles freed"); | |
free_handles(_port_handles); | |
+ KLOG("..port handles freed"); | |
free_handles(_dom_handles); | |
+ KLOG("..dom handles freed"); | |
KLOG("freeing queues"); | |
@@ -214,6 +217,7 @@ rust_kernel::free_handles(hash_map<T*, rust_handle<T>* > &map) { | |
T* key; | |
rust_handle<T> *value; | |
while (map.pop(&key, &value)) { | |
+ KLOG("...freeing " PTR, value); | |
delete value; | |
} | |
} | |
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp | |
index f476955..a760e25 100644 | |
--- a/src/rt/rust_task.cpp | |
+++ b/src/rt/rust_task.cpp | |
@@ -58,6 +58,7 @@ align_down(uintptr_t sp) | |
return sp & ~(16 - 1); | |
} | |
+#if 0 | |
static uintptr_t* | |
align_down(uintptr_t* sp) | |
{ | |
@@ -72,7 +73,7 @@ make_aligned_room_for_bytes(uintptr_t*& sp, size_t n) | |
tmp = align_down(tmp - n) + n; | |
sp = (uintptr_t*) tmp; | |
} | |
- | |
+#endif | |
rust_task::rust_task(rust_dom *dom, rust_task_list *state, | |
rust_task *spawner, const char *name) : | |
@@ -135,6 +136,30 @@ rust_task::~rust_task() | |
extern "C" void rust_new_exit_task_glue(); | |
+extern "C" CDECL | |
+void task_start_wrapper(uintptr_t a1, rust_task *task, | |
+ uintptr_t a3, uintptr_t a4, | |
+ void (*f)(uintptr_t, rust_task *, | |
+ uintptr_t, uintptr_t)) | |
+{ | |
+ // This is used by the context switching code. LLVM generates fastcall | |
+ // functions, but ucontext needs cdecl functions. This massages the | |
+ // calling conventions into the right form. | |
+ f(a1, task, a3, a4); | |
+ | |
+ // TODO: the old exit glue does some magical argument copying stuff. This | |
+ // is probably still needed. | |
+ | |
+ // This is duplicated from upcall_exit, which is probably dead code by | |
+ // now. | |
+ LOG(task, task, "task ref_count: %d", task->ref_count); | |
+ A(task->dom, task->ref_count >= 0, | |
+ "Task ref_count should not be negative on exit!"); | |
+ task->die(); | |
+ task->notify_tasks_waiting_to_join(); | |
+ task->yield(1); | |
+} | |
+ | |
void | |
rust_task::start(uintptr_t spawnee_fn, | |
uintptr_t args, | |
@@ -142,53 +167,23 @@ rust_task::start(uintptr_t spawnee_fn, | |
{ | |
LOGPTR(dom, "from spawnee", spawnee_fn); | |
- // Set sp to last uintptr_t-sized cell of segment | |
- rust_sp -= sizeof(uintptr_t); | |
- | |
- // Begin synthesizing the exit_task_glue frame. We will return to | |
- // exit_task_glue and it is responsible for calling the user code | |
- // and passing the value returned by the user to the system | |
- // exit routine. | |
- uintptr_t *spp = (uintptr_t *)rust_sp; | |
- | |
- uintptr_t dummy_ret = (uintptr_t) spp--; | |
- | |
- uintptr_t args_size = callsz - 3*sizeof(uintptr_t); | |
- uintptr_t frame_size = args_size + 4*sizeof(uintptr_t); | |
- | |
- | |
- // NB: Darwin needs "16-byte aligned" stacks *at the point of the call | |
- // instruction in the caller*. This means that the address at which the | |
- // word before retpc is pushed must always be 16-byte aligned. | |
- // | |
- // see: "Mac OS X ABI Function Call Guide" | |
- | |
- make_aligned_room_for_bytes(spp, frame_size - sizeof(uintptr_t)); | |
- | |
- // Copy args from spawner to spawnee. | |
- uintptr_t *src = (uintptr_t *)args; | |
- src += 1; // spawn-call output slot | |
- src += 1; // spawn-call task slot | |
- src += 1; // spawn-call closure-or-obj slot | |
- | |
- *spp-- = (uintptr_t) *src; // vec | |
- *spp-- = (uintptr_t) 0x0; // closure-or-obj | |
- *spp-- = (uintptr_t) this; // task | |
- *spp-- = (uintptr_t) dummy_ret; // output address | |
+ // Initialize the context | |
+ int res = getcontext(&this->context); | |
+ if(!res) { | |
+ // TODO: handle this error sanely. | |
+ } | |
- I(dom, spp == align_down(spp)); | |
- *spp-- = (uintptr_t) (uintptr_t) spawnee_fn; | |
+ I(dom, stk->data != NULL); | |
+ context.uc_stack.ss_sp = stk->data; | |
+ context.uc_stack.ss_size = stk->limit - (uintptr_t)stk->data; | |
- *spp-- = (uintptr_t) 0x0; // retp | |
+ // TODO: copy the args somewhere safe | |
+ makecontext(&context, (void(*)())task_start_wrapper, 5, | |
+ 0, this, 0, args, spawnee_fn); | |
- *spp-- = (uintptr_t) rust_new_exit_task_glue; | |
+ // TODO: we might need to new task exit glue... | |
- for (size_t j = 0; j < n_callee_saves; ++j) { | |
- *spp-- = (uintptr_t)NULL; | |
- } | |
- | |
- // Back up one, we overshot where sp should be. | |
- rust_sp = (uintptr_t) (spp+1); | |
+ yield_timer.reset(0); | |
transition(&dom->newborn_tasks, &dom->running_tasks); | |
} | |
@@ -288,7 +283,7 @@ rust_task::run_after_return(size_t nargs, uintptr_t glue) | |
// Move the current return address (which points into rust code) | |
// onto the rust stack and pretend we just called into the glue. | |
- push_onto_thread_stack(rust_sp, *retpc); | |
+ //push_onto_thread_stack(rust_sp, *retpc); | |
*retpc = glue; | |
} | |
@@ -320,8 +315,15 @@ void | |
rust_task::yield(size_t nargs, size_t time_in_us) { | |
LOG(this, task, "task %s @0x%" PRIxPTR " yielding for %d us", | |
name, this, time_in_us); | |
+ | |
+ // TODO: what is nargs for, and is it safe to ignore? | |
+ | |
yield_timer.reset(time_in_us); | |
- run_after_return(nargs, (uintptr_t) new_rust_yield_glue); | |
+ | |
+ // Return to the scheduler. | |
+ swapcontext(&context, context.uc_link); | |
+ | |
+ //run_after_return(nargs, (uintptr_t) new_rust_yield_glue); | |
} | |
static inline uintptr_t | |
diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h | |
index 35b9476..4625bb9 100644 | |
--- a/src/rt/rust_task.h | |
+++ b/src/rt/rust_task.h | |
@@ -25,8 +25,6 @@ rust_task : public maybe_proxy<rust_task>, | |
rust_dom *dom; | |
rust_crate_cache *cache; | |
- ucontext_t context; | |
- | |
// Fields known only to the runtime. | |
const char *const name; | |
rust_task_list *state; | |
@@ -55,6 +53,8 @@ rust_task : public maybe_proxy<rust_task>, | |
rust_handle<rust_task> *handle; | |
+ ucontext_t context; | |
+ | |
// Only a pointer to 'name' is kept, so it must live as long as this task. | |
rust_task(rust_dom *dom, | |
rust_task_list *state, | |
diff --git a/src/test/run-pass/yield.rs b/src/test/run-pass/yield.rs | |
index aa32127..df67b10 100644 | |
--- a/src/test/run-pass/yield.rs | |
+++ b/src/test/run-pass/yield.rs | |
@@ -9,18 +9,18 @@ import std::task::*; | |
fn main() { | |
auto other = spawn child(); | |
- log "1"; | |
+ log_err "1"; | |
yield(); | |
- log "2"; | |
+ log_err "2"; | |
yield(); | |
- log "3"; | |
+ log_err "3"; | |
join(other); | |
} | |
fn child() { | |
- log "4"; | |
+ log_err "4"; | |
yield(); | |
- log "5"; | |
+ log_err "5"; | |
yield(); | |
- log "6"; | |
+ log_err "6"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment