Skip to content

Instantly share code, notes, and snippets.

@eholk
Created June 1, 2011 23:49
Show Gist options
  • Save eholk/1003627 to your computer and use it in GitHub Desktop.
Save eholk/1003627 to your computer and use it in GitHub Desktop.
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