| #include "rust_internal.h" |
| #include "vg/valgrind.h" |
| |
| // The mechanism in this file is very crude; every domain (thread) spawns its |
| // own secondary timer thread, and that timer thread *never idles*. It |
| // sleep-loops interrupting the domain. |
| // |
| // This will need replacement, particularly in order to achieve an actual |
| // state of idling when we're waiting on the outside world. Though that might |
| // be as simple as making a secondary waitable start/stop-timer signalling |
| // system between the domain and its timer thread. We'll see. |
| // |
| // On the other hand, we don't presently have the ability to idle domains *at |
| // all*, and without the timer thread we're unable to otherwise preempt rust |
| // tasks. So ... one step at a time. |
| // |
| // The implementation here is "lockless" in the sense that it only involves |
| // one-directional signaling of one-shot events, so the event initiator just |
| // writes a nonzero word to a prederermined location and waits for the |
| // receiver to see it show up in their memory. |
| |
| #if defined(__WIN32__) |
| static DWORD WINAPI |
| #elif defined(__GNUC__) |
| static void * |
| #else |
| #error "Platform not supported" |
| #endif |
| timer_loop(void *ptr) { |
| // We were handed the rust_timer that owns us. |
| rust_timer *timer = (rust_timer *)ptr; |
| rust_scheduler *sched = timer->sched; |
| DLOG(sched, timer, "in timer 0x%" PRIxPTR, (uintptr_t)timer); |
| size_t ms = TIME_SLICE_IN_MS; |
| |
| while (!timer->exit_flag) { |
| #if defined(__WIN32__) |
| Sleep(ms); |
| #else |
| usleep(ms * 1000); |
| #endif |
| DLOG(sched, timer, "timer 0x%" PRIxPTR |
| " interrupting schedain 0x%" PRIxPTR, (uintptr_t) timer, |
| (uintptr_t) sched); |
| sched->interrupt_flag = 1; |
| } |
| #if defined(__WIN32__) |
| ExitThread(0); |
| #else |
| pthread_exit(NULL); |
| #endif |
| return 0; |
| } |
| |
| rust_timer::rust_timer(rust_scheduler *sched) : |
| sched(sched), exit_flag(0) { |
| DLOG(sched, timer, "creating timer for domain 0x%" PRIxPTR, sched); |
| #if defined(__WIN32__) |
| thread = CreateThread(NULL, 0, timer_loop, this, 0, NULL); |
| sched->kernel->win32_require("CreateThread", thread != NULL); |
| if (RUNNING_ON_VALGRIND) |
| Sleep(10); |
| #else |
| pthread_attr_init(&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); |
| pthread_create(&thread, &attr, timer_loop, (void *)this); |
| #endif |
| } |
| |
| rust_timer::~rust_timer() { |
| exit_flag = 1; |
| #if defined(__WIN32__) |
| sched->kernel->win32_require("WaitForSingleObject", |
| WaitForSingleObject(thread, INFINITE) == |
| WAIT_OBJECT_0); |
| #else |
| pthread_join(thread, NULL); |
| #endif |
| } |
| |
| // |
| // Local Variables: |
| // mode: C++ |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; |
| // End: |
| // |