Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 682 lines (577 sloc) 14.826 kB
a3e1b1c @ko1 * Merge YARV
ko1 authored
1 /* -*-c-*- */
2 /**********************************************************************
3
c334a09 @ko1 * common.mk, *.ci: renamed to *.c.
ko1 authored
4 thread_win32.c -
a3e1b1c @ko1 * Merge YARV
ko1 authored
5
6 $Author$
7
d907cbc @ko1 * blockinlining.c, compile.c, compile.h, debug.c, debug.h,
ko1 authored
8 Copyright (C) 2004-2007 Koichi Sasada
a3e1b1c @ko1 * Merge YARV
ko1 authored
9
10 **********************************************************************/
11
12 #ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
13
14 #include <process.h>
15
16 #define WIN32_WAIT_TIMEOUT 10 /* 10 ms */
17 #undef Sleep
18
19 #define native_thread_yield() Sleep(0)
ae317b5 @ko1 * yarvcore.h, thread.c: fix to use pthread on cygwin.
ko1 authored
20 #define remove_signal_thread_list(th)
a3e1b1c @ko1 * Merge YARV
ko1 authored
21
6fc746d @nobu * thread.c (is_ruby_native_thread): check properly. [ruby-dev:31166]
nobu authored
22 static volatile DWORD ruby_native_thread_key = TLS_OUT_OF_INDEXES;
23
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
24 static void
25 w32_error(const char *func)
26 {
27 LPVOID lpMsgBuf;
28 DWORD err = GetLastError();
29 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
30 FORMAT_MESSAGE_FROM_SYSTEM |
31 FORMAT_MESSAGE_IGNORE_INSERTS,
32 NULL,
33 err,
34 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
35 (LPTSTR) & lpMsgBuf, 0, NULL) == 0)
36 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
37 FORMAT_MESSAGE_FROM_SYSTEM |
38 FORMAT_MESSAGE_IGNORE_INSERTS,
39 NULL,
40 err,
41 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
42 (LPTSTR) & lpMsgBuf, 0, NULL);
43 rb_bug("%s: %s", func, (char*)lpMsgBuf);
44 }
45
46 static int
47 w32_mutex_lock(HANDLE lock)
48 {
49 DWORD result;
50 while (1) {
51 thread_debug("native_mutex_lock: %p\n", lock);
52 result = w32_wait_events(&lock, 1, INFINITE, 0);
53 switch (result) {
54 case WAIT_OBJECT_0:
55 /* get mutex object */
56 thread_debug("acquire mutex: %p\n", lock);
57 return 0;
58 case WAIT_OBJECT_0 + 1:
59 /* interrupt */
60 errno = EINTR;
61 thread_debug("acquire mutex interrupted: %p\n", lock);
62 return 0;
63 case WAIT_TIMEOUT:
64 thread_debug("timeout mutex: %p\n", lock);
65 break;
66 case WAIT_ABANDONED:
67 rb_bug("win32_mutex_lock: WAIT_ABANDONED");
68 break;
69 default:
f0445d1 @nobu * thread_win32.c (gvl_release, gvl_init): suppress warnings.
nobu authored
70 rb_bug("win32_mutex_lock: unknown result (%ld)", result);
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
71 break;
72 }
73 }
74 return 0;
75 }
76
77 static HANDLE
78 w32_mutex_create(void)
79 {
80 HANDLE lock = CreateMutex(NULL, FALSE, NULL);
81 if (lock == NULL) {
82 w32_error("native_mutex_initialize");
83 }
84 return lock;
85 }
86
87 #define GVL_DEBUG 0
88
89 static void
90 gvl_acquire(rb_vm_t *vm, rb_thread_t *th)
91 {
92 w32_mutex_lock(vm->gvl.lock);
93 if (GVL_DEBUG) fprintf(stderr, "gvl acquire (%p): acquire\n", th);
94 }
95
96 static void
97 gvl_release(rb_vm_t *vm)
98 {
99 ReleaseMutex(vm->gvl.lock);
100 }
101
102 static void
103 gvl_atfork(rb_vm_t *vm)
104 {
105 rb_bug("gvl_atfork() is called on win32");
106 }
107
108 static void
109 gvl_init(rb_vm_t *vm)
110 {
111 if (GVL_DEBUG) fprintf(stderr, "gvl init\n");
112 vm->gvl.lock = w32_mutex_create();
113 }
114
115 static void
116 gvl_destroy(rb_vm_t *vm)
117 {
118 if (GVL_DEBUG) fprintf(stderr, "gvl destroy\n");
119 CloseHandle(vm->gvl.lock);
120 }
121
6fc746d @nobu * thread.c (is_ruby_native_thread): check properly. [ruby-dev:31166]
nobu authored
122 static rb_thread_t *
123 ruby_thread_from_native(void)
124 {
125 return TlsGetValue(ruby_native_thread_key);
126 }
127
128 static int
129 ruby_thread_set_native(rb_thread_t *th)
130 {
131 return TlsSetValue(ruby_native_thread_key, th);
132 }
133
f40d2c9 @akr * vm.c (Init_BareVM): call Init_native_thread here.
akr authored
134 void
6fc746d @nobu * thread.c (is_ruby_native_thread): check properly. [ruby-dev:31166]
nobu authored
135 Init_native_thread(void)
a3e1b1c @ko1 * Merge YARV
ko1 authored
136 {
9c57438 @ko1 * blockinlining.c, error.c, eval.c, eval_error.h, eval_intern.h,
ko1 authored
137 rb_thread_t *th = GET_THREAD();
6fc746d @nobu * thread.c (is_ruby_native_thread): check properly. [ruby-dev:31166]
nobu authored
138
139 ruby_native_thread_key = TlsAlloc();
b451955 @unak * thread_win32.c (Init_native_thread): need to call
unak authored
140 ruby_thread_set_native(th);
a3e1b1c @ko1 * Merge YARV
ko1 authored
141 DuplicateHandle(GetCurrentProcess(),
142 GetCurrentThread(),
143 GetCurrentProcess(),
144 &th->thread_id, 0, FALSE, DUPLICATE_SAME_ACCESS);
145
146 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
147
148 thread_debug("initial thread (th: %p, thid: %p, event: %p)\n",
149 th, GET_THREAD()->thread_id,
150 th->native_thread_data.interrupt_event);
151 }
152
153 static void
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
154 w32_set_event(HANDLE handle)
155 {
156 if (SetEvent(handle) == 0) {
5bc85d6 @unak * thread_win32.c (w32_error): should report the function.
unak authored
157 w32_error("w32_set_event");
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
158 }
159 }
160
161 static void
162 w32_reset_event(HANDLE handle)
163 {
164 if (ResetEvent(handle) == 0) {
5bc85d6 @unak * thread_win32.c (w32_error): should report the function.
unak authored
165 w32_error("w32_reset_event");
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
166 }
a3e1b1c @ko1 * Merge YARV
ko1 authored
167 }
168
169 static int
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
170 w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
a3e1b1c @ko1 * Merge YARV
ko1 authored
171 {
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
172 HANDLE *targets = events;
00f60d0 @unak * thread_win32.ci (w32_wait_events): check whether interrupt_event is
unak authored
173 HANDLE intr;
a3e1b1c @ko1 * Merge YARV
ko1 authored
174 DWORD ret;
175
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
176 thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n",
177 events, count, timeout, th);
00f60d0 @unak * thread_win32.ci (w32_wait_events): check whether interrupt_event is
unak authored
178 if (th && (intr = th->native_thread_data.interrupt_event)) {
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
179 gvl_acquire(th->vm, th);
bd21118 @wanabe * thread_win32.c (w32_wait_events): get GVL before handle interrupt
wanabe authored
180 if (intr == th->native_thread_data.interrupt_event) {
181 w32_reset_event(intr);
182 if (RUBY_VM_INTERRUPTED(th)) {
183 w32_set_event(intr);
184 }
185
186 targets = ALLOCA_N(HANDLE, count + 1);
187 memcpy(targets, events, sizeof(HANDLE) * count);
188
189 targets[count++] = intr;
190 thread_debug(" * handle: %p (count: %d, intr)\n", intr, count);
a3e1b1c @ko1 * Merge YARV
ko1 authored
191 }
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
192 gvl_release(th->vm);
a3e1b1c @ko1 * Merge YARV
ko1 authored
193 }
194
195 thread_debug(" WaitForMultipleObjects start (count: %d)\n", count);
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
196 ret = WaitForMultipleObjects(count, targets, FALSE, timeout);
87e4ad0 @nobu * io.c, signal.c, thread.c, thread_win32.c, include/ruby/intern.h:
nobu authored
197 thread_debug(" WaitForMultipleObjects end (ret: %lu)\n", ret);
a3e1b1c @ko1 * Merge YARV
ko1 authored
198
060f18c @wanabe * thread_win32.c (w32_wait_events, w32_close_handle): suppress warnings.
wanabe authored
199 if (ret == (DWORD)(WAIT_OBJECT_0 + count - 1) && th) {
a3e1b1c @ko1 * Merge YARV
ko1 authored
200 errno = EINTR;
201 }
060f18c @wanabe * thread_win32.c (w32_wait_events, w32_close_handle): suppress warnings.
wanabe authored
202 if (ret == WAIT_FAILED && THREAD_DEBUG) {
a3e1b1c @ko1 * Merge YARV
ko1 authored
203 int i;
204 DWORD dmy;
205 for (i = 0; i < count; i++) {
206 thread_debug(" * error handle %d - %s\n", i,
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
207 GetHandleInformation(targets[i], &dmy) ? "OK" : "NG");
a3e1b1c @ko1 * Merge YARV
ko1 authored
208 }
209 }
210 return ret;
211 }
212
3453b2b @ko1 * gc.h, vm_core.h: decl of rb_gc_save_machine_context()
ko1 authored
213 static void ubf_handle(void *ptr);
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
214 #define ubf_select ubf_handle
215
216 int
c034fce @nobu * process.c (rb_waitpid_blocking, rb_waitpid): use UBF feature.
nobu authored
217 rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
218 {
219 return w32_wait_events(events, num, timeout, GET_THREAD());
220 }
221
222 int
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
223 rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
224 {
225 int ret;
226
3453b2b @ko1 * gc.h, vm_core.h: decl of rb_gc_save_machine_context()
ko1 authored
227 BLOCKING_REGION(ret = rb_w32_wait_events_blocking(events, num, timeout),
4b645dc @mame * thread.c, thread_win32.c, vm_core.h: try to remove false positive of
mame authored
228 ubf_handle, GET_THREAD());
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
229 return ret;
230 }
231
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
232 static void
233 w32_close_handle(HANDLE handle)
234 {
235 if (CloseHandle(handle) == 0) {
5bc85d6 @unak * thread_win32.c (w32_error): should report the function.
unak authored
236 w32_error("w32_close_handle");
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
237 }
238 }
239
240 static void
241 w32_resume_thread(HANDLE handle)
242 {
060f18c @wanabe * thread_win32.c (w32_wait_events, w32_close_handle): suppress warnings.
wanabe authored
243 if (ResumeThread(handle) == (DWORD)-1) {
5bc85d6 @unak * thread_win32.c (w32_error): should report the function.
unak authored
244 w32_error("w32_resume_thread");
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
245 }
246 }
247
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
248 #ifdef _MSC_VER
249 #define HAVE__BEGINTHREADEX 1
250 #else
251 #undef HAVE__BEGINTHREADEX
252 #endif
253
254 #ifdef HAVE__BEGINTHREADEX
255 #define start_thread (HANDLE)_beginthreadex
9e0f3e0 @nobu * thread_win32.c (thread_errno): CreateThread does not set errno.
nobu authored
256 #define thread_errno errno
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
257 typedef unsigned long (_stdcall *w32_thread_start_func)(void*);
258 #else
259 #define start_thread CreateThread
9e0f3e0 @nobu * thread_win32.c (thread_errno): CreateThread does not set errno.
nobu authored
260 #define thread_errno rb_w32_map_errno(GetLastError())
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
261 typedef LPTHREAD_START_ROUTINE w32_thread_start_func;
262 #endif
263
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
264 static HANDLE
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
265 w32_create_thread(DWORD stack_size, w32_thread_start_func func, void *val)
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
266 {
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
267 return start_thread(0, stack_size, func, val, CREATE_SUSPENDED, 0);
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
268 }
269
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
270 int
271 rb_w32_sleep(unsigned long msec)
272 {
273 return w32_wait_events(0, 0, msec, GET_THREAD());
274 }
275
276 int WINAPI
277 rb_w32_Sleep(unsigned long msec)
278 {
279 int ret;
280
3453b2b @ko1 * gc.h, vm_core.h: decl of rb_gc_save_machine_context()
ko1 authored
281 BLOCKING_REGION(ret = rb_w32_sleep(msec),
4b645dc @mame * thread.c, thread_win32.c, vm_core.h: try to remove false positive of
mame authored
282 ubf_handle, GET_THREAD());
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
283 return ret;
284 }
ae317b5 @ko1 * yarvcore.h, thread.c: fix to use pthread on cygwin.
ko1 authored
285
a3e1b1c @ko1 * Merge YARV
ko1 authored
286 static void
47e3f4e @nobu * thread.c (thread_start_func_2): wake up joining threads.
nobu authored
287 native_sleep(rb_thread_t *th, struct timeval *tv)
a3e1b1c @ko1 * Merge YARV
ko1 authored
288 {
a146829 @nobu * thread.c (sleep_forever): wait until timed out. [ruby-core:17270]
nobu authored
289 DWORD msec;
4b02286 @unak * thread_win32.c (native_sleep): fixed previous commit.
unak authored
290
a3e1b1c @ko1 * Merge YARV
ko1 authored
291 if (tv) {
292 msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
293 }
294 else {
295 msec = INFINITE;
296 }
297
298 GVL_UNLOCK_BEGIN();
299 {
a146829 @nobu * thread.c (sleep_forever): wait until timed out. [ruby-core:17270]
nobu authored
300 DWORD ret;
301
8724448 @unak * thread_win32.c (native_sleep): must block reentrance when accessing
unak authored
302 native_mutex_lock(&th->interrupt_lock);
1b63d7b @nobu * vm_core.h (struct rb_unblock_callback), thread.c
nobu authored
303 th->unblock.func = ubf_handle;
304 th->unblock.arg = th;
8724448 @unak * thread_win32.c (native_sleep): must block reentrance when accessing
unak authored
305 native_mutex_unlock(&th->interrupt_lock);
5f0b8af @ko1 * vm_core.h, thread.c, cont.c: add RUBY_VM_SET_INTERRUPT(),
ko1 authored
306
307 if (RUBY_VM_INTERRUPTED(th)) {
308 /* interrupted. return immediate */
309 }
310 else {
87e4ad0 @nobu * io.c, signal.c, thread.c, thread_win32.c, include/ruby/intern.h:
nobu authored
311 thread_debug("native_sleep start (%lu)\n", msec);
5f0b8af @ko1 * vm_core.h, thread.c, cont.c: add RUBY_VM_SET_INTERRUPT(),
ko1 authored
312 ret = w32_wait_events(0, 0, msec, th);
87e4ad0 @nobu * io.c, signal.c, thread.c, thread_win32.c, include/ruby/intern.h:
nobu authored
313 thread_debug("native_sleep done (%lu)\n", ret);
5f0b8af @ko1 * vm_core.h, thread.c, cont.c: add RUBY_VM_SET_INTERRUPT(),
ko1 authored
314 }
315
8724448 @unak * thread_win32.c (native_sleep): must block reentrance when accessing
unak authored
316 native_mutex_lock(&th->interrupt_lock);
1b63d7b @nobu * vm_core.h (struct rb_unblock_callback), thread.c
nobu authored
317 th->unblock.func = 0;
318 th->unblock.arg = 0;
8724448 @unak * thread_win32.c (native_sleep): must block reentrance when accessing
unak authored
319 native_mutex_unlock(&th->interrupt_lock);
a3e1b1c @ko1 * Merge YARV
ko1 authored
320 }
321 GVL_UNLOCK_END();
322 }
323
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
324 static int
8ee7d07 @ko1 * blockinlining.c, compile.c, compile.h, error.c, eval.c,
ko1 authored
325 native_mutex_lock(rb_thread_lock_t *lock)
a3e1b1c @ko1 * Merge YARV
ko1 authored
326 {
327 #if USE_WIN32_MUTEX
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
328 w32_mutex_lock(*lock);
a3e1b1c @ko1 * Merge YARV
ko1 authored
329 #else
330 EnterCriticalSection(lock);
331 return 0;
332 #endif
333 }
334
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
335 static int
8ee7d07 @ko1 * blockinlining.c, compile.c, compile.h, error.c, eval.c,
ko1 authored
336 native_mutex_unlock(rb_thread_lock_t *lock)
a3e1b1c @ko1 * Merge YARV
ko1 authored
337 {
338 #if USE_WIN32_MUTEX
339 thread_debug("release mutex: %p\n", *lock);
340 return ReleaseMutex(*lock);
341 #else
342 LeaveCriticalSection(lock);
343 return 0;
344 #endif
345 }
346
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
347 static int
8ee7d07 @ko1 * blockinlining.c, compile.c, compile.h, error.c, eval.c,
ko1 authored
348 native_mutex_trylock(rb_thread_lock_t *lock)
a3e1b1c @ko1 * Merge YARV
ko1 authored
349 {
35eb542 @nobu * thread_win32.ci: fixed typo.
nobu authored
350 #if USE_WIN32_MUTEX
a3e1b1c @ko1 * Merge YARV
ko1 authored
351 int result;
352 thread_debug("native_mutex_trylock: %p\n", *lock);
bb022be @unak * thread.c (rb_thread_polling): check interrupts here.
unak authored
353 result = w32_wait_events(&*lock, 1, 1, 0);
a3e1b1c @ko1 * Merge YARV
ko1 authored
354 thread_debug("native_mutex_trylock result: %d\n", result);
355 switch (result) {
99d65b1 @nobu * compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
nobu authored
356 case WAIT_OBJECT_0:
a3e1b1c @ko1 * Merge YARV
ko1 authored
357 return 0;
99d65b1 @nobu * compile.c, dir.c, eval.c, eval_jump.h, eval_method.h, numeric.c,
nobu authored
358 case WAIT_TIMEOUT:
a3e1b1c @ko1 * Merge YARV
ko1 authored
359 return EBUSY;
360 }
361 return EINVAL;
362 #else
363 return TryEnterCriticalSection(lock) == 0;
364 #endif
365 }
366
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
367 static void
8ee7d07 @ko1 * blockinlining.c, compile.c, compile.h, error.c, eval.c,
ko1 authored
368 native_mutex_initialize(rb_thread_lock_t *lock)
a3e1b1c @ko1 * Merge YARV
ko1 authored
369 {
35eb542 @nobu * thread_win32.ci: fixed typo.
nobu authored
370 #if USE_WIN32_MUTEX
450463d @ko1 * thread.c, vm_core.h: make gvl_acquire/release/init/destruct
ko1 authored
371 *lock = w32_mutex_create();
205f310 @nobu * call_cfunc.ci, compile.c, compile.h, debug.h, eval.c,
nobu authored
372 /* thread_debug("initialize mutex: %p\n", *lock); */
a3e1b1c @ko1 * Merge YARV
ko1 authored
373 #else
374 InitializeCriticalSection(lock);
375 #endif
376 }
377
a000201 @nobu * thread.c (rb_thread_atfork_internal): reinitialize global lock
nobu authored
378 #define native_mutex_reinitialize_atfork(lock) (void)(lock)
379
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
380 static void
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
381 native_mutex_destroy(rb_thread_lock_t *lock)
382 {
35eb542 @nobu * thread_win32.ci: fixed typo.
nobu authored
383 #if USE_WIN32_MUTEX
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
384 w32_close_handle(lock);
385 #else
386 DeleteCriticalSection(lock);
387 #endif
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
388 }
389
a73ba1d @unak * thread_win32.[ch] (cond_every_entry, rb_thread_cond_struct): reverted
unak authored
390 struct cond_event_entry {
391 struct cond_event_entry* next;
392 HANDLE event;
393 };
394
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
395 static void
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
396 native_cond_signal(rb_thread_cond_t *cond)
397 {
398 /* cond is guarded by mutex */
399 struct cond_event_entry *e = cond->next;
400
401 if (e) {
402 cond->next = e->next;
403 SetEvent(e->event);
404 }
405 else {
406 rb_bug("native_cond_signal: no pending threads");
407 }
408 }
409
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
410 static void
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
411 native_cond_broadcast(rb_thread_cond_t *cond)
412 {
413 /* cond is guarded by mutex */
414 struct cond_event_entry *e = cond->next;
415 cond->next = 0;
416
417 while (e) {
418 SetEvent(e->event);
419 e = e->next;
420 }
421 }
422
b4c5fad @kosaki * thread_win32.c (native_cond_timedwait): New. r31373 caused
kosaki authored
423
424 static int
425 __cond_timedwait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex, unsigned long msec)
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
426 {
427 DWORD r;
428 struct cond_event_entry entry;
429
430 entry.next = 0;
431 entry.event = CreateEvent(0, FALSE, FALSE, 0);
432
433 /* cond is guarded by mutex */
434 if (cond->next) {
435 cond->last->next = &entry;
436 cond->last = &entry;
437 }
438 else {
439 cond->next = &entry;
440 cond->last = &entry;
441 }
442
443 native_mutex_unlock(mutex);
444 {
b4c5fad @kosaki * thread_win32.c (native_cond_timedwait): New. r31373 caused
kosaki authored
445 r = WaitForSingleObject(entry.event, msec);
446 if ((r != WAIT_OBJECT_0) && (r != WAIT_TIMEOUT)) {
87e4ad0 @nobu * io.c, signal.c, thread.c, thread_win32.c, include/ruby/intern.h:
nobu authored
447 rb_bug("native_cond_wait: WaitForSingleObject returns %lu", r);
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
448 }
449 }
450 native_mutex_lock(mutex);
451
452 w32_close_handle(entry.event);
b4c5fad @kosaki * thread_win32.c (native_cond_timedwait): New. r31373 caused
kosaki authored
453 return (r == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
454 }
455
456 static int
457 native_cond_wait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex)
458 {
459 return __cond_timedwait(cond, mutex, INFINITE);
460 }
461
462 static unsigned long
463 abs_timespec_to_timeout_ms(struct timespec *ts)
464 {
465 struct timeval tv;
466 struct timeval now;
467
468 gettimeofday(&now, NULL);
469 tv.tv_sec = ts->tv_sec;
470 tv.tv_usec = ts->tv_nsec;
471
472 if (!rb_w32_time_subtract(&tv, &now))
473 return 0;
474
475 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
476 }
477
478 static int
479 native_cond_timedwait(rb_thread_cond_t *cond, rb_thread_lock_t *mutex, struct timespec *ts)
480 {
481 unsigned long timeout_ms;
482
483 timeout_ms = abs_timespec_to_timeout_ms(ts);
484 if (!timeout_ms)
485 return ETIMEDOUT;
486
487 return __cond_timedwait(cond, mutex, timeout_ms);
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
488 }
489
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
490 static void
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
491 native_cond_initialize(rb_thread_cond_t *cond)
492 {
493 cond->next = 0;
494 cond->last = 0;
495 }
496
42f0b52 @ko1 * thread_pthread.c, thread_pthread.h, thread_win32.c,
ko1 authored
497 static void
6244e50 @ko1 * thread.c: fix Mutex to be interruptable lock.
ko1 authored
498 native_cond_destroy(rb_thread_cond_t *cond)
499 {
500 /* */
501 }
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
502
fc3c60f @nobu * gc.h (STACK_UPPER): moved from gc.c
nobu authored
503 void
c7853b4 @nobu * eval.c (ruby_cleanup): the order of local variables on stack is
nobu authored
504 ruby_init_stack(volatile VALUE *addr)
fc3c60f @nobu * gc.h (STACK_UPPER): moved from gc.c
nobu authored
505 {
506 }
507
508 #define CHECK_ERR(expr) \
509 {if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}}
510
511 static void
512 native_thread_init_stack(rb_thread_t *th)
513 {
514 MEMORY_BASIC_INFORMATION mi;
515 char *base, *end;
516 DWORD size, space;
517
518 CHECK_ERR(VirtualQuery(&mi, &mi, sizeof(mi)));
519 base = mi.AllocationBase;
520 end = mi.BaseAddress;
521 end += mi.RegionSize;
522 size = end - base;
523 space = size / 5;
524 if (space > 1024*1024) space = 1024*1024;
525 th->machine_stack_start = (VALUE *)end - 1;
526 th->machine_stack_maxsize = size - space;
527 }
528
dfc07e8 @unak * thread_win32.c (InterlockedExchangePointer): old SDK support.
unak authored
529 #ifndef InterlockedExchangePointer
530 #define InterlockedExchangePointer(t, v) \
531 (void *)InterlockedExchange((long *)(t), (long)(v))
532 #endif
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
533 static void
534 native_thread_destroy(rb_thread_t *th)
535 {
9f90682 @unak * thread_win32.c (native_thread_destroy): decreased the probability of
unak authored
536 HANDLE intr = InterlockedExchangePointer(&th->native_thread_data.interrupt_event, 0);
00f60d0 @unak * thread_win32.ci (w32_wait_events): check whether interrupt_event is
unak authored
537 thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id);
538 w32_close_handle(intr);
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
539 }
a3e1b1c @ko1 * Merge YARV
ko1 authored
540
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
541 static unsigned long _stdcall
a3e1b1c @ko1 * Merge YARV
ko1 authored
542 thread_start_func_1(void *th_ptr)
543 {
9c57438 @ko1 * blockinlining.c, error.c, eval.c, eval_error.h, eval_intern.h,
ko1 authored
544 rb_thread_t *th = th_ptr;
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
545 volatile HANDLE thread_id = th->thread_id;
546
fc3c60f @nobu * gc.h (STACK_UPPER): moved from gc.c
nobu authored
547 native_thread_init_stack(th);
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
548 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
a3e1b1c @ko1 * Merge YARV
ko1 authored
549
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
550 /* run */
a3e1b1c @ko1 * Merge YARV
ko1 authored
551 thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th,
552 th->thread_id, th->native_thread_data.interrupt_event);
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
553
df6ea23 @nobu * thread_win32.c (thread_start_func_1): use already gotten stack info.
nobu authored
554 thread_start_func_2(th, th->machine_stack_start, rb_ia64_bsp());
a3e1b1c @ko1 * Merge YARV
ko1 authored
555
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
556 w32_close_handle(thread_id);
a3e1b1c @ko1 * Merge YARV
ko1 authored
557 thread_debug("thread deleted (th: %p)\n", th);
558 return 0;
559 }
560
561 static int
9c57438 @ko1 * blockinlining.c, error.c, eval.c, eval_error.h, eval_intern.h,
ko1 authored
562 native_thread_create(rb_thread_t *th)
a3e1b1c @ko1 * Merge YARV
ko1 authored
563 {
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
564 size_t stack_size = 4 * 1024; /* 4KB */
565 th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th);
a3e1b1c @ko1 * Merge YARV
ko1 authored
566
a902624 @ko1 * thread.c, thread_pthread.ci, thread_win32.ci (thread_start_func_1):
ko1 authored
567 if ((th->thread_id) == 0) {
9e0f3e0 @nobu * thread_win32.c (thread_errno): CreateThread does not set errno.
nobu authored
568 return thread_errno;
a3e1b1c @ko1 * Merge YARV
ko1 authored
569 }
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
570
571 w32_resume_thread(th->thread_id);
572
a3e1b1c @ko1 * Merge YARV
ko1 authored
573 if (THREAD_DEBUG) {
574 Sleep(0);
cea3919 @nobu * configure.in (RUBY_CHECK_PRINTF_PREFIX): check for printf format
nobu authored
575 thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %"PRIdSIZE"\n",
a3e1b1c @ko1 * Merge YARV
ko1 authored
576 th, th->thread_id,
577 th->native_thread_data.interrupt_event, stack_size);
578 }
579 return 0;
580 }
581
582 static void
84f8da1 @ko1 * thread.c (rb_thread_stop_timer_thread(), rb_thread_reset_timer_thre…
ko1 authored
583 native_thread_join(HANDLE th)
584 {
6198f53 @unak * thread_win32.c (native_thread_join): need to wait thread, of course.
unak authored
585 w32_wait_events(&th, 1, INFINITE, 0);
84f8da1 @ko1 * thread.c (rb_thread_stop_timer_thread(), rb_thread_reset_timer_thre…
ko1 authored
586 }
587
16612b3 @ko1 * thread.c, vm_core.h: add manual priority support
ko1 authored
588 #if USE_NATIVE_THREAD_PRIORITY
589
84f8da1 @ko1 * thread.c (rb_thread_stop_timer_thread(), rb_thread_reset_timer_thre…
ko1 authored
590 static void
9c57438 @ko1 * blockinlining.c, error.c, eval.c, eval_error.h, eval_intern.h,
ko1 authored
591 native_thread_apply_priority(rb_thread_t *th)
a3e1b1c @ko1 * Merge YARV
ko1 authored
592 {
593 int priority = th->priority;
594 if (th->priority > 0) {
595 priority = THREAD_PRIORITY_ABOVE_NORMAL;
596 }
597 else if (th->priority < 0) {
598 priority = THREAD_PRIORITY_BELOW_NORMAL;
599 }
600 else {
601 priority = THREAD_PRIORITY_NORMAL;
602 }
603
604 SetThreadPriority(th->thread_id, priority);
605 }
606
16612b3 @ko1 * thread.c, vm_core.h: add manual priority support
ko1 authored
607 #endif /* USE_NATIVE_THREAD_PRIORITY */
608
a3e1b1c @ko1 * Merge YARV
ko1 authored
609 static void
3453b2b @ko1 * gc.h, vm_core.h: decl of rb_gc_save_machine_context()
ko1 authored
610 ubf_handle(void *ptr)
a3e1b1c @ko1 * Merge YARV
ko1 authored
611 {
3453b2b @ko1 * gc.h, vm_core.h: decl of rb_gc_save_machine_context()
ko1 authored
612 rb_thread_t *th = (rb_thread_t *)ptr;
ae317b5 @ko1 * yarvcore.h, thread.c: fix to use pthread on cygwin.
ko1 authored
613 thread_debug("ubf_handle: %p\n", th);
25498d2 @unak * thread_win32.c (ubf_handle): cancel blocking IO if it can (only
unak authored
614
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
615 w32_set_event(th->native_thread_data.interrupt_event);
a3e1b1c @ko1 * Merge YARV
ko1 authored
616 }
617
84f8da1 @ko1 * thread.c (rb_thread_stop_timer_thread(), rb_thread_reset_timer_thre…
ko1 authored
618 static HANDLE timer_thread_id = 0;
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
619 static HANDLE timer_thread_lock;
a3e1b1c @ko1 * Merge YARV
ko1 authored
620
2840fa6 @nobu * common.mk: inverted rules order.
nobu authored
621 static unsigned long _stdcall
a3e1b1c @ko1 * Merge YARV
ko1 authored
622 timer_thread_func(void *dummy)
623 {
624 thread_debug("timer_thread\n");
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
625 while (WaitForSingleObject(timer_thread_lock, WIN32_WAIT_TIMEOUT) ==
626 WAIT_TIMEOUT) {
6bbbf98 @nobu * thread.c (thread_initialize): NUM2INT() returns int.
nobu authored
627 timer_thread_function(dummy);
a3e1b1c @ko1 * Merge YARV
ko1 authored
628 }
629 thread_debug("timer killed\n");
630 return 0;
631 }
632
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
633 static void
a3e1b1c @ko1 * Merge YARV
ko1 authored
634 rb_thread_create_timer_thread(void)
635 {
84f8da1 @ko1 * thread.c (rb_thread_stop_timer_thread(), rb_thread_reset_timer_thre…
ko1 authored
636 if (timer_thread_id == 0) {
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
637 if (!timer_thread_lock) {
638 timer_thread_lock = CreateEvent(0, TRUE, FALSE, 0);
639 }
a534e39 @nobu * thread_{pthread,win32}.c (rb_thread_create_timer_thread): needs more
nobu authored
640 timer_thread_id = w32_create_thread(1024 + (THREAD_DEBUG ? BUFSIZ : 0),
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
641 timer_thread_func, 0);
a5abb1c @ko1 * thread_win32.ci (w32_show_error_message): renamed to w32_error.
ko1 authored
642 w32_resume_thread(timer_thread_id);
a3e1b1c @ko1 * Merge YARV
ko1 authored
643 }
644 }
645
641f43d @nobu * thread_pthread.c (thread_timer): checks working flags again.
nobu authored
646 static int
647 native_stop_timer_thread(void)
648 {
649 int stopped = --system_working <= 0;
650 if (stopped) {
9ee5e61 @unak * thread_{pthread,win32}.c (native_stop_timer_thread): join the thread
unak authored
651 SetEvent(timer_thread_lock);
652 native_thread_join(timer_thread_id);
641f43d @nobu * thread_pthread.c (thread_timer): checks working flags again.
nobu authored
653 CloseHandle(timer_thread_lock);
654 timer_thread_lock = 0;
655 }
656 return stopped;
657 }
5732566 @nobu * thread.c (rb_thread_stop_timer_thread): terminates timer thread
nobu authored
658
9ee5e61 @unak * thread_{pthread,win32}.c (native_stop_timer_thread): join the thread
unak authored
659 static void
660 native_reset_timer_thread(void)
661 {
662 if (timer_thread_id) {
663 CloseHandle(timer_thread_id);
664 timer_thread_id = 0;
665 }
666 }
667
767d708 @nobu * Makefile.in (ASFLAGS): needs INCFLAGS.
nobu authored
668 #ifdef RUBY_ALLOCA_CHKSTK
669 void
670 ruby_alloca_chkstk(size_t len, void *sp)
671 {
672 if (ruby_stack_length(NULL) * sizeof(VALUE) >= len) {
673 rb_thread_t *th = GET_THREAD();
674 if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW)) {
675 rb_thread_raised_set(th, RAISED_STACKOVERFLOW);
676 rb_exc_raise(sysstack_error);
677 }
678 }
679 }
680 #endif
a3e1b1c @ko1 * Merge YARV
ko1 authored
681 #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
Something went wrong with that request. Please try again.