aboutsummaryrefslogtreecommitdiff
path: root/src/rt/sync
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-09-08 19:13:49 -0700
committerGraydon Hoare <[email protected]>2010-09-08 19:13:49 -0700
commit616b7afb724a32df41eebfaf95402d008c60b411 (patch)
tree03e13578e8b43b9001cef983d1117800a6f93e65 /src/rt/sync
parentXFAIL many.rs since it crashes on win32, and add a time-slice sleep to the ke... (diff)
downloadrust-616b7afb724a32df41eebfaf95402d008c60b411.tar.xz
rust-616b7afb724a32df41eebfaf95402d008c60b411.zip
Tidy up the sync dir, remove dead or mis-designed code in favour of OS primitives, switch rust_kernel to use a lock/signal pair and wait rather than spin.
Diffstat (limited to 'src/rt/sync')
-rw-r--r--src/rt/sync/condition_variable.cpp84
-rw-r--r--src/rt/sync/condition_variable.h20
-rw-r--r--src/rt/sync/fair_ticket_lock.cpp43
-rw-r--r--src/rt/sync/fair_ticket_lock.h15
-rw-r--r--src/rt/sync/interrupt_transparent_queue.cpp56
-rw-r--r--src/rt/sync/interrupt_transparent_queue.h22
-rwxr-xr-xsrc/rt/sync/lock_and_signal.cpp97
-rw-r--r--src/rt/sync/lock_and_signal.h23
-rw-r--r--src/rt/sync/spin_lock.cpp48
-rw-r--r--src/rt/sync/spin_lock.h14
-rw-r--r--src/rt/sync/sync.cpp9
11 files changed, 125 insertions, 306 deletions
diff --git a/src/rt/sync/condition_variable.cpp b/src/rt/sync/condition_variable.cpp
deleted file mode 100644
index c34ab7f4..00000000
--- a/src/rt/sync/condition_variable.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "../globals.h"
-
-/*
- * Conditional variable. Implemented using pthreads condition variables, and
- * using events on windows.
- */
-
-#include "condition_variable.h"
-
-// #define TRACE
-
-#if defined(__WIN32__)
-condition_variable::condition_variable() {
- _event = CreateEvent(NULL, FALSE, FALSE, NULL);
-}
-#else
-condition_variable::condition_variable() {
- pthread_cond_init(&_cond, NULL);
- pthread_mutex_init(&_mutex, NULL);
-}
-#endif
-
-condition_variable::~condition_variable() {
-#if defined(__WIN32__)
- CloseHandle(_event);
-#else
- pthread_cond_destroy(&_cond);
- pthread_mutex_destroy(&_mutex);
-#endif
-}
-
-/**
- * Wait indefinitely until condition is signaled.
- */
-void condition_variable::wait() {
- timed_wait(0);
-}
-
-void condition_variable::timed_wait(size_t timeout_in_ns) {
-#ifdef TRACE
- printf("waiting on condition_variable: 0x%" PRIxPTR " for %d ns. \n",
- (uintptr_t) this, (int) timeout_in_ns);
-#endif
-#if defined(__WIN32__)
- WaitForSingleObject(_event, INFINITE);
-#else
- pthread_mutex_lock(&_mutex);
- // wait() automatically releases the mutex while it waits, and acquires
- // it right before exiting. This allows signal() to acquire the mutex
- // when signaling.)
- if (timeout_in_ns == 0) {
- pthread_cond_wait(&_cond, &_mutex);
- } else {
- timeval time_val;
- gettimeofday(&time_val, NULL);
- timespec time_spec;
- time_spec.tv_sec = time_val.tv_sec + 0;
- time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ns;
- pthread_cond_timedwait(&_cond, &_mutex, &time_spec);
- }
- pthread_mutex_unlock(&_mutex);
-#endif
-#ifdef TRACE
- printf("resumed on condition_variable: 0x%" PRIxPTR "\n",
- (uintptr_t)this);
-#endif
-}
-
-/**
- * Signal condition, and resume the waiting thread.
- */
-void condition_variable::signal() {
-#if defined(__WIN32__)
- SetEvent(_event);
-#else
- pthread_mutex_lock(&_mutex);
- pthread_cond_signal(&_cond);
- pthread_mutex_unlock(&_mutex);
-#endif
-#ifdef TRACE
- printf("signal condition_variable: 0x%" PRIxPTR "\n",
- (uintptr_t)this);
-#endif
-}
diff --git a/src/rt/sync/condition_variable.h b/src/rt/sync/condition_variable.h
deleted file mode 100644
index f336a7f2..00000000
--- a/src/rt/sync/condition_variable.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef CONDITION_VARIABLE_H
-#define CONDITION_VARIABLE_H
-
-class condition_variable {
-#if defined(__WIN32__)
- HANDLE _event;
-#else
- pthread_cond_t _cond;
- pthread_mutex_t _mutex;
-#endif
-public:
- condition_variable();
- virtual ~condition_variable();
-
- void wait();
- void timed_wait(size_t timeout_in_ns);
- void signal();
-};
-
-#endif /* CONDITION_VARIABLE_H */
diff --git a/src/rt/sync/fair_ticket_lock.cpp b/src/rt/sync/fair_ticket_lock.cpp
deleted file mode 100644
index 0306ee1d..00000000
--- a/src/rt/sync/fair_ticket_lock.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This works well as long as the number of contending threads
- * is less than the number of processors. This is because of
- * the fair locking scheme. If the thread that is next in line
- * for acquiring the lock is not currently running, no other
- * thread can acquire the lock. This is terrible for performance,
- * and it seems that all fair locking schemes suffer from this
- * behavior.
- */
-
-// #define TRACE
-
-fair_ticket_lock::fair_ticket_lock() {
- next_ticket = now_serving = 0;
-}
-
-fair_ticket_lock::~fair_ticket_lock() {
-
-}
-
-void fair_ticket_lock::lock() {
- unsigned ticket = __sync_fetch_and_add(&next_ticket, 1);
- while (now_serving != ticket) {
- pause();
- }
-#ifdef TRACE
- printf("locked nextTicket: %d nowServing: %d",
- next_ticket, now_serving);
-#endif
-}
-
-void fair_ticket_lock::unlock() {
- now_serving++;
-#ifdef TRACE
- printf("unlocked nextTicket: %d nowServing: %d",
- next_ticket, now_serving);
-#endif
-}
-
-void fair_ticket_lock::pause() {
- asm volatile("pause\n" : : : "memory");
-}
-
diff --git a/src/rt/sync/fair_ticket_lock.h b/src/rt/sync/fair_ticket_lock.h
deleted file mode 100644
index c34c9041..00000000
--- a/src/rt/sync/fair_ticket_lock.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef FAIR_TICKET_LOCK_H
-#define FAIR_TICKET_LOCK_H
-
-class fair_ticket_lock {
- unsigned next_ticket;
- unsigned now_serving;
- void pause();
-public:
- fair_ticket_lock();
- virtual ~fair_ticket_lock();
- void lock();
- void unlock();
-};
-
-#endif /* FAIR_TICKET_LOCK_H */
diff --git a/src/rt/sync/interrupt_transparent_queue.cpp b/src/rt/sync/interrupt_transparent_queue.cpp
deleted file mode 100644
index 064b25f1..00000000
--- a/src/rt/sync/interrupt_transparent_queue.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Interrupt transparent queue, Schoen et. al, "On Interrupt-Transparent
- * Synchronization in an Embedded Object-Oriented Operating System", 2000.
- * enqueue() is allowed to interrupt enqueue() and dequeue(), however,
- * dequeue() is not allowed to interrupt itself.
- */
-
-#include "../globals.h"
-#include "interrupt_transparent_queue.h"
-
-interrupt_transparent_queue_node::interrupt_transparent_queue_node() :
- next(NULL) {
-
-}
-
-interrupt_transparent_queue::interrupt_transparent_queue() : _tail(this) {
-
-}
-
-void
-interrupt_transparent_queue::enqueue(interrupt_transparent_queue_node *item) {
- lock.lock();
- item->next = (interrupt_transparent_queue_node *) NULL;
- interrupt_transparent_queue_node *last = _tail;
- _tail = item;
- while (last->next) {
- last = last->next;
- }
- last->next = item;
- lock.unlock();
-}
-
-interrupt_transparent_queue_node *
-interrupt_transparent_queue::dequeue() {
- lock.lock();
- interrupt_transparent_queue_node *item = next;
- if (item && !(next = item->next)) {
- _tail = (interrupt_transparent_queue_node *) this;
- if (item->next) {
- interrupt_transparent_queue_node *lost = item->next;
- interrupt_transparent_queue_node *help;
- do {
- help = lost->next;
- enqueue(lost);
- } while ((lost = help) !=
- (interrupt_transparent_queue_node *) NULL);
- }
- }
- lock.unlock();
- return item;
-}
-
-bool
-interrupt_transparent_queue::is_empty() {
- return next == NULL;
-}
diff --git a/src/rt/sync/interrupt_transparent_queue.h b/src/rt/sync/interrupt_transparent_queue.h
deleted file mode 100644
index 7c02d0c8..00000000
--- a/src/rt/sync/interrupt_transparent_queue.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef INTERRUPT_TRANSPARENT_QUEUE_H
-#define INTERRUPT_TRANSPARENT_QUEUE_H
-
-#include "spin_lock.h"
-
-class interrupt_transparent_queue_node {
-public:
- interrupt_transparent_queue_node *next;
- interrupt_transparent_queue_node();
-};
-
-class interrupt_transparent_queue : interrupt_transparent_queue_node {
- spin_lock lock;
- interrupt_transparent_queue_node *_tail;
-public:
- interrupt_transparent_queue();
- void enqueue(interrupt_transparent_queue_node *item);
- interrupt_transparent_queue_node *dequeue();
- bool is_empty();
-};
-
-#endif /* INTERRUPT_TRANSPARENT_QUEUE_H */
diff --git a/src/rt/sync/lock_and_signal.cpp b/src/rt/sync/lock_and_signal.cpp
new file mode 100755
index 00000000..c010086e
--- /dev/null
+++ b/src/rt/sync/lock_and_signal.cpp
@@ -0,0 +1,97 @@
+#include "../globals.h"
+
+/*
+ * A "lock-and-signal" pair. These are necessarily coupled on pthreads
+ * systems, and artificially coupled (by this file) on win32. Put
+ * together here to minimize ifdefs elsewhere; you must use them as
+ * if you're using a pthreads cvar+mutex pair.
+ */
+
+#include "lock_and_signal.h"
+
+#if defined(__WIN32__)
+lock_and_signal::lock_and_signal() {
+ _event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ InitializeCriticalSection(&_cs);
+}
+
+#else
+lock_and_signal::lock_and_signal() {
+ pthread_cond_init(&_cond, NULL);
+ pthread_mutex_init(&_mutex, NULL);
+}
+#endif
+
+lock_and_signal::~lock_and_signal() {
+#if defined(__WIN32__)
+ CloseHandle(_event);
+#else
+ pthread_cond_destroy(&_cond);
+ pthread_mutex_destroy(&_mutex);
+#endif
+}
+
+void lock_and_signal::lock() {
+#if defined(__WIN32__)
+ EnterCriticalSection(&_cs);
+#else
+ pthread_mutex_lock(&_mutex);
+#endif
+}
+
+void lock_and_signal::unlock() {
+#if defined(__WIN32__)
+ LeaveCriticalSection(&_cs);
+#else
+ pthread_mutex_unlock(&_mutex);
+#endif
+}
+
+
+/**
+ * Wait indefinitely until condition is signaled.
+ */
+void lock_and_signal::wait() {
+ timed_wait(0);
+}
+
+void lock_and_signal::timed_wait(size_t timeout_in_ns) {
+#if defined(__WIN32__)
+ LeaveCriticalSection(&_cs);
+ WaitForSingleObject(_event, INFINITE);
+ EnterCriticalSection(&_cs);
+#else
+ if (timeout_in_ns == 0) {
+ pthread_cond_wait(&_cond, &_mutex);
+ } else {
+ timeval time_val;
+ gettimeofday(&time_val, NULL);
+ timespec time_spec;
+ time_spec.tv_sec = time_val.tv_sec + 0;
+ time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ns;
+ pthread_cond_timedwait(&_cond, &_mutex, &time_spec);
+ }
+#endif
+}
+
+/**
+ * Signal condition, and resume the waiting thread.
+ */
+void lock_and_signal::signal() {
+#if defined(__WIN32__)
+ SetEvent(_event);
+#else
+ pthread_cond_signal(&_cond);
+#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 .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/rt/sync/lock_and_signal.h b/src/rt/sync/lock_and_signal.h
new file mode 100644
index 00000000..5a852d9d
--- /dev/null
+++ b/src/rt/sync/lock_and_signal.h
@@ -0,0 +1,23 @@
+#ifndef LOCK_AND_SIGNAL_H
+#define LOCK_AND_SIGNAL_H
+
+class lock_and_signal {
+#if defined(__WIN32__)
+ HANDLE _event;
+ CRITICAL_SECTION _cs;
+#else
+ pthread_cond_t _cond;
+ pthread_mutex_t _mutex;
+#endif
+public:
+ lock_and_signal();
+ virtual ~lock_and_signal();
+
+ void lock();
+ void unlock();
+ void wait();
+ void timed_wait(size_t timeout_in_ns);
+ void signal();
+};
+
+#endif /* LOCK_AND_SIGNAL_H */
diff --git a/src/rt/sync/spin_lock.cpp b/src/rt/sync/spin_lock.cpp
deleted file mode 100644
index 4a113d1a..00000000
--- a/src/rt/sync/spin_lock.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#include "../globals.h"
-#include "spin_lock.h"
-
-/*
- * Your average spin lock.
- */
-
-// #define TRACE
-
-spin_lock::spin_lock() {
- unlock();
-}
-
-spin_lock::~spin_lock() {
-}
-
-static inline unsigned xchg32(void *ptr, unsigned x) {
- __asm__ __volatile__("xchgl %0,%1"
- :"=r" ((unsigned) x)
- :"m" (*(volatile unsigned *)ptr), "0" (x)
- :"memory");
- return x;
-}
-
-void spin_lock::lock() {
- while (true) {
- if (!xchg32(&ticket, 1)) {
- return;
- }
- while (ticket) {
- pause();
- }
- }
-#ifdef TRACE
- printf(" lock: %d", ticket);
-#endif
-}
-
-void spin_lock::unlock() {
- ticket = 0;
-#ifdef TRACE
- printf("unlock:");
-#endif
-}
-
-void spin_lock::pause() {
- asm volatile("pause\n" : : : "memory");
-}
diff --git a/src/rt/sync/spin_lock.h b/src/rt/sync/spin_lock.h
deleted file mode 100644
index f15416a2..00000000
--- a/src/rt/sync/spin_lock.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SPIN_LOCK_H
-#define SPIN_LOCK_H
-
-class spin_lock {
- unsigned ticket;
- void pause();
-public:
- spin_lock();
- virtual ~spin_lock();
- void lock();
- void unlock();
-};
-
-#endif /* SPIN_LOCK_H */
diff --git a/src/rt/sync/sync.cpp b/src/rt/sync/sync.cpp
index fdfc0652..c754392a 100644
--- a/src/rt/sync/sync.cpp
+++ b/src/rt/sync/sync.cpp
@@ -11,7 +11,7 @@ void sync::yield() {
#endif
}
-rust_thread::rust_thread() : _is_running(false) {
+rust_thread::rust_thread() : _is_running(false), thread(0) {
// Nop.
}
@@ -25,7 +25,6 @@ static void *
rust_thread_start(void *ptr) {
rust_thread *thread = (rust_thread *) ptr;
thread->run();
- thread->thread = 0;
return 0;
}
@@ -46,9 +45,11 @@ rust_thread::start() {
void
rust_thread::join() {
#if defined(__WIN32__)
- WaitForSingleObject(thread, INFINITE);
+ if (thread)
+ WaitForSingleObject(thread, INFINITE);
#else
- pthread_join(thread, NULL);
+ if (thread)
+ pthread_join(thread, NULL);
#endif
thread = 0;
_is_running = false;