|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* -*-c-*- */ 00002 /********************************************************************** 00003 00004 thread_win32.c - 00005 00006 $Author: mame $ 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 WIN32_WAIT_TIMEOUT 10 /* 10 ms */ 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 /* interrupted. return immediate */ 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 /* get mutex object */ 00262 thread_debug("acquire mutex: %p\n", *lock); 00263 return 0; 00264 case WAIT_OBJECT_0 + 1: 00265 /* interrupt */ 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 /* thread_debug("initialize mutex: %p\n", *lock); */ 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 /* cond is guarded by mutex */ 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 /* cond is guarded by mutex */ 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 /* cond is guarded by mutex */ 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 /* run */ 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; /* 4KB */ 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 /* USE_NATIVE_THREAD_PRIORITY */ 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 /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */ 00594
1.7.3