aboutsummaryrefslogtreecommitdiff
path: root/src/rt
diff options
context:
space:
mode:
authorMichael Bebenita <[email protected]>2010-08-11 21:23:34 -0700
committerMichael Bebenita <[email protected]>2010-08-11 21:24:04 -0700
commit988695a96cee1eb825435260a1874b8daa0e590a (patch)
treeee92e117a653c8c6fad100e7416afe5468073ff3 /src/rt
parentSome ELF correctness issues, but apparently none enough to placate gdb. (diff)
downloadrust-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.cpp7
-rw-r--r--src/rt/rust_dom.cpp15
-rw-r--r--src/rt/rust_internal.h1
-rw-r--r--src/rt/rust_task.cpp12
-rw-r--r--src/rt/rust_task.h6
-rw-r--r--src/rt/rust_upcall.cpp8
-rw-r--r--src/rt/sync/timer.cpp61
-rw-r--r--src/rt/sync/timer.h25
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 */