aboutsummaryrefslogtreecommitdiffstats
path: root/thread_win32.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-11-27 20:15:59 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-11-27 20:15:59 +0000
commit450463d5fbc7098666c1405b5ea1ece4c8dd04a5 (patch)
tree028db9106314e277c7bd6329c97ce13fef9e9094 /thread_win32.c
parentac0f5a53b6d567b319df73878bd08d70cbbdc37c (diff)
downloadruby-450463d5fbc7098666c1405b5ea1ece4c8dd04a5.tar.gz
* thread.c, vm_core.h: make gvl_acquire/release/init/destruct
APIs to modularize GVL implementation. * thread_pthread.c, thread_pthread.h: Two GVL implementations. (1) Simple locking GVL which is same as existing GVL. (2) Wake-up queued threads. The wake-up order is simple FIFO. (We can make several queues to support exact priorities, however this causes some issues such as priority inversion and so on.) This impl. prevents spin-loop (*1) caused on SMP environemnts. *1: Only one Ruby thread acqures GVL again and again. Bug #2359 [ruby-core:26694] * thread_win32.c, thread_win32.h: Using simple lock not by CRITICAL_SECTION but by Mutex. Bug #3890 [ruby-dev:42315] * vm.c (ruby_vm_destruct): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29956 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'thread_win32.c')
-rw-r--r--thread_win32.c163
1 files changed, 104 insertions, 59 deletions
diff --git a/thread_win32.c b/thread_win32.c
index dc0b236328..51f74298fa 100644
--- a/thread_win32.c
+++ b/thread_win32.c
@@ -25,6 +25,7 @@ static int native_mutex_lock(rb_thread_lock_t *);
static int native_mutex_unlock(rb_thread_lock_t *);
static int native_mutex_trylock(rb_thread_lock_t *);
static void native_mutex_initialize(rb_thread_lock_t *);
+static void native_mutex_destroy(rb_thread_lock_t *);
static void native_cond_signal(rb_thread_cond_t *cond);
static void native_cond_broadcast(rb_thread_cond_t *cond);
@@ -32,6 +33,105 @@ static void native_cond_wait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex);
static void native_cond_initialize(rb_thread_cond_t *cond);
static void native_cond_destroy(rb_thread_cond_t *cond);
+static void
+w32_error(const char *func)
+{
+ LPVOID lpMsgBuf;
+ DWORD err = GetLastError();
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPTSTR) & lpMsgBuf, 0, NULL) == 0)
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) & lpMsgBuf, 0, NULL);
+ rb_bug("%s: %s", func, (char*)lpMsgBuf);
+}
+
+static int
+w32_mutex_lock(HANDLE lock)
+{
+ DWORD result;
+ while (1) {
+ thread_debug("native_mutex_lock: %p\n", lock);
+ result = w32_wait_events(&lock, 1, INFINITE, 0);
+ switch (result) {
+ case WAIT_OBJECT_0:
+ /* get mutex object */
+ thread_debug("acquire mutex: %p\n", lock);
+ return 0;
+ case WAIT_OBJECT_0 + 1:
+ /* interrupt */
+ errno = EINTR;
+ thread_debug("acquire mutex interrupted: %p\n", lock);
+ return 0;
+ case WAIT_TIMEOUT:
+ thread_debug("timeout mutex: %p\n", lock);
+ break;
+ case WAIT_ABANDONED:
+ rb_bug("win32_mutex_lock: WAIT_ABANDONED");
+ break;
+ default:
+ rb_bug("win32_mutex_lock: unknown result (%d)", result);
+ break;
+ }
+ }
+ return 0;
+}
+
+static HANDLE
+w32_mutex_create(void)
+{
+ HANDLE lock = CreateMutex(NULL, FALSE, NULL);
+ if (lock == NULL) {
+ w32_error("native_mutex_initialize");
+ }
+ return lock;
+}
+
+#define GVL_DEBUG 0
+
+static void
+gvl_acquire(rb_vm_t *vm, rb_thread_t *th)
+{
+ w32_mutex_lock(vm->gvl.lock);
+ if (GVL_DEBUG) fprintf(stderr, "gvl acquire (%p): acquire\n", th);
+}
+
+static void
+gvl_release(rb_vm_t *vm)
+{
+ ReleaseMutex(vm->gvl.lock);
+}
+
+static void
+gvl_atfork(rb_vm_t *vm)
+{
+ rb_bug("gvl_atfork() is called on win32");
+}
+
+static void
+gvl_init(rb_vm_t *vm)
+{
+ int r;
+ if (GVL_DEBUG) fprintf(stderr, "gvl init\n");
+ vm->gvl.lock = w32_mutex_create();
+}
+
+static void
+gvl_destroy(rb_vm_t *vm)
+{
+ if (GVL_DEBUG) fprintf(stderr, "gvl destroy\n");
+ CloseHandle(vm->gvl.lock);
+}
+
static rb_thread_t *
ruby_thread_from_native(void)
{
@@ -64,28 +164,6 @@ Init_native_thread(void)
}
static void
-w32_error(const char *func)
-{
- LPVOID lpMsgBuf;
- DWORD err = GetLastError();
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- err,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (LPTSTR) & lpMsgBuf, 0, NULL) == 0)
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- err,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) & lpMsgBuf, 0, NULL);
- rb_bug("%s: %s", func, (char*)lpMsgBuf);
-}
-
-static void
w32_set_event(HANDLE handle)
{
if (SetEvent(handle) == 0) {
@@ -111,7 +189,7 @@ w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n",
events, count, timeout, th);
if (th && (intr = th->native_thread_data.interrupt_event)) {
- native_mutex_lock(&th->vm->global_vm_lock);
+ gvl_acquire(th->vm, th);
if (intr == th->native_thread_data.interrupt_event) {
w32_reset_event(intr);
if (RUBY_VM_INTERRUPTED(th)) {
@@ -124,7 +202,7 @@ w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
targets[count++] = intr;
thread_debug(" * handle: %p (count: %d, intr)\n", intr, count);
}
- native_mutex_unlock(&th->vm->global_vm_lock);
+ gvl_release(th->vm);
}
thread_debug(" WaitForMultipleObjects start (count: %d)\n", count);
@@ -260,32 +338,7 @@ static int
native_mutex_lock(rb_thread_lock_t *lock)
{
#if USE_WIN32_MUTEX
- DWORD result;
- while (1) {
- thread_debug("native_mutex_lock: %p\n", *lock);
- result = w32_wait_events(&*lock, 1, INFINITE, 0);
- switch (result) {
- case WAIT_OBJECT_0:
- /* get mutex object */
- thread_debug("acquire mutex: %p\n", *lock);
- return 0;
- case WAIT_OBJECT_0 + 1:
- /* interrupt */
- errno = EINTR;
- thread_debug("acquire mutex interrupted: %p\n", *lock);
- return 0;
- case WAIT_TIMEOUT:
- thread_debug("timeout mutex: %p\n", *lock);
- break;
- case WAIT_ABANDONED:
- rb_bug("win32_mutex_lock: WAIT_ABANDONED");
- break;
- default:
- rb_bug("win32_mutex_lock: unknown result (%d)", result);
- break;
- }
- }
- return 0;
+ w32_mutex_lock(*lock);
#else
EnterCriticalSection(lock);
return 0;
@@ -328,10 +381,7 @@ static void
native_mutex_initialize(rb_thread_lock_t *lock)
{
#if USE_WIN32_MUTEX
- *lock = CreateMutex(NULL, FALSE, NULL);
- if (*lock == NULL) {
- w32_error("native_mutex_initialize");
- }
+ *lock = w32_mutex_create();
/* thread_debug("initialize mutex: %p\n", *lock); */
#else
InitializeCriticalSection(lock);
@@ -355,11 +405,6 @@ struct cond_event_entry {
HANDLE event;
};
-struct rb_thread_cond_struct {
- struct cond_event_entry *next;
- struct cond_event_entry *last;
-};
-
static void
native_cond_signal(rb_thread_cond_t *cond)
{