Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* -*-c-*- */ 00002 /********************************************************************** 00003 00004 thread_win32.c - 00005 00006 $Author: ko1 $ 00007 00008 Copyright (C) 2004-2007 Koichi Sasada 00009 00010 **********************************************************************/ 00011 00012 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION 00013 00014 #include <process.h> 00015 00016 #define TIME_QUANTUM_USEC (10 * 1000) 00017 #define RB_CONDATTR_CLOCK_MONOTONIC 1 /* no effect */ 00018 00019 #undef Sleep 00020 00021 #define native_thread_yield() Sleep(0) 00022 #define remove_signal_thread_list(th) 00023 00024 static volatile DWORD ruby_native_thread_key = TLS_OUT_OF_INDEXES; 00025 00026 static int w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th); 00027 static int native_mutex_lock(rb_thread_lock_t *lock); 00028 static int native_mutex_unlock(rb_thread_lock_t *lock); 00029 00030 static void 00031 w32_error(const char *func) 00032 { 00033 LPVOID lpMsgBuf; 00034 DWORD err = GetLastError(); 00035 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 00036 FORMAT_MESSAGE_FROM_SYSTEM | 00037 FORMAT_MESSAGE_IGNORE_INSERTS, 00038 NULL, 00039 err, 00040 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 00041 (LPTSTR) & lpMsgBuf, 0, NULL) == 0) 00042 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 00043 FORMAT_MESSAGE_FROM_SYSTEM | 00044 FORMAT_MESSAGE_IGNORE_INSERTS, 00045 NULL, 00046 err, 00047 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 00048 (LPTSTR) & lpMsgBuf, 0, NULL); 00049 rb_bug("%s: %s", func, (char*)lpMsgBuf); 00050 } 00051 00052 static int 00053 w32_mutex_lock(HANDLE lock) 00054 { 00055 DWORD result; 00056 while (1) { 00057 thread_debug("native_mutex_lock: %p\n", lock); 00058 result = w32_wait_events(&lock, 1, INFINITE, 0); 00059 switch (result) { 00060 case WAIT_OBJECT_0: 00061 /* get mutex object */ 00062 thread_debug("acquire mutex: %p\n", lock); 00063 return 0; 00064 case WAIT_OBJECT_0 + 1: 00065 /* interrupt */ 00066 errno = EINTR; 00067 thread_debug("acquire mutex interrupted: %p\n", lock); 00068 return 0; 00069 case WAIT_TIMEOUT: 00070 thread_debug("timeout mutex: %p\n", lock); 00071 break; 00072 case WAIT_ABANDONED: 00073 rb_bug("win32_mutex_lock: WAIT_ABANDONED"); 00074 break; 00075 default: 00076 rb_bug("win32_mutex_lock: unknown result (%ld)", result); 00077 break; 00078 } 00079 } 00080 return 0; 00081 } 00082 00083 static HANDLE 00084 w32_mutex_create(void) 00085 { 00086 HANDLE lock = CreateMutex(NULL, FALSE, NULL); 00087 if (lock == NULL) { 00088 w32_error("native_mutex_initialize"); 00089 } 00090 return lock; 00091 } 00092 00093 #define GVL_DEBUG 0 00094 00095 static void 00096 gvl_acquire(rb_vm_t *vm, rb_thread_t *th) 00097 { 00098 w32_mutex_lock(vm->gvl.lock); 00099 if (GVL_DEBUG) fprintf(stderr, "gvl acquire (%p): acquire\n", th); 00100 } 00101 00102 static void 00103 gvl_release(rb_vm_t *vm) 00104 { 00105 ReleaseMutex(vm->gvl.lock); 00106 } 00107 00108 static void 00109 gvl_yield(rb_vm_t *vm, rb_thread_t *th) 00110 { 00111 gvl_release(th->vm); 00112 native_thread_yield(); 00113 gvl_acquire(vm, th); 00114 } 00115 00116 00117 static void 00118 gvl_atfork(rb_vm_t *vm) 00119 { 00120 rb_bug("gvl_atfork() is called on win32"); 00121 } 00122 00123 static void 00124 gvl_init(rb_vm_t *vm) 00125 { 00126 if (GVL_DEBUG) fprintf(stderr, "gvl init\n"); 00127 vm->gvl.lock = w32_mutex_create(); 00128 } 00129 00130 static void 00131 gvl_destroy(rb_vm_t *vm) 00132 { 00133 if (GVL_DEBUG) fprintf(stderr, "gvl destroy\n"); 00134 CloseHandle(vm->gvl.lock); 00135 } 00136 00137 static rb_thread_t * 00138 ruby_thread_from_native(void) 00139 { 00140 return TlsGetValue(ruby_native_thread_key); 00141 } 00142 00143 static int 00144 ruby_thread_set_native(rb_thread_t *th) 00145 { 00146 return TlsSetValue(ruby_native_thread_key, th); 00147 } 00148 00149 void 00150 Init_native_thread(void) 00151 { 00152 rb_thread_t *th = GET_THREAD(); 00153 00154 ruby_native_thread_key = TlsAlloc(); 00155 ruby_thread_set_native(th); 00156 DuplicateHandle(GetCurrentProcess(), 00157 GetCurrentThread(), 00158 GetCurrentProcess(), 00159 &th->thread_id, 0, FALSE, DUPLICATE_SAME_ACCESS); 00160 00161 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0); 00162 00163 thread_debug("initial thread (th: %p, thid: %p, event: %p)\n", 00164 th, GET_THREAD()->thread_id, 00165 th->native_thread_data.interrupt_event); 00166 } 00167 00168 static void 00169 w32_set_event(HANDLE handle) 00170 { 00171 if (SetEvent(handle) == 0) { 00172 w32_error("w32_set_event"); 00173 } 00174 } 00175 00176 static void 00177 w32_reset_event(HANDLE handle) 00178 { 00179 if (ResetEvent(handle) == 0) { 00180 w32_error("w32_reset_event"); 00181 } 00182 } 00183 00184 static int 00185 w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th) 00186 { 00187 HANDLE *targets = events; 00188 HANDLE intr; 00189 DWORD ret; 00190 00191 thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n", 00192 events, count, timeout, th); 00193 if (th && (intr = th->native_thread_data.interrupt_event)) { 00194 gvl_acquire(th->vm, th); 00195 if (intr == th->native_thread_data.interrupt_event) { 00196 w32_reset_event(intr); 00197 if (RUBY_VM_INTERRUPTED(th)) { 00198 w32_set_event(intr); 00199 } 00200 00201 targets = ALLOCA_N(HANDLE, count + 1); 00202 memcpy(targets, events, sizeof(HANDLE) * count); 00203 00204 targets[count++] = intr; 00205 thread_debug(" * handle: %p (count: %d, intr)\n", intr, count); 00206 } 00207 gvl_release(th->vm); 00208 } 00209 00210 thread_debug(" WaitForMultipleObjects start (count: %d)\n", count); 00211 ret = WaitForMultipleObjects(count, targets, FALSE, timeout); 00212 thread_debug(" WaitForMultipleObjects end (ret: %lu)\n", ret); 00213 00214 if (ret == (DWORD)(WAIT_OBJECT_0 + count - 1) && th) { 00215 errno = EINTR; 00216 } 00217 if (ret == WAIT_FAILED && THREAD_DEBUG) { 00218 int i; 00219 DWORD dmy; 00220 for (i = 0; i < count; i++) { 00221 thread_debug(" * error handle %d - %s\n", i, 00222 GetHandleInformation(targets[i], &dmy) ? "OK" : "NG"); 00223 } 00224 } 00225 return ret; 00226 } 00227 00228 static void ubf_handle(void *ptr); 00229 #define ubf_select ubf_handle 00230 00231 int 00232 rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout) 00233 { 00234 return w32_wait_events(events, num, timeout, ruby_thread_from_native()); 00235 } 00236 00237 int 00238 rb_w32_wait_events(HANDLE *events, int num, DWORD timeout) 00239 { 00240 int ret; 00241 00242 BLOCKING_REGION(ret = rb_w32_wait_events_blocking(events, num, timeout), 00243 ubf_handle, ruby_thread_from_native(), FALSE); 00244 return ret; 00245 } 00246 00247 static void 00248 w32_close_handle(HANDLE handle) 00249 { 00250 if (CloseHandle(handle) == 0) { 00251 w32_error("w32_close_handle"); 00252 } 00253 } 00254 00255 static void 00256 w32_resume_thread(HANDLE handle) 00257 { 00258 if (ResumeThread(handle) == (DWORD)-1) { 00259 w32_error("w32_resume_thread"); 00260 } 00261 } 00262 00263 #ifdef _MSC_VER 00264 #define HAVE__BEGINTHREADEX 1 00265 #else 00266 #undef HAVE__BEGINTHREADEX 00267 #endif 00268 00269 #ifdef HAVE__BEGINTHREADEX 00270 #define start_thread (HANDLE)_beginthreadex 00271 #define thread_errno errno 00272 typedef unsigned long (_stdcall *w32_thread_start_func)(void*); 00273 #else 00274 #define start_thread CreateThread 00275 #define thread_errno rb_w32_map_errno(GetLastError()) 00276 typedef LPTHREAD_START_ROUTINE w32_thread_start_func; 00277 #endif 00278 00279 static HANDLE 00280 w32_create_thread(DWORD stack_size, w32_thread_start_func func, void *val) 00281 { 00282 return start_thread(0, stack_size, func, val, CREATE_SUSPENDED, 0); 00283 } 00284 00285 int 00286 rb_w32_sleep(unsigned long msec) 00287 { 00288 return w32_wait_events(0, 0, msec, ruby_thread_from_native()); 00289 } 00290 00291 int WINAPI 00292 rb_w32_Sleep(unsigned long msec) 00293 { 00294 int ret; 00295 00296 BLOCKING_REGION(ret = rb_w32_sleep(msec), 00297 ubf_handle, ruby_thread_from_native(), FALSE); 00298 return ret; 00299 } 00300 00301 static void 00302 native_sleep(rb_thread_t *th, struct timeval *tv) 00303 { 00304 DWORD msec; 00305 00306 if (tv) { 00307 msec = tv->tv_sec * 1000 + tv->tv_usec / 1000; 00308 } 00309 else { 00310 msec = INFINITE; 00311 } 00312 00313 GVL_UNLOCK_BEGIN(); 00314 { 00315 DWORD ret; 00316 00317 native_mutex_lock(&th->interrupt_lock); 00318 th->unblock.func = ubf_handle; 00319 th->unblock.arg = th; 00320 native_mutex_unlock(&th->interrupt_lock); 00321 00322 if (RUBY_VM_INTERRUPTED(th)) { 00323 /* interrupted. return immediate */ 00324 } 00325 else { 00326 thread_debug("native_sleep start (%lu)\n", msec); 00327 ret = w32_wait_events(0, 0, msec, th); 00328 thread_debug("native_sleep done (%lu)\n", ret); 00329 } 00330 00331 native_mutex_lock(&th->interrupt_lock); 00332 th->unblock.func = 0; 00333 th->unblock.arg = 0; 00334 native_mutex_unlock(&th->interrupt_lock); 00335 } 00336 GVL_UNLOCK_END(); 00337 } 00338 00339 static int 00340 native_mutex_lock(rb_thread_lock_t *lock) 00341 { 00342 #if USE_WIN32_MUTEX 00343 w32_mutex_lock(lock->mutex); 00344 #else 00345 EnterCriticalSection(&lock->crit); 00346 #endif 00347 return 0; 00348 } 00349 00350 static int 00351 native_mutex_unlock(rb_thread_lock_t *lock) 00352 { 00353 #if USE_WIN32_MUTEX 00354 thread_debug("release mutex: %p\n", lock->mutex); 00355 return ReleaseMutex(lock->mutex); 00356 #else 00357 LeaveCriticalSection(&lock->crit); 00358 return 0; 00359 #endif 00360 } 00361 00362 static int 00363 native_mutex_trylock(rb_thread_lock_t *lock) 00364 { 00365 #if USE_WIN32_MUTEX 00366 int result; 00367 thread_debug("native_mutex_trylock: %p\n", lock->mutex); 00368 result = w32_wait_events(&lock->mutex, 1, 1, 0); 00369 thread_debug("native_mutex_trylock result: %d\n", result); 00370 switch (result) { 00371 case WAIT_OBJECT_0: 00372 return 0; 00373 case WAIT_TIMEOUT: 00374 return EBUSY; 00375 } 00376 return EINVAL; 00377 #else 00378 return TryEnterCriticalSection(&lock->crit) == 0; 00379 #endif 00380 } 00381 00382 static void 00383 native_mutex_initialize(rb_thread_lock_t *lock) 00384 { 00385 #if USE_WIN32_MUTEX 00386 lock->mutex = w32_mutex_create(); 00387 /* thread_debug("initialize mutex: %p\n", lock->mutex); */ 00388 #else 00389 InitializeCriticalSection(&lock->crit); 00390 #endif 00391 } 00392 00393 static void 00394 native_mutex_destroy(rb_thread_lock_t *lock) 00395 { 00396 #if USE_WIN32_MUTEX 00397 w32_close_handle(lock->mutex); 00398 #else 00399 DeleteCriticalSection(&lock->crit); 00400 #endif 00401 } 00402 00403 struct cond_event_entry { 00404 struct cond_event_entry* next; 00405 struct cond_event_entry* prev; 00406 HANDLE event; 00407 }; 00408 00409 static void 00410 native_cond_signal(rb_thread_cond_t *cond) 00411 { 00412 /* cond is guarded by mutex */ 00413 struct cond_event_entry *e = cond->next; 00414 struct cond_event_entry *head = (struct cond_event_entry*)cond; 00415 00416 if (e != head) { 00417 struct cond_event_entry *next = e->next; 00418 struct cond_event_entry *prev = e->prev; 00419 00420 prev->next = next; 00421 next->prev = prev; 00422 e->next = e->prev = e; 00423 00424 SetEvent(e->event); 00425 } 00426 } 00427 00428 static void 00429 native_cond_broadcast(rb_thread_cond_t *cond) 00430 { 00431 /* cond is guarded by mutex */ 00432 struct cond_event_entry *e = cond->next; 00433 struct cond_event_entry *head = (struct cond_event_entry*)cond; 00434 00435 while (e != head) { 00436 struct cond_event_entry *next = e->next; 00437 struct cond_event_entry *prev = e->prev; 00438 00439 SetEvent(e->event); 00440 00441 prev->next = next; 00442 next->prev = prev; 00443 e->next = e->prev = e; 00444 00445 e = next; 00446 } 00447 } 00448 00449 00450 static int 00451 native_cond_timedwait_ms(rb_thread_cond_t *cond, rb_thread_lock_t *mutex, unsigned long msec) 00452 { 00453 DWORD r; 00454 struct cond_event_entry entry; 00455 struct cond_event_entry *head = (struct cond_event_entry*)cond; 00456 00457 entry.event = CreateEvent(0, FALSE, FALSE, 0); 00458 00459 /* cond is guarded by mutex */ 00460 entry.next = head; 00461 entry.prev = head->prev; 00462 head->prev->next = &entry; 00463 head->prev = &entry; 00464 00465 native_mutex_unlock(mutex); 00466 { 00467 r = WaitForSingleObject(entry.event, msec); 00468 if ((r != WAIT_OBJECT_0) && (r != WAIT_TIMEOUT)) { 00469 rb_bug("native_cond_wait: WaitForSingleObject returns %lu", r); 00470 } 00471 } 00472 native_mutex_lock(mutex); 00473 00474 entry.prev->next = entry.next; 00475 entry.next->prev = entry.prev; 00476 00477 w32_close_handle(entry.event); 00478 return (r == WAIT_OBJECT_0) ? 0 : ETIMEDOUT; 00479 } 00480 00481 static int 00482 native_cond_wait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex) 00483 { 00484 return native_cond_timedwait_ms(cond, mutex, INFINITE); 00485 } 00486 00487 static unsigned long 00488 abs_timespec_to_timeout_ms(struct timespec *ts) 00489 { 00490 struct timeval tv; 00491 struct timeval now; 00492 00493 gettimeofday(&now, NULL); 00494 tv.tv_sec = ts->tv_sec; 00495 tv.tv_usec = ts->tv_nsec / 1000; 00496 00497 if (!rb_w32_time_subtract(&tv, &now)) 00498 return 0; 00499 00500 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 00501 } 00502 00503 static int 00504 native_cond_timedwait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex, struct timespec *ts) 00505 { 00506 unsigned long timeout_ms; 00507 00508 timeout_ms = abs_timespec_to_timeout_ms(ts); 00509 if (!timeout_ms) 00510 return ETIMEDOUT; 00511 00512 return native_cond_timedwait_ms(cond, mutex, timeout_ms); 00513 } 00514 00515 #if SIZEOF_TIME_T == SIZEOF_LONG 00516 typedef unsigned long unsigned_time_t; 00517 #elif SIZEOF_TIME_T == SIZEOF_INT 00518 typedef unsigned int unsigned_time_t; 00519 #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG 00520 typedef unsigned LONG_LONG unsigned_time_t; 00521 #else 00522 # error cannot find integer type which size is same as time_t. 00523 #endif 00524 00525 #define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0)) 00526 00527 static struct timespec 00528 native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel) 00529 { 00530 int ret; 00531 struct timeval tv; 00532 struct timespec timeout; 00533 struct timespec now; 00534 00535 ret = gettimeofday(&tv, 0); 00536 if (ret != 0) 00537 rb_sys_fail(0); 00538 now.tv_sec = tv.tv_sec; 00539 now.tv_nsec = tv.tv_usec * 1000; 00540 00541 timeout.tv_sec = now.tv_sec; 00542 timeout.tv_nsec = now.tv_nsec; 00543 timeout.tv_sec += timeout_rel.tv_sec; 00544 timeout.tv_nsec += timeout_rel.tv_nsec; 00545 00546 if (timeout.tv_nsec >= 1000*1000*1000) { 00547 timeout.tv_sec++; 00548 timeout.tv_nsec -= 1000*1000*1000; 00549 } 00550 00551 if (timeout.tv_sec < now.tv_sec) 00552 timeout.tv_sec = TIMET_MAX; 00553 00554 return timeout; 00555 } 00556 00557 static void 00558 native_cond_initialize(rb_thread_cond_t *cond, int flags) 00559 { 00560 cond->next = (struct cond_event_entry *)cond; 00561 cond->prev = (struct cond_event_entry *)cond; 00562 } 00563 00564 static void 00565 native_cond_destroy(rb_thread_cond_t *cond) 00566 { 00567 /* */ 00568 } 00569 00570 void 00571 ruby_init_stack(volatile VALUE *addr) 00572 { 00573 } 00574 00575 #define CHECK_ERR(expr) \ 00576 {if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}} 00577 00578 static void 00579 native_thread_init_stack(rb_thread_t *th) 00580 { 00581 MEMORY_BASIC_INFORMATION mi; 00582 char *base, *end; 00583 DWORD size, space; 00584 00585 CHECK_ERR(VirtualQuery(&mi, &mi, sizeof(mi))); 00586 base = mi.AllocationBase; 00587 end = mi.BaseAddress; 00588 end += mi.RegionSize; 00589 size = end - base; 00590 space = size / 5; 00591 if (space > 1024*1024) space = 1024*1024; 00592 th->machine_stack_start = (VALUE *)end - 1; 00593 th->machine_stack_maxsize = size - space; 00594 } 00595 00596 #ifndef InterlockedExchangePointer 00597 #define InterlockedExchangePointer(t, v) \ 00598 (void *)InterlockedExchange((long *)(t), (long)(v)) 00599 #endif 00600 static void 00601 native_thread_destroy(rb_thread_t *th) 00602 { 00603 HANDLE intr = InterlockedExchangePointer(&th->native_thread_data.interrupt_event, 0); 00604 thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id); 00605 w32_close_handle(intr); 00606 } 00607 00608 static unsigned long _stdcall 00609 thread_start_func_1(void *th_ptr) 00610 { 00611 rb_thread_t *th = th_ptr; 00612 volatile HANDLE thread_id = th->thread_id; 00613 00614 native_thread_init_stack(th); 00615 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0); 00616 00617 /* run */ 00618 thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th, 00619 th->thread_id, th->native_thread_data.interrupt_event); 00620 00621 thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp()); 00622 00623 w32_close_handle(thread_id); 00624 thread_debug("thread deleted (th: %p)\n", th); 00625 return 0; 00626 } 00627 00628 static int 00629 native_thread_create(rb_thread_t *th) 00630 { 00631 size_t stack_size = 4 * 1024; /* 4KB is the minimum commit size */ 00632 th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th); 00633 00634 if ((th->thread_id) == 0) { 00635 return thread_errno; 00636 } 00637 00638 w32_resume_thread(th->thread_id); 00639 00640 if (THREAD_DEBUG) { 00641 Sleep(0); 00642 thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %"PRIdSIZE"\n", 00643 th, th->thread_id, 00644 th->native_thread_data.interrupt_event, stack_size); 00645 } 00646 return 0; 00647 } 00648 00649 static void 00650 native_thread_join(HANDLE th) 00651 { 00652 w32_wait_events(&th, 1, INFINITE, 0); 00653 } 00654 00655 #if USE_NATIVE_THREAD_PRIORITY 00656 00657 static void 00658 native_thread_apply_priority(rb_thread_t *th) 00659 { 00660 int priority = th->priority; 00661 if (th->priority > 0) { 00662 priority = THREAD_PRIORITY_ABOVE_NORMAL; 00663 } 00664 else if (th->priority < 0) { 00665 priority = THREAD_PRIORITY_BELOW_NORMAL; 00666 } 00667 else { 00668 priority = THREAD_PRIORITY_NORMAL; 00669 } 00670 00671 SetThreadPriority(th->thread_id, priority); 00672 } 00673 00674 #endif /* USE_NATIVE_THREAD_PRIORITY */ 00675 00676 int rb_w32_select_with_thread(int, fd_set *, fd_set *, fd_set *, struct timeval *, void *); /* @internal */ 00677 00678 static int 00679 native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th) 00680 { 00681 fd_set *r = NULL, *w = NULL, *e = NULL; 00682 if (readfds) { 00683 rb_fd_resize(n - 1, readfds); 00684 r = rb_fd_ptr(readfds); 00685 } 00686 if (writefds) { 00687 rb_fd_resize(n - 1, writefds); 00688 w = rb_fd_ptr(writefds); 00689 } 00690 if (exceptfds) { 00691 rb_fd_resize(n - 1, exceptfds); 00692 e = rb_fd_ptr(exceptfds); 00693 } 00694 return rb_w32_select_with_thread(n, r, w, e, timeout, th); 00695 } 00696 00697 /* @internal */ 00698 int 00699 rb_w32_check_interrupt(rb_thread_t *th) 00700 { 00701 return w32_wait_events(0, 0, 0, th); 00702 } 00703 00704 static void 00705 ubf_handle(void *ptr) 00706 { 00707 rb_thread_t *th = (rb_thread_t *)ptr; 00708 thread_debug("ubf_handle: %p\n", th); 00709 00710 w32_set_event(th->native_thread_data.interrupt_event); 00711 } 00712 00713 static HANDLE timer_thread_id = 0; 00714 static HANDLE timer_thread_lock; 00715 00716 static unsigned long _stdcall 00717 timer_thread_func(void *dummy) 00718 { 00719 thread_debug("timer_thread\n"); 00720 while (WaitForSingleObject(timer_thread_lock, TIME_QUANTUM_USEC/1000) == 00721 WAIT_TIMEOUT) { 00722 timer_thread_function(dummy); 00723 } 00724 thread_debug("timer killed\n"); 00725 return 0; 00726 } 00727 00728 void 00729 rb_thread_wakeup_timer_thread(void) 00730 { 00731 /* do nothing */ 00732 } 00733 00734 static void 00735 rb_thread_create_timer_thread(void) 00736 { 00737 if (timer_thread_id == 0) { 00738 if (!timer_thread_lock) { 00739 timer_thread_lock = CreateEvent(0, TRUE, FALSE, 0); 00740 } 00741 timer_thread_id = w32_create_thread(1024 + (THREAD_DEBUG ? BUFSIZ : 0), 00742 timer_thread_func, 0); 00743 w32_resume_thread(timer_thread_id); 00744 } 00745 } 00746 00747 static int 00748 native_stop_timer_thread(int close_anyway) 00749 { 00750 int stopped = --system_working <= 0; 00751 if (stopped) { 00752 SetEvent(timer_thread_lock); 00753 native_thread_join(timer_thread_id); 00754 CloseHandle(timer_thread_lock); 00755 timer_thread_lock = 0; 00756 } 00757 return stopped; 00758 } 00759 00760 static void 00761 native_reset_timer_thread(void) 00762 { 00763 if (timer_thread_id) { 00764 CloseHandle(timer_thread_id); 00765 timer_thread_id = 0; 00766 } 00767 } 00768 00769 #ifdef RUBY_ALLOCA_CHKSTK 00770 void 00771 ruby_alloca_chkstk(size_t len, void *sp) 00772 { 00773 if (ruby_stack_length(NULL) * sizeof(VALUE) >= len) { 00774 rb_thread_t *th = GET_THREAD(); 00775 if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW)) { 00776 rb_thread_raised_set(th, RAISED_STACKOVERFLOW); 00777 rb_exc_raise(sysstack_error); 00778 } 00779 } 00780 } 00781 #endif 00782 int 00783 rb_reserved_fd_p(int fd) 00784 { 00785 return 0; 00786 } 00787 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */ 00788