diff options
| author | Michael Bebenita <[email protected]> | 2010-08-11 21:23:34 -0700 |
|---|---|---|
| committer | Michael Bebenita <[email protected]> | 2010-08-11 21:24:04 -0700 |
| commit | 988695a96cee1eb825435260a1874b8daa0e590a (patch) | |
| tree | ee92e117a653c8c6fad100e7416afe5468073ff3 /src/rt | |
| parent | Some ELF correctness issues, but apparently none enough to placate gdb. (diff) | |
| download | rust-988695a96cee1eb825435260a1874b8daa0e590a.tar.xz rust-988695a96cee1eb825435260a1874b8daa0e590a.zip | |
Added support for task sleeping in the scheduler.
Diffstat (limited to 'src/rt')
| -rw-r--r-- | src/rt/rust_builtin.cpp | 7 | ||||
| -rw-r--r-- | src/rt/rust_dom.cpp | 15 | ||||
| -rw-r--r-- | src/rt/rust_internal.h | 1 | ||||
| -rw-r--r-- | src/rt/rust_task.cpp | 12 | ||||
| -rw-r--r-- | src/rt/rust_task.h | 6 | ||||
| -rw-r--r-- | src/rt/rust_upcall.cpp | 8 | ||||
| -rw-r--r-- | src/rt/sync/timer.cpp | 61 | ||||
| -rw-r--r-- | src/rt/sync/timer.h | 25 |
8 files changed, 127 insertions, 8 deletions
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index acbb10a4..596a05cc 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -191,6 +191,13 @@ rand_free(rust_task *task, randctx *rctx) task->free(rctx); } +extern "C" CDECL void upcall_sleep(rust_task *task, size_t time_in_us); + +extern "C" CDECL void +task_sleep(rust_task *task, size_t time_in_us) { + upcall_sleep(task, time_in_us); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_dom.cpp b/src/rt/rust_dom.cpp index f7b8e97b..1d067560 100644 --- a/src/rt/rust_dom.cpp +++ b/src/rt/rust_dom.cpp @@ -330,7 +330,9 @@ rust_dom::schedule_task() if (running_tasks.length() > 0) { size_t i = rand(&rctx); i %= running_tasks.length(); - return (rust_task *)running_tasks[i]; + if (running_tasks[i]->yield_timer.has_timed_out()) { + return (rust_task *)running_tasks[i]; + } } // log(rust_log::DOM|rust_log::TASK, "no schedulable tasks"); return NULL; @@ -349,8 +351,11 @@ rust_dom::log_state() { log(rust_log::TASK, "running tasks:"); for (size_t i = 0; i < running_tasks.length(); i++) { log(rust_log::TASK, - "\t task: %s @0x%" PRIxPTR, - running_tasks[i]->name, running_tasks[i]); + "\t task: %s @0x%" PRIxPTR + " timeout: %d", + running_tasks[i]->name, + running_tasks[i], + running_tasks[i]->yield_timer.get_timeout()); } } @@ -396,8 +401,8 @@ rust_dom::start_main_loop() rust_task *scheduled_task = schedule_task(); // If we cannot schedule a task because all other live tasks - // are blocked, wait on a condition variable which is signaled - // if progress is made in other domains. + // are blocked, yield and hopefully some progress is made in + // other domains. if (scheduled_task == NULL) { if (_log.is_tracing(rust_log::TASK)) { diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index 17148399..05463c53 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -39,6 +39,7 @@ extern "C" { #endif #include "sync/sync.h" +#include "sync/timer.h" #include "sync/condition_variable.h" #ifndef __i386__ diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index aca8bca7..cd38433e 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -309,10 +309,16 @@ rust_task::run_on_resume(uintptr_t glue) } void -rust_task::yield(size_t nargs) -{ +rust_task::yield(size_t nargs) { + yield(nargs, 0); +} + +void +rust_task::yield(size_t nargs, size_t time_in_us) { log(rust_log::TASK, - "task %s @0x%" PRIxPTR " yielding", name, this); + "task %s @0x%" PRIxPTR " yielding for %d us", + name, this, time_in_us); + yield_timer.reset(time_in_us); run_after_return(nargs, dom->root_crate->get_yield_glue()); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 27495e2c..b66ee5a1 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -29,6 +29,9 @@ rust_task : public maybe_proxy<rust_task>, size_t gc_alloc_thresh; size_t gc_alloc_accum; + // Keeps track of the last time this task yielded. + timer yield_timer; + // Rendezvous pointer for receiving data when blocked on a port. If we're // trying to read data and no data is available on any incoming channel, // we block on the port, and yield control to the scheduler. Since, we @@ -88,6 +91,9 @@ rust_task : public maybe_proxy<rust_task>, // Save callee-saved registers and return to the main loop. void yield(size_t nargs); + // Yields for a specified duration of time. + void yield(size_t nargs, size_t time_in_ms); + // Fail this task (assuming caller-on-stack is different task). void kill(); diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 01eaf744..7f9f0db1 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -183,6 +183,14 @@ extern "C" CDECL void upcall_yield(rust_task *task) { task->yield(1); } +extern "C" CDECL void upcall_sleep(rust_task *task, size_t time_in_us) { + LOG_UPCALL_ENTRY(task); + task->log(rust_log::UPCALL | rust_log::TASK, "elapsed %d", + task->yield_timer.get_elapsed_time()); + task->log(rust_log::UPCALL | rust_log::TASK, "sleep %d us", time_in_us); + task->yield(2, time_in_us); +} + extern "C" CDECL void upcall_join(rust_task *task, maybe_proxy<rust_task> *target) { LOG_UPCALL_ENTRY(task); diff --git a/src/rt/sync/timer.cpp b/src/rt/sync/timer.cpp new file mode 100644 index 00000000..e45dd633 --- /dev/null +++ b/src/rt/sync/timer.cpp @@ -0,0 +1,61 @@ +#include "../globals.h" +#include "timer.h" + +#if defined(__APPLE__) +#include <mach/mach_time.h> +#endif + +timer::timer() { + reset(0); +#if __WIN32__ + uint64_t ticks_per_second; + QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second); + _ticks_per_us = ticks_per_second / 1000000; +#endif +} + +void +timer::reset(uint64_t timeout) { + _start = get_time(); + _timeout = timeout; +} + +uint64_t +timer::get_elapsed_time() { + return get_time() - _start; +} + +int64_t +timer::get_timeout() { + return _timeout - get_elapsed_time(); +} + +bool +timer::has_timed_out() { + return get_timeout() <= 0; +} + +uint64_t +timer::get_time() { +#ifdef __APPLE__ + uint64_t time = mach_absolute_time(); + mach_timebase_info_data_t info = {0, 0}; + if (info.denom == 0) { + mach_timebase_info(&info); + } + uint64_t time_nano = time * (info.numer / info.denom); + return time_nano / 1000; +#elif __WIN32__ + uint64_t ticks; + QueryPerformanceCounter((LARGE_INTEGER *)&ticks); + return ticks / _ticks_per_us; +#else + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000000000LL + ts.tv_nsec) / 1000; +#endif +} + +timer::~timer() { + // Nop. +} diff --git a/src/rt/sync/timer.h b/src/rt/sync/timer.h new file mode 100644 index 00000000..509fd22c --- /dev/null +++ b/src/rt/sync/timer.h @@ -0,0 +1,25 @@ +/* + * Utility class to measure time in a platform independent way. + */ + +#ifndef TIMER_H +#define TIMER_H + +class timer { +private: + uint64_t _start; + uint64_t _timeout; + uint64_t get_time(); +#if __WIN32__ + uint64_t _ticks_per_us; +#endif +public: + timer(); + void reset(uint64_t timeout); + uint64_t get_elapsed_time(); + int64_t get_timeout(); + bool has_timed_out(); + virtual ~timer(); +}; + +#endif /* TIMER_H */ |