00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
00013
00014 #include <process.h>
00015
00016 #define WIN32_WAIT_TIMEOUT 10
00017 #undef Sleep
00018
00019 #define native_thread_yield() Sleep(0)
00020 #define remove_signal_thread_list(th)
00021
00022 static volatile DWORD ruby_native_thread_key = TLS_OUT_OF_INDEXES;
00023
00024 static int native_mutex_lock(rb_thread_lock_t *);
00025 static int native_mutex_unlock(rb_thread_lock_t *);
00026 static int native_mutex_trylock(rb_thread_lock_t *);
00027 static void native_mutex_initialize(rb_thread_lock_t *);
00028
00029 static void native_cond_signal(rb_thread_cond_t *cond);
00030 static void native_cond_broadcast(rb_thread_cond_t *cond);
00031 static void native_cond_wait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex);
00032 static void native_cond_initialize(rb_thread_cond_t *cond);
00033 static void native_cond_destroy(rb_thread_cond_t *cond);
00034
00035 static rb_thread_t *
00036 ruby_thread_from_native(void)
00037 {
00038 return TlsGetValue(ruby_native_thread_key);
00039 }
00040
00041 static int
00042 ruby_thread_set_native(rb_thread_t *th)
00043 {
00044 return TlsSetValue(ruby_native_thread_key, th);
00045 }
00046
00047 void
00048 Init_native_thread(void)
00049 {
00050 rb_thread_t *th = GET_THREAD();
00051
00052 ruby_native_thread_key = TlsAlloc();
00053 ruby_thread_set_native(th);
00054 DuplicateHandle(GetCurrentProcess(),
00055 GetCurrentThread(),
00056 GetCurrentProcess(),
00057 &th->thread_id, 0, FALSE, DUPLICATE_SAME_ACCESS);
00058
00059 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
00060
00061 thread_debug("initial thread (th: %p, thid: %p, event: %p)\n",
00062 th, GET_THREAD()->thread_id,
00063 th->native_thread_data.interrupt_event);
00064 }
00065
00066 static void
00067 w32_error(const char *func)
00068 {
00069 LPVOID lpMsgBuf;
00070 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
00071 FORMAT_MESSAGE_FROM_SYSTEM |
00072 FORMAT_MESSAGE_IGNORE_INSERTS,
00073 NULL,
00074 GetLastError(),
00075 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00076 (LPTSTR) & lpMsgBuf, 0, NULL);
00077 rb_bug("%s: %s", func, (char*)lpMsgBuf);
00078 }
00079
00080 static void
00081 w32_set_event(HANDLE handle)
00082 {
00083 if (SetEvent(handle) == 0) {
00084 w32_error("w32_set_event");
00085 }
00086 }
00087
00088 static void
00089 w32_reset_event(HANDLE handle)
00090 {
00091 if (ResetEvent(handle) == 0) {
00092 w32_error("w32_reset_event");
00093 }
00094 }
00095
00096 static int
00097 w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
00098 {
00099 HANDLE *targets = events;
00100 HANDLE intr;
00101 DWORD ret;
00102
00103 thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n",
00104 events, count, timeout, th);
00105 if (th && (intr = th->native_thread_data.interrupt_event)) {
00106 native_mutex_lock(&th->vm->global_vm_lock);
00107 if (intr == th->native_thread_data.interrupt_event) {
00108 w32_reset_event(intr);
00109 if (RUBY_VM_INTERRUPTED(th)) {
00110 w32_set_event(intr);
00111 }
00112
00113 targets = ALLOCA_N(HANDLE, count + 1);
00114 memcpy(targets, events, sizeof(HANDLE) * count);
00115
00116 targets[count++] = intr;
00117 thread_debug(" * handle: %p (count: %d, intr)\n", intr, count);
00118 }
00119 native_mutex_unlock(&th->vm->global_vm_lock);
00120 }
00121
00122 thread_debug(" WaitForMultipleObjects start (count: %d)\n", count);
00123 ret = WaitForMultipleObjects(count, targets, FALSE, timeout);
00124 thread_debug(" WaitForMultipleObjects end (ret: %lu)\n", ret);
00125
00126 if (ret == WAIT_OBJECT_0 + count - 1 && th) {
00127 errno = EINTR;
00128 }
00129 if (ret == -1 && THREAD_DEBUG) {
00130 int i;
00131 DWORD dmy;
00132 for (i = 0; i < count; i++) {
00133 thread_debug(" * error handle %d - %s\n", i,
00134 GetHandleInformation(targets[i], &dmy) ? "OK" : "NG");
00135 }
00136 }
00137 return ret;
00138 }
00139
00140 static void ubf_handle(void *ptr);
00141 #define ubf_select ubf_handle
00142
00143 int
00144 rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
00145 {
00146 return w32_wait_events(events, num, timeout, GET_THREAD());
00147 }
00148
00149 int
00150 rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
00151 {
00152 int ret;
00153
00154 BLOCKING_REGION(ret = rb_w32_wait_events_blocking(events, num, timeout),
00155 ubf_handle, GET_THREAD());
00156 return ret;
00157 }
00158
00159 static void
00160 w32_close_handle(HANDLE handle)
00161 {
00162 if (CloseHandle(handle) == 0) {
00163 w32_error("w32_close_handle");
00164 }
00165 }
00166
00167 static void
00168 w32_resume_thread(HANDLE handle)
00169 {
00170 if (ResumeThread(handle) == -1) {
00171 w32_error("w32_resume_thread");
00172 }
00173 }
00174
00175 #ifdef _MSC_VER
00176 #define HAVE__BEGINTHREADEX 1
00177 #else
00178 #undef HAVE__BEGINTHREADEX
00179 #endif
00180
00181 #ifdef HAVE__BEGINTHREADEX
00182 #define start_thread (HANDLE)_beginthreadex
00183 #define thread_errno errno
00184 typedef unsigned long (_stdcall *w32_thread_start_func)(void*);
00185 #else
00186 #define start_thread CreateThread
00187 #define thread_errno rb_w32_map_errno(GetLastError())
00188 typedef LPTHREAD_START_ROUTINE w32_thread_start_func;
00189 #endif
00190
00191 static HANDLE
00192 w32_create_thread(DWORD stack_size, w32_thread_start_func func, void *val)
00193 {
00194 return start_thread(0, stack_size, func, val, CREATE_SUSPENDED, 0);
00195 }
00196
00197 int
00198 rb_w32_sleep(unsigned long msec)
00199 {
00200 return w32_wait_events(0, 0, msec, GET_THREAD());
00201 }
00202
00203 int WINAPI
00204 rb_w32_Sleep(unsigned long msec)
00205 {
00206 int ret;
00207
00208 BLOCKING_REGION(ret = rb_w32_sleep(msec),
00209 ubf_handle, GET_THREAD());
00210 return ret;
00211 }
00212
00213 static void
00214 native_sleep(rb_thread_t *th, struct timeval *tv)
00215 {
00216 DWORD msec;
00217
00218 if (tv) {
00219 msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
00220 }
00221 else {
00222 msec = INFINITE;
00223 }
00224
00225 GVL_UNLOCK_BEGIN();
00226 {
00227 DWORD ret;
00228
00229 native_mutex_lock(&th->interrupt_lock);
00230 th->unblock.func = ubf_handle;
00231 th->unblock.arg = th;
00232 native_mutex_unlock(&th->interrupt_lock);
00233
00234 if (RUBY_VM_INTERRUPTED(th)) {
00235
00236 }
00237 else {
00238 thread_debug("native_sleep start (%lu)\n", msec);
00239 ret = w32_wait_events(0, 0, msec, th);
00240 thread_debug("native_sleep done (%lu)\n", ret);
00241 }
00242
00243 native_mutex_lock(&th->interrupt_lock);
00244 th->unblock.func = 0;
00245 th->unblock.arg = 0;
00246 native_mutex_unlock(&th->interrupt_lock);
00247 }
00248 GVL_UNLOCK_END();
00249 }
00250
00251 static int
00252 native_mutex_lock(rb_thread_lock_t *lock)
00253 {
00254 #if USE_WIN32_MUTEX
00255 DWORD result;
00256 while (1) {
00257 thread_debug("native_mutex_lock: %p\n", *lock);
00258 result = w32_wait_events(&*lock, 1, INFINITE, 0);
00259 switch (result) {
00260 case WAIT_OBJECT_0:
00261
00262 thread_debug("acquire mutex: %p\n", *lock);
00263 return 0;
00264 case WAIT_OBJECT_0 + 1:
00265
00266 errno = EINTR;
00267 thread_debug("acquire mutex interrupted: %p\n", *lock);
00268 return 0;
00269 case WAIT_TIMEOUT:
00270 thread_debug("timeout mutex: %p\n", *lock);
00271 break;
00272 case WAIT_ABANDONED:
00273 rb_bug("win32_mutex_lock: WAIT_ABANDONED");
00274 break;
00275 default:
00276 rb_bug("win32_mutex_lock: unknown result (%d)", result);
00277 break;
00278 }
00279 }
00280 return 0;
00281 #else
00282 EnterCriticalSection(lock);
00283 return 0;
00284 #endif
00285 }
00286
00287 static int
00288 native_mutex_unlock(rb_thread_lock_t *lock)
00289 {
00290 #if USE_WIN32_MUTEX
00291 thread_debug("release mutex: %p\n", *lock);
00292 return ReleaseMutex(*lock);
00293 #else
00294 LeaveCriticalSection(lock);
00295 return 0;
00296 #endif
00297 }
00298
00299 static int
00300 native_mutex_trylock(rb_thread_lock_t *lock)
00301 {
00302 #if USE_WIN32_MUTEX
00303 int result;
00304 thread_debug("native_mutex_trylock: %p\n", *lock);
00305 result = w32_wait_events(&*lock, 1, 1, 0);
00306 thread_debug("native_mutex_trylock result: %d\n", result);
00307 switch (result) {
00308 case WAIT_OBJECT_0:
00309 return 0;
00310 case WAIT_TIMEOUT:
00311 return EBUSY;
00312 }
00313 return EINVAL;
00314 #else
00315 return TryEnterCriticalSection(lock) == 0;
00316 #endif
00317 }
00318
00319 static void
00320 native_mutex_initialize(rb_thread_lock_t *lock)
00321 {
00322 #if USE_WIN32_MUTEX
00323 *lock = CreateMutex(NULL, FALSE, NULL);
00324 if (*lock == NULL) {
00325 w32_error("native_mutex_initialize");
00326 }
00327
00328 #else
00329 InitializeCriticalSection(lock);
00330 #endif
00331 }
00332
00333 #define native_mutex_reinitialize_atfork(lock) (void)(lock)
00334
00335 static void
00336 native_mutex_destroy(rb_thread_lock_t *lock)
00337 {
00338 #if USE_WIN32_MUTEX
00339 w32_close_handle(lock);
00340 #else
00341 DeleteCriticalSection(lock);
00342 #endif
00343 }
00344
00345 struct cond_event_entry {
00346 struct cond_event_entry* next;
00347 HANDLE event;
00348 };
00349
00350 struct rb_thread_cond_struct {
00351 struct cond_event_entry *next;
00352 struct cond_event_entry *last;
00353 };
00354
00355 static void
00356 native_cond_signal(rb_thread_cond_t *cond)
00357 {
00358
00359 struct cond_event_entry *e = cond->next;
00360
00361 if (e) {
00362 cond->next = e->next;
00363 SetEvent(e->event);
00364 }
00365 else {
00366 rb_bug("native_cond_signal: no pending threads");
00367 }
00368 }
00369
00370 static void
00371 native_cond_broadcast(rb_thread_cond_t *cond)
00372 {
00373
00374 struct cond_event_entry *e = cond->next;
00375 cond->next = 0;
00376
00377 while (e) {
00378 SetEvent(e->event);
00379 e = e->next;
00380 }
00381 }
00382
00383 static void
00384 native_cond_wait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex)
00385 {
00386 DWORD r;
00387 struct cond_event_entry entry;
00388
00389 entry.next = 0;
00390 entry.event = CreateEvent(0, FALSE, FALSE, 0);
00391
00392
00393 if (cond->next) {
00394 cond->last->next = &entry;
00395 cond->last = &entry;
00396 }
00397 else {
00398 cond->next = &entry;
00399 cond->last = &entry;
00400 }
00401
00402 native_mutex_unlock(mutex);
00403 {
00404 r = WaitForSingleObject(entry.event, INFINITE);
00405 if (r != WAIT_OBJECT_0) {
00406 rb_bug("native_cond_wait: WaitForSingleObject returns %lu", r);
00407 }
00408 }
00409 native_mutex_lock(mutex);
00410
00411 w32_close_handle(entry.event);
00412 }
00413
00414 static void
00415 native_cond_initialize(rb_thread_cond_t *cond)
00416 {
00417 cond->next = 0;
00418 cond->last = 0;
00419 }
00420
00421 static void
00422 native_cond_destroy(rb_thread_cond_t *cond)
00423 {
00424
00425 }
00426
00427 void
00428 ruby_init_stack(volatile VALUE *addr)
00429 {
00430 }
00431
00432 #define CHECK_ERR(expr) \
00433 {if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}}
00434
00435 static void
00436 native_thread_init_stack(rb_thread_t *th)
00437 {
00438 MEMORY_BASIC_INFORMATION mi;
00439 char *base, *end;
00440 DWORD size, space;
00441
00442 CHECK_ERR(VirtualQuery(&mi, &mi, sizeof(mi)));
00443 base = mi.AllocationBase;
00444 end = mi.BaseAddress;
00445 end += mi.RegionSize;
00446 size = end - base;
00447 space = size / 5;
00448 if (space > 1024*1024) space = 1024*1024;
00449 th->machine_stack_start = (VALUE *)end - 1;
00450 th->machine_stack_maxsize = size - space;
00451 }
00452
00453 #ifndef InterlockedExchangePointer
00454 #define InterlockedExchangePointer(t, v) \
00455 (void *)InterlockedExchange((long *)(t), (long)(v))
00456 #endif
00457 static void
00458 native_thread_destroy(rb_thread_t *th)
00459 {
00460 HANDLE intr = InterlockedExchangePointer(&th->native_thread_data.interrupt_event, 0);
00461 native_mutex_destroy(&th->interrupt_lock);
00462 thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id);
00463 w32_close_handle(intr);
00464 }
00465
00466 static unsigned long _stdcall
00467 thread_start_func_1(void *th_ptr)
00468 {
00469 rb_thread_t *th = th_ptr;
00470 volatile HANDLE thread_id = th->thread_id;
00471
00472 native_thread_init_stack(th);
00473 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
00474
00475
00476 thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th,
00477 th->thread_id, th->native_thread_data.interrupt_event);
00478
00479 thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp());
00480
00481 w32_close_handle(thread_id);
00482 thread_debug("thread deleted (th: %p)\n", th);
00483 return 0;
00484 }
00485
00486 static int
00487 native_thread_create(rb_thread_t *th)
00488 {
00489 size_t stack_size = 4 * 1024;
00490 th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th);
00491
00492 if ((th->thread_id) == 0) {
00493 return thread_errno;
00494 }
00495
00496 w32_resume_thread(th->thread_id);
00497
00498 if (THREAD_DEBUG) {
00499 Sleep(0);
00500 thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %d\n",
00501 th, th->thread_id,
00502 th->native_thread_data.interrupt_event, stack_size);
00503 }
00504 return 0;
00505 }
00506
00507 static void
00508 native_thread_join(HANDLE th)
00509 {
00510 w32_wait_events(&th, 1, INFINITE, 0);
00511 }
00512
00513 #if USE_NATIVE_THREAD_PRIORITY
00514
00515 static void
00516 native_thread_apply_priority(rb_thread_t *th)
00517 {
00518 int priority = th->priority;
00519 if (th->priority > 0) {
00520 priority = THREAD_PRIORITY_ABOVE_NORMAL;
00521 }
00522 else if (th->priority < 0) {
00523 priority = THREAD_PRIORITY_BELOW_NORMAL;
00524 }
00525 else {
00526 priority = THREAD_PRIORITY_NORMAL;
00527 }
00528
00529 SetThreadPriority(th->thread_id, priority);
00530 }
00531
00532 #endif
00533
00534 static void
00535 ubf_handle(void *ptr)
00536 {
00537 rb_thread_t *th = (rb_thread_t *)ptr;
00538 thread_debug("ubf_handle: %p\n", th);
00539
00540 w32_set_event(th->native_thread_data.interrupt_event);
00541 }
00542
00543 static HANDLE timer_thread_id = 0;
00544 static HANDLE timer_thread_lock;
00545
00546 static unsigned long _stdcall
00547 timer_thread_func(void *dummy)
00548 {
00549 thread_debug("timer_thread\n");
00550 while (WaitForSingleObject(timer_thread_lock, WIN32_WAIT_TIMEOUT) ==
00551 WAIT_TIMEOUT) {
00552 timer_thread_function(dummy);
00553 }
00554 thread_debug("timer killed\n");
00555 return 0;
00556 }
00557
00558 static void
00559 rb_thread_create_timer_thread(void)
00560 {
00561 if (timer_thread_id == 0) {
00562 if (!timer_thread_lock) {
00563 timer_thread_lock = CreateEvent(0, TRUE, FALSE, 0);
00564 }
00565 timer_thread_id = w32_create_thread(1024 + (THREAD_DEBUG ? BUFSIZ : 0),
00566 timer_thread_func, 0);
00567 w32_resume_thread(timer_thread_id);
00568 }
00569 }
00570
00571 static int
00572 native_stop_timer_thread(void)
00573 {
00574 int stopped = --system_working <= 0;
00575 if (stopped) {
00576 SetEvent(timer_thread_lock);
00577 native_thread_join(timer_thread_id);
00578 CloseHandle(timer_thread_lock);
00579 timer_thread_lock = 0;
00580 }
00581 return stopped;
00582 }
00583
00584 static void
00585 native_reset_timer_thread(void)
00586 {
00587 if (timer_thread_id) {
00588 CloseHandle(timer_thread_id);
00589 timer_thread_id = 0;
00590 }
00591 }
00592
00593 #endif
00594