aboutsummaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/Makefile11
-rw-r--r--src/lib/_task.rs12
-rw-r--r--src/lib/std.rc2
-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
-rw-r--r--src/test/run-pass/task-lib.rs6
12 files changed, 154 insertions, 12 deletions
diff --git a/src/Makefile b/src/Makefile
index 63834799..c10088ea 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -35,7 +35,7 @@ ifeq ($(CFG_OSTYPE), Linux)
CFG_RUNTIME := librustrt.so
CFG_STDLIB := libstd.so
CFG_GCC_CFLAGS += -fPIC
- CFG_GCC_LINK_FLAGS += -shared -fPIC -ldl -lpthread
+ CFG_GCC_LINK_FLAGS += -shared -fPIC -ldl -lpthread -lrt
ifeq ($(CFG_CPUTYPE), x86_64)
CFG_GCC_CFLAGS += -m32
CFG_GCC_LINK_FLAGS += -m32
@@ -245,8 +245,9 @@ BOOT_CMXS := $(BOOT_MLS:.ml=.cmx)
BOOT_OBJS := $(BOOT_MLS:.ml=.o)
BOOT_CMIS := $(BOOT_MLS:.ml=.cmi)
-RUNTIME_CS := rt/sync/sync.cpp \
- rt/sync/spin_lock.cpp \
+RUNTIME_CS := rt/sync/timer.cpp \
+ rt/sync/sync.cpp \
+ rt/sync/spin_lock.cpp \
rt/sync/lock_free_queue.cpp \
rt/sync/condition_variable.cpp \
rt/rust.cpp \
@@ -281,7 +282,8 @@ RUNTIME_HDR := rt/globals.h \
rt/circular_buffer.h \
rt/util/array_list.h \
rt/util/hash_map.h \
- rt/sync/sync.h
+ rt/sync/sync.h \
+ rt/sync/timer.h
RUNTIME_INCS := -Irt/isaac -Irt/uthash
RUNTIME_OBJS := $(RUNTIME_CS:.cpp=$(CFG_OBJ_SUFFIX))
@@ -513,6 +515,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
str-concat.rs \
str-idx.rs \
str-lib.rs \
+ task-lib.rs \
tag.rs \
tail-cps.rs \
tail-direct.rs \
diff --git a/src/lib/_task.rs b/src/lib/_task.rs
new file mode 100644
index 00000000..a12c2f27
--- /dev/null
+++ b/src/lib/_task.rs
@@ -0,0 +1,12 @@
+native "rust" mod rustrt {
+ fn task_sleep(uint time_in_us);
+}
+
+/**
+ * Hints the scheduler to yield this task for a specified ammount of time.
+ *
+ * arg: time_in_us maximum number of microseconds to yield control for
+ */
+fn sleep(uint time_in_us) {
+ ret rustrt.task_sleep(time_in_us);
+} \ No newline at end of file
diff --git a/src/lib/std.rc b/src/lib/std.rc
index 8c956691..c2a2cf0c 100644
--- a/src/lib/std.rc
+++ b/src/lib/std.rc
@@ -15,6 +15,7 @@ mod _str;
mod _io;
mod sys;
+mod _task;
// Utility modules.
@@ -25,6 +26,7 @@ mod util;
auth _io = unsafe;
auth _str = unsafe;
auth _vec = unsafe;
+auth _task = unsafe;
auth _int.next_power_of_two = unsafe;
auth map.mk_hashmap = unsafe;
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 */
diff --git a/src/test/run-pass/task-lib.rs b/src/test/run-pass/task-lib.rs
new file mode 100644
index 00000000..18499f4e
--- /dev/null
+++ b/src/test/run-pass/task-lib.rs
@@ -0,0 +1,6 @@
+use std;
+import std._task;
+
+fn main() {
+ _task.sleep(1000000u);
+} \ No newline at end of file