Ruby: thread_win32.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

thread_win32.c
Go to the documentation of this file.
1/* -*-c-*- */
2/**********************************************************************
3
4 thread_win32.c -
5
6 $Author$
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#ifdef THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION
13
14#include <process.h>
15
16#define TIME_QUANTUM_USEC (10 * 1000)
17#define RB_CONDATTR_CLOCK_MONOTONIC 1 /* no effect */
18
19#undef Sleep
20
21#define native_thread_yield() Sleep(0)
22#define unregister_ubf_list(th)
23#define ubf_wakeup_all_threads() do {} while (0)
24#define ubf_threads_empty() (1)
25#define ubf_timer_disarm() do {} while (0)
26#define ubf_list_atfork() do {} while (0)
27
28static volatile DWORD ruby_native_thread_key = TLS_OUT_OF_INDEXES;
29
30static int w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th);
31
32static void
33w32_error(const char *func)
34{
35 LPVOID lpMsgBuf;
36 DWORD err = GetLastError();
37 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
38 FORMAT_MESSAGE_FROM_SYSTEM |
39 FORMAT_MESSAGE_IGNORE_INSERTS,
40 NULL,
41 err,
42 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
43 (LPTSTR) & lpMsgBuf, 0, NULL) == 0)
44 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
45 FORMAT_MESSAGE_FROM_SYSTEM |
46 FORMAT_MESSAGE_IGNORE_INSERTS,
47 NULL,
48 err,
49 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
50 (LPTSTR) & lpMsgBuf, 0, NULL);
51 rb_bug("%s: %s", func, (char*)lpMsgBuf);
52}
53
54static int
55w32_mutex_lock(HANDLE lock, bool try)
56{
57 DWORD result;
58 while (1) {
59 thread_debug("rb_native_mutex_lock: %p\n", lock);
60 result = w32_wait_events(&lock, 1, try ? 0 : INFINITE, 0);
61 switch (result) {
62 case WAIT_OBJECT_0:
63 /* get mutex object */
64 thread_debug("acquire mutex: %p\n", lock);
65 return 0;
66 case WAIT_OBJECT_0 + 1:
67 /* interrupt */
68 errno = EINTR;
69 thread_debug("acquire mutex interrupted: %p\n", lock);
70 return 0;
71 case WAIT_TIMEOUT:
72 thread_debug("timeout mutex: %p\n", lock);
73 return EBUSY;
74 case WAIT_ABANDONED:
75 rb_bug("win32_mutex_lock: WAIT_ABANDONED");
76 break;
77 default:
78 rb_bug("win32_mutex_lock: unknown result (%ld)", result);
79 break;
80 }
81 }
82 return 0;
83}
84
85static HANDLE
86w32_mutex_create(void)
87{
88 HANDLE lock = CreateMutex(NULL, FALSE, NULL);
89 if (lock == NULL) {
90 w32_error("rb_native_mutex_initialize");
91 }
92 return lock;
93}
94
95#define GVL_DEBUG 0
96
97static void
98gvl_acquire(rb_global_vm_lock_t *gvl, rb_thread_t *th)
99{
100 w32_mutex_lock(gvl->lock, false);
101 if (GVL_DEBUG) fprintf(stderr, "gvl acquire (%p): acquire\n", th);
102}
103
104static void
105gvl_release(rb_global_vm_lock_t *gvl)
106{
107 ReleaseMutex(gvl->lock);
108}
109
110static void
111gvl_yield(rb_global_vm_lock_t *gvl, rb_thread_t *th)
112{
113 gvl_release(gvl);
114 native_thread_yield();
115 gvl_acquire(gvl, th);
116}
117
118void
119 rb_gvl_init(rb_global_vm_lock_t *gvl)
120{
121 if (GVL_DEBUG) fprintf(stderr, "gvl init\n");
122 gvl->lock = w32_mutex_create();
123}
124
125static void
126gvl_destroy(rb_global_vm_lock_t *gvl)
127{
128 if (GVL_DEBUG) fprintf(stderr, "gvl destroy\n");
129 CloseHandle(gvl->lock);
130}
131
132static rb_thread_t *
133ruby_thread_from_native(void)
134{
135 return TlsGetValue(ruby_native_thread_key);
136}
137
138static int
139ruby_thread_set_native(rb_thread_t *th)
140{
141 if (th && th->ec) {
142 rb_ractor_set_current_ec(th->ractor, th->ec);
143 }
144 return TlsSetValue(ruby_native_thread_key, th);
145}
146
147void
148 Init_native_thread(rb_thread_t *th)
149{
150 if ((ruby_current_ec_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
151 rb_bug("TlsAlloc() for ruby_current_ec_key fails");
152 }
153 if ((ruby_native_thread_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
154 rb_bug("TlsAlloc() for ruby_native_thread_key fails");
155 }
156 ruby_thread_set_native(th);
157 DuplicateHandle(GetCurrentProcess(),
158 GetCurrentThread(),
159 GetCurrentProcess(),
160 &th->thread_id, 0, FALSE, DUPLICATE_SAME_ACCESS);
161
162 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
163
164 thread_debug("initial thread (th: %p, thid: %p, event: %p)\n",
165 th, GET_THREAD()->thread_id,
166 th->native_thread_data.interrupt_event);
167}
168
169static int
170w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
171{
172 HANDLE *targets = events;
173 HANDLE intr;
174 const int initcount = count;
175 DWORD ret;
176
177 thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n",
178 events, count, timeout, th);
179 if (th && (intr = th->native_thread_data.interrupt_event)) {
180 if (ResetEvent(intr) && (!RUBY_VM_INTERRUPTED(th->ec) || SetEvent(intr))) {
181 targets = ALLOCA_N(HANDLE, count + 1);
182 memcpy(targets, events, sizeof(HANDLE) * count);
183
184 targets[count++] = intr;
185 thread_debug(" * handle: %p (count: %d, intr)\n", intr, count);
186 }
187 else if (intr == th->native_thread_data.interrupt_event) {
188 w32_error("w32_wait_events");
189 }
190 }
191
192 thread_debug(" WaitForMultipleObjects start (count: %d)\n", count);
193 ret = WaitForMultipleObjects(count, targets, FALSE, timeout);
194 thread_debug(" WaitForMultipleObjects end (ret: %lu)\n", ret);
195
196 if (ret == (DWORD)(WAIT_OBJECT_0 + initcount) && th) {
197 errno = EINTR;
198 }
199 if (ret == WAIT_FAILED && THREAD_DEBUG) {
200 int i;
201 DWORD dmy;
202 for (i = 0; i < count; i++) {
203 thread_debug(" * error handle %d - %s\n", i,
204 GetHandleInformation(targets[i], &dmy) ? "OK" : "NG");
205 }
206 }
207 return ret;
208}
209
210static void ubf_handle(void *ptr);
211#define ubf_select ubf_handle
212
213int
214 rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
215{
216 return w32_wait_events(events, num, timeout, ruby_thread_from_native());
217}
218
219int
220 rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
221{
222 int ret;
223 rb_thread_t *th = GET_THREAD();
224
225 BLOCKING_REGION(th, ret = rb_w32_wait_events_blocking(events, num, timeout),
226 ubf_handle, ruby_thread_from_native(), FALSE);
227 return ret;
228}
229
230static void
231w32_close_handle(HANDLE handle)
232{
233 if (CloseHandle(handle) == 0) {
234 w32_error("w32_close_handle");
235 }
236}
237
238static void
239w32_resume_thread(HANDLE handle)
240{
241 if (ResumeThread(handle) == (DWORD)-1) {
242 w32_error("w32_resume_thread");
243 }
244}
245
246#ifdef _MSC_VER
247#define HAVE__BEGINTHREADEX 1
248#else
249#undef HAVE__BEGINTHREADEX
250#endif
251
252#ifdef HAVE__BEGINTHREADEX
253#define start_thread (HANDLE)_beginthreadex
254#define thread_errno errno
255typedef unsigned long (__stdcall *w32_thread_start_func)(void*);
256#else
257#define start_thread CreateThread
258#define thread_errno rb_w32_map_errno(GetLastError())
259typedef LPTHREAD_START_ROUTINE w32_thread_start_func;
260#endif
261
262static HANDLE
263w32_create_thread(DWORD stack_size, w32_thread_start_func func, void *val)
264{
265 return start_thread(0, stack_size, func, val, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, 0);
266}
267
268int
269 rb_w32_sleep(unsigned long msec)
270{
271 return w32_wait_events(0, 0, msec, ruby_thread_from_native());
272}
273
274int WINAPI
275 rb_w32_Sleep(unsigned long msec)
276{
277 int ret;
278 rb_thread_t *th = GET_THREAD();
279
280 BLOCKING_REGION(th, ret = rb_w32_sleep(msec),
281 ubf_handle, ruby_thread_from_native(), FALSE);
282 return ret;
283}
284
285static DWORD
286hrtime2msec(rb_hrtime_t hrt)
287{
288 return (DWORD)hrt / (DWORD)RB_HRTIME_PER_MSEC;
289}
290
291static void
292native_sleep(rb_thread_t *th, rb_hrtime_t *rel)
293{
294 const volatile DWORD msec = rel ? hrtime2msec(*rel) : INFINITE;
295
296 GVL_UNLOCK_BEGIN(th);
297 {
298 DWORD ret;
299
300 rb_native_mutex_lock(&th->interrupt_lock);
301 th->unblock.func = ubf_handle;
302 th->unblock.arg = th;
303 rb_native_mutex_unlock(&th->interrupt_lock);
304
305 if (RUBY_VM_INTERRUPTED(th->ec)) {
306 /* interrupted. return immediate */
307 }
308 else {
309 thread_debug("native_sleep start (%lu)\n", msec);
310 ret = w32_wait_events(0, 0, msec, th);
311 thread_debug("native_sleep done (%lu)\n", ret);
312 }
313
314 rb_native_mutex_lock(&th->interrupt_lock);
315 th->unblock.func = 0;
316 th->unblock.arg = 0;
317 rb_native_mutex_unlock(&th->interrupt_lock);
318 }
319 GVL_UNLOCK_END(th);
320}
321
322void
323 rb_native_mutex_lock(rb_nativethread_lock_t *lock)
324{
325#if USE_WIN32_MUTEX
326 w32_mutex_lock(lock->mutex, false);
327#else
328 EnterCriticalSection(&lock->crit);
329#endif
330}
331
332int
333 rb_native_mutex_trylock(rb_nativethread_lock_t *lock)
334{
335#if USE_WIN32_MUTEX
336 return w32_mutex_lock(lock->mutex, true);
337#else
338 return TryEnterCriticalSection(&lock->crit) == 0 ? EBUSY : 0;
339#endif
340}
341
342void
343 rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
344{
345#if USE_WIN32_MUTEX
346 thread_debug("release mutex: %p\n", lock->mutex);
347 ReleaseMutex(lock->mutex);
348#else
349 LeaveCriticalSection(&lock->crit);
350#endif
351}
352
353void
354 rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
355{
356#if USE_WIN32_MUTEX
357 lock->mutex = w32_mutex_create();
358 /* thread_debug("initialize mutex: %p\n", lock->mutex); */
359#else
360 InitializeCriticalSection(&lock->crit);
361#endif
362}
363
364void
365 rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
366{
367#if USE_WIN32_MUTEX
368 w32_close_handle(lock->mutex);
369#else
370 DeleteCriticalSection(&lock->crit);
371#endif
372}
373
374struct cond_event_entry {
375 struct cond_event_entry* next;
376 struct cond_event_entry* prev;
377 HANDLE event;
378};
379
380void
381 rb_native_cond_signal(rb_nativethread_cond_t *cond)
382{
383 /* cond is guarded by mutex */
384 struct cond_event_entry *e = cond->next;
385 struct cond_event_entry *head = (struct cond_event_entry*)cond;
386
387 if (e != head) {
388 struct cond_event_entry *next = e->next;
389 struct cond_event_entry *prev = e->prev;
390
391 prev->next = next;
392 next->prev = prev;
393 e->next = e->prev = e;
394
395 SetEvent(e->event);
396 }
397}
398
399void
400 rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
401{
402 /* cond is guarded by mutex */
403 struct cond_event_entry *e = cond->next;
404 struct cond_event_entry *head = (struct cond_event_entry*)cond;
405
406 while (e != head) {
407 struct cond_event_entry *next = e->next;
408 struct cond_event_entry *prev = e->prev;
409
410 SetEvent(e->event);
411
412 prev->next = next;
413 next->prev = prev;
414 e->next = e->prev = e;
415
416 e = next;
417 }
418}
419
420static int
421native_cond_timedwait_ms(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
422{
423 DWORD r;
424 struct cond_event_entry entry;
425 struct cond_event_entry *head = (struct cond_event_entry*)cond;
426
427 entry.event = CreateEvent(0, FALSE, FALSE, 0);
428
429 /* cond is guarded by mutex */
430 entry.next = head;
431 entry.prev = head->prev;
432 head->prev->next = &entry;
433 head->prev = &entry;
434
435 rb_native_mutex_unlock(mutex);
436 {
437 r = WaitForSingleObject(entry.event, msec);
438 if ((r != WAIT_OBJECT_0) && (r != WAIT_TIMEOUT)) {
439 rb_bug("rb_native_cond_wait: WaitForSingleObject returns %lu", r);
440 }
441 }
442 rb_native_mutex_lock(mutex);
443
444 entry.prev->next = entry.next;
445 entry.next->prev = entry.prev;
446
447 w32_close_handle(entry.event);
448 return (r == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
449}
450
451void
452 rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
453{
454 native_cond_timedwait_ms(cond, mutex, INFINITE);
455}
456
457static unsigned long
458abs_timespec_to_timeout_ms(const struct timespec *ts)
459{
460 struct timeval tv;
461 struct timeval now;
462
463 gettimeofday(&now, NULL);
464 tv.tv_sec = ts->tv_sec;
465 tv.tv_usec = ts->tv_nsec / 1000;
466
467 if (!rb_w32_time_subtract(&tv, &now))
468 return 0;
469
470 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
471}
472
473static int
474native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, const struct timespec *ts)
475{
476 unsigned long timeout_ms;
477
478 timeout_ms = abs_timespec_to_timeout_ms(ts);
479 if (!timeout_ms)
480 return ETIMEDOUT;
481
482 return native_cond_timedwait_ms(cond, mutex, timeout_ms);
483}
484
485static struct timespec native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel);
486
487void
488 rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
489{
490 struct timespec rel = {
491 .tv_sec = msec / 1000,
492 .tv_nsec = (msec % 1000) * 1000 * 1000,
493 };
494 struct timespec ts = native_cond_timeout(cond, rel);
495 native_cond_timedwait(cond, mutex, &ts);
496}
497
498static struct timespec
499native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
500{
501 int ret;
502 struct timeval tv;
503 struct timespec timeout;
504 struct timespec now;
505
506 ret = gettimeofday(&tv, 0);
507 if (ret != 0)
508 rb_sys_fail(0);
509 now.tv_sec = tv.tv_sec;
510 now.tv_nsec = tv.tv_usec * 1000;
511
512 timeout.tv_sec = now.tv_sec;
513 timeout.tv_nsec = now.tv_nsec;
514 timeout.tv_sec += timeout_rel.tv_sec;
515 timeout.tv_nsec += timeout_rel.tv_nsec;
516
517 if (timeout.tv_nsec >= 1000*1000*1000) {
518 timeout.tv_sec++;
519 timeout.tv_nsec -= 1000*1000*1000;
520 }
521
522 if (timeout.tv_sec < now.tv_sec)
523 timeout.tv_sec = TIMET_MAX;
524
525 return timeout;
526}
527
528void
529 rb_native_cond_initialize(rb_nativethread_cond_t *cond)
530{
531 cond->next = (struct cond_event_entry *)cond;
532 cond->prev = (struct cond_event_entry *)cond;
533}
534
535void
536 rb_native_cond_destroy(rb_nativethread_cond_t *cond)
537{
538 /* */
539}
540
541void
542 ruby_init_stack(volatile VALUE *addr)
543{
544}
545
546#define CHECK_ERR(expr) \
547 {if (!(expr)) {rb_bug("err: %lu - %s", GetLastError(), #expr);}}
548
549static void
550native_thread_init_stack(rb_thread_t *th)
551{
552 MEMORY_BASIC_INFORMATION mi;
553 char *base, *end;
554 DWORD size, space;
555
556 CHECK_ERR(VirtualQuery(&mi, &mi, sizeof(mi)));
557 base = mi.AllocationBase;
558 end = mi.BaseAddress;
559 end += mi.RegionSize;
560 size = end - base;
561 space = size / 5;
562 if (space > 1024*1024) space = 1024*1024;
563 th->ec->machine.stack_start = (VALUE *)end - 1;
564 th->ec->machine.stack_maxsize = size - space;
565}
566
567#ifndef InterlockedExchangePointer
568#define InterlockedExchangePointer(t, v) \
569 (void *)InterlockedExchange((long *)(t), (long)(v))
570#endif
571static void
572native_thread_destroy(rb_thread_t *th)
573{
574 HANDLE intr = InterlockedExchangePointer(&th->native_thread_data.interrupt_event, 0);
575 thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id);
576 w32_close_handle(intr);
577}
578
579static unsigned long __stdcall
580thread_start_func_1(void *th_ptr)
581{
582 rb_thread_t *th = th_ptr;
583 volatile HANDLE thread_id = th->thread_id;
584
585 native_thread_init_stack(th);
586 th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);
587
588 /* run */
589 thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th,
590 th->thread_id, th->native_thread_data.interrupt_event);
591
592 thread_start_func_2(th, th->ec->machine.stack_start);
593
594 w32_close_handle(thread_id);
595 thread_debug("thread deleted (th: %p)\n", th);
596 return 0;
597}
598
599static int
600native_thread_create(rb_thread_t *th)
601{
602 const size_t stack_size = th->vm->default_params.thread_machine_stack_size + th->vm->default_params.thread_vm_stack_size;
603 th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th);
604
605 if ((th->thread_id) == 0) {
606 return thread_errno;
607 }
608
609 w32_resume_thread(th->thread_id);
610
611 if (THREAD_DEBUG) {
612 Sleep(0);
613 thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %"PRIuSIZE"\n",
614 th, th->thread_id,
615 th->native_thread_data.interrupt_event, stack_size);
616 }
617 return 0;
618}
619
620static void
621native_thread_join(HANDLE th)
622{
623 w32_wait_events(&th, 1, INFINITE, 0);
624}
625
626#if USE_NATIVE_THREAD_PRIORITY
627
628static void
629native_thread_apply_priority(rb_thread_t *th)
630{
631 int priority = th->priority;
632 if (th->priority > 0) {
633 priority = THREAD_PRIORITY_ABOVE_NORMAL;
634 }
635 else if (th->priority < 0) {
636 priority = THREAD_PRIORITY_BELOW_NORMAL;
637 }
638 else {
639 priority = THREAD_PRIORITY_NORMAL;
640 }
641
642 SetThreadPriority(th->thread_id, priority);
643}
644
645#endif /* USE_NATIVE_THREAD_PRIORITY */
646
647int rb_w32_select_with_thread(int, fd_set *, fd_set *, fd_set *, struct timeval *, void *); /* @internal */
648
649static int
650native_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *exceptfds, struct timeval *timeout, rb_thread_t *th)
651{
652 fd_set *r = NULL, *w = NULL, *e = NULL;
653 if (readfds) {
654 rb_fd_resize(n - 1, readfds);
655 r = rb_fd_ptr(readfds);
656 }
657 if (writefds) {
658 rb_fd_resize(n - 1, writefds);
659 w = rb_fd_ptr(writefds);
660 }
661 if (exceptfds) {
662 rb_fd_resize(n - 1, exceptfds);
663 e = rb_fd_ptr(exceptfds);
664 }
665 return rb_w32_select_with_thread(n, r, w, e, timeout, th);
666}
667
668/* @internal */
669int
670 rb_w32_check_interrupt(rb_thread_t *th)
671{
672 return w32_wait_events(0, 0, 0, th);
673}
674
675static void
676ubf_handle(void *ptr)
677{
678 rb_thread_t *th = (rb_thread_t *)ptr;
679 thread_debug("ubf_handle: %p\n", th);
680
681 if (!SetEvent(th->native_thread_data.interrupt_event)) {
682 w32_error("ubf_handle");
683 }
684}
685
686int rb_w32_set_thread_description(HANDLE th, const WCHAR *name);
687int rb_w32_set_thread_description_str(HANDLE th, VALUE name);
688#define native_set_another_thread_name rb_w32_set_thread_description_str
689
690static struct {
691 HANDLE id;
692 HANDLE lock;
693} timer_thread;
694#define TIMER_THREAD_CREATED_P() (timer_thread.id != 0)
695
696static unsigned long __stdcall
697timer_thread_func(void *dummy)
698{
699 rb_vm_t *vm = GET_VM();
700 thread_debug("timer_thread\n");
701 rb_w32_set_thread_description(GetCurrentThread(), L"ruby-timer-thread");
702 while (WaitForSingleObject(timer_thread.lock,
703 TIME_QUANTUM_USEC/1000) == WAIT_TIMEOUT) {
704 vm->clock++;
705 ruby_sigchld_handler(vm); /* probably no-op */
706 rb_threadptr_check_signal(vm->ractor.main_thread);
707 }
708 thread_debug("timer killed\n");
709 return 0;
710}
711
712void
713 rb_thread_wakeup_timer_thread(int sig)
714{
715 /* do nothing */
716}
717
718static VALUE
719rb_thread_start_unblock_thread(void)
720{
721 return Qfalse; /* no-op */
722}
723
724static void
725rb_thread_create_timer_thread(void)
726{
727 if (timer_thread.id == 0) {
728 if (!timer_thread.lock) {
729 timer_thread.lock = CreateEvent(0, TRUE, FALSE, 0);
730 }
731 timer_thread.id = w32_create_thread(1024 + (THREAD_DEBUG ? BUFSIZ : 0),
732 timer_thread_func, 0);
733 w32_resume_thread(timer_thread.id);
734 }
735}
736
737static int
738native_stop_timer_thread(void)
739{
740 int stopped = --system_working <= 0;
741 if (stopped) {
742 SetEvent(timer_thread.lock);
743 native_thread_join(timer_thread.id);
744 CloseHandle(timer_thread.lock);
745 timer_thread.lock = 0;
746 }
747 return stopped;
748}
749
750static void
751native_reset_timer_thread(void)
752{
753 if (timer_thread.id) {
754 CloseHandle(timer_thread.id);
755 timer_thread.id = 0;
756 }
757}
758
759int
760ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr)
761{
762 return rb_ec_raised_p(th->ec, RAISED_STACKOVERFLOW);
763}
764
765#if defined(__MINGW32__)
766LONG WINAPI
767rb_w32_stack_overflow_handler(struct _EXCEPTION_POINTERS *exception)
768{
769 if (exception->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
770 rb_ec_raised_set(GET_EC(), RAISED_STACKOVERFLOW);
771 raise(SIGSEGV);
772 }
773 return EXCEPTION_CONTINUE_SEARCH;
774}
775#endif
776
777#ifdef RUBY_ALLOCA_CHKSTK
778void
779ruby_alloca_chkstk(size_t len, void *sp)
780{
781 if (ruby_stack_length(NULL) * sizeof(VALUE) >= len) {
782 rb_execution_context_t *ec = GET_EC();
783 if (!rb_ec_raised_p(ec, RAISED_STACKOVERFLOW)) {
784 rb_ec_raised_set(ec, RAISED_STACKOVERFLOW);
785 rb_exc_raise(sysstack_error);
786 }
787 }
788}
789#endif
790int
791 rb_reserved_fd_p(int fd)
792{
793 return 0;
794}
795
796int
797 rb_sigwait_fd_get(rb_thread_t *th)
798{
799 return -1; /* TODO */
800}
801
802 NORETURN(void rb_sigwait_fd_put(rb_thread_t *, int));
803void
804 rb_sigwait_fd_put(rb_thread_t *th, int fd)
805{
806 rb_bug("not implemented, should not be called");
807}
808
809 NORETURN(void rb_sigwait_sleep(const rb_thread_t *, int, const rb_hrtime_t *));
810void
811 rb_sigwait_sleep(const rb_thread_t *th, int fd, const rb_hrtime_t *rel)
812{
813 rb_bug("not implemented, should not be called");
814}
815
816rb_nativethread_id_t
817 rb_nativethread_self(void)
818{
819 return GetCurrentThread();
820}
821
822static void
823native_set_thread_name(rb_thread_t *th)
824{
825}
826
827#if USE_MJIT
828static unsigned long __stdcall
829 mjit_worker(void *arg)
830{
831 void (*worker_func)(void) = arg;
832 rb_w32_set_thread_description(GetCurrentThread(), L"ruby-mjitworker");
833 worker_func();
834 return 0;
835}
836
837/* Launch MJIT thread. Returns FALSE if it fails to create thread. */
838int
839rb_thread_create_mjit_thread(void (*worker_func)(void))
840{
841 size_t stack_size = 4 * 1024; /* 4KB is the minimum commit size */
842 HANDLE thread_id = w32_create_thread(stack_size, mjit_worker, worker_func);
843 if (thread_id == 0) {
844 return FALSE;
845 }
846
847 w32_resume_thread(thread_id);
848 return TRUE;
849}
850#endif
851
852#endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */
L
#define L(x)
Definition: asm.h:125
NORETURN
#define NORETURN(x)
Definition: attributes.h:152
ptr
struct RIMemo * ptr
Definition: debug.c:88
num
big_t * num
Definition: enough.c:232
len
uint8_t len
Definition: escape.c:17
rb_ec_raised_p
#define rb_ec_raised_p(ec, f)
Definition: eval_intern.h:272
rb_ec_raised_set
#define rb_ec_raised_set(ec, f)
Definition: eval_intern.h:270
RAISED_STACKOVERFLOW
@ RAISED_STACKOVERFLOW
Definition: eval_intern.h:267
memcpy
#define memcpy(d, s, n)
Definition: ffi_common.h:55
ruby_init_stack
void ruby_init_stack(volatile VALUE *)
ruby_stack_length
size_t ruby_stack_length(VALUE **p)
Definition: gc.c:5512
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:712
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:768
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:3041
RB_HRTIME_PER_MSEC
#define RB_HRTIME_PER_MSEC
Definition: hrtime.h:36
rb_hrtime_t
uint64_t rb_hrtime_t
Definition: hrtime.h:47
rb_reserved_fd_p
int rb_reserved_fd_p(int fd)
PRIuSIZE
#define PRIuSIZE
Definition: inttypes.h:127
size
voidpf void uLong size
Definition: ioapi.h:138
long
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
ALLOCA_N
#define ALLOCA_N(type, n)
Definition: memory.h:112
mjit_worker
void mjit_worker(void)
Definition: mjit_worker.c:1418
id
const int id
Definition: nkf.c:209
name
const char * name
Definition: nkf.c:208
count
int count
Definition: nkf.c:5055
TRUE
#define TRUE
Definition: nkf.h:175
FALSE
#define FALSE
Definition: nkf.h:174
rb_sigwait_fd_put
void rb_sigwait_fd_put(const rb_thread_t *, int fd)
rb_sigwait_fd_get
int rb_sigwait_fd_get(const rb_thread_t *)
rb_sigwait_sleep
void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *)
rb_gvl_init
void rb_gvl_init(rb_global_vm_lock_t *gvl)
NULL
#define NULL
Definition: regenc.h:69
rb_fd_resize
#define rb_fd_resize(n, f)
Definition: select.h:41
ruby_sigchld_handler
void ruby_sigchld_handler(rb_vm_t *vm)
Definition: signal.c:1090
Qfalse
#define Qfalse
Definition: special_consts.h:50
native_thread_data_struct::interrupt_event
HANDLE interrupt_event
Definition: thread_win32.h:30
rb_execution_context_struct
Definition: vm_core.h:854
rb_execution_context_struct::machine
struct rb_execution_context_struct::@200 machine
rb_execution_context_struct::stack_maxsize
size_t stack_maxsize
Definition: vm_core.h:903
rb_execution_context_struct::stack_start
VALUE * stack_start
Definition: vm_core.h:901
rb_fdset_t
Definition: largesize.h:69
rb_global_vm_lock_struct
Definition: thread_pthread.h:45
rb_global_vm_lock_struct::lock
rb_nativethread_lock_t lock
Definition: thread_pthread.h:48
rb_thread_cond_struct
Definition: thread_win32.h:24
rb_thread_cond_struct::next
struct cond_event_entry * next
Definition: thread_win32.h:25
rb_thread_cond_struct::prev
struct cond_event_entry * prev
Definition: thread_win32.h:26
rb_thread_struct
Definition: vm_core.h:935
rb_thread_struct::ec
rb_execution_context_t * ec
Definition: vm_core.h:941
rb_thread_struct::unblock
struct rb_unblock_callback unblock
Definition: vm_core.h:983
rb_thread_struct::native_thread_data
native_thread_data_t native_thread_data
Definition: vm_core.h:966
rb_thread_struct::vm
rb_vm_t * vm
Definition: vm_core.h:939
rb_thread_struct::ractor
rb_ractor_t * ractor
Definition: vm_core.h:938
rb_thread_struct::priority
int8_t priority
Definition: vm_core.h:963
rb_thread_struct::thread_id
rb_nativethread_id_t thread_id
Definition: vm_core.h:953
rb_thread_struct::interrupt_lock
rb_nativethread_lock_t interrupt_lock
Definition: vm_core.h:982
rb_unblock_callback::arg
void * arg
Definition: vm_core.h:828
rb_unblock_callback::func
rb_unblock_function_t * func
Definition: vm_core.h:827
rb_vm_struct
Definition: vm_core.h:564
rb_vm_struct::ractor
struct rb_vm_struct::@194 ractor
rb_vm_struct::main_thread
struct rb_thread_struct * main_thread
Definition: vm_core.h:573
rb_vm_struct::default_params
struct rb_vm_struct::@196 default_params
rb_vm_struct::thread_vm_stack_size
size_t thread_vm_stack_size
Definition: vm_core.h:672
rb_vm_struct::thread_machine_stack_size
size_t thread_machine_stack_size
Definition: vm_core.h:673
timespec
Definition: missing.h:62
timespec::tv_nsec
long tv_nsec
Definition: missing.h:64
timespec::tv_sec
time_t tv_sec
Definition: missing.h:63
timeval
Definition: missing.h:51
rb_threadptr_check_signal
void rb_threadptr_check_signal(rb_thread_t *mth)
Definition: thread.c:4598
GVL_UNLOCK_BEGIN
#define GVL_UNLOCK_BEGIN(th)
Definition: thread.c:173
BLOCKING_REGION
#define BLOCKING_REGION(th, exec, ubf, ubfarg, fail_if_interrupted)
Definition: thread.c:191
THREAD_DEBUG
#define THREAD_DEBUG
Definition: thread.c:108
GVL_UNLOCK_END
#define GVL_UNLOCK_END(th)
Definition: thread.c:177
thread_debug
#define thread_debug
Definition: thread.c:333
rb_nativethread_self
rb_nativethread_id_t rb_nativethread_self()
rb_native_mutex_lock
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
rb_native_cond_initialize
void rb_native_cond_initialize(rb_nativethread_cond_t *cond)
rb_native_mutex_trylock
int rb_native_mutex_trylock(rb_nativethread_lock_t *lock)
rb_native_cond_broadcast
void rb_native_cond_broadcast(rb_nativethread_cond_t *cond)
rb_native_mutex_initialize
void rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
rb_native_mutex_unlock
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
rb_native_mutex_destroy
void rb_native_mutex_destroy(rb_nativethread_lock_t *lock)
rb_native_cond_destroy
void rb_native_cond_destroy(rb_nativethread_cond_t *cond)
rb_native_cond_signal
void rb_native_cond_signal(rb_nativethread_cond_t *cond)
rb_native_cond_wait
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
rb_native_cond_timedwait
void rb_native_cond_timedwait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex, unsigned long msec)
ruby_current_ec_key
native_tls_key_t ruby_current_ec_key
Definition: vm.c:400
TryEnterCriticalSection
WINBASEAPI BOOL WINAPI TryEnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection)
VALUE
unsigned long VALUE
Definition: value.h:38
RUBY_VM_INTERRUPTED
#define RUBY_VM_INTERRUPTED(ec)
Definition: vm_core.h:1881
Init_native_thread
void Init_native_thread(rb_thread_t *th)
sysstack_error
#define sysstack_error
Definition: vm_core.h:1729
rb_thread_wakeup_timer_thread
void rb_thread_wakeup_timer_thread(int)
rb_w32_select_with_thread
int rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout, void *th)
Definition: win32.c:3169
rb_w32_check_interrupt
int rb_w32_check_interrupt(void *)
rb_w32_set_thread_description
int rb_w32_set_thread_description(HANDLE th, const WCHAR *name)
Definition: win32.c:8134
err
int err
Definition: win32.c:142
rb_w32_set_thread_description_str
int rb_w32_set_thread_description_str(HANDLE th, VALUE name)
Definition: win32.c:8151
rb_w32_wait_events
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
gettimeofday
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4654
rb_w32_wait_events_blocking
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
rb_w32_sleep
int rb_w32_sleep(unsigned long msec)
ETIMEDOUT
#define ETIMEDOUT
Definition: win32.h:543
rb_w32_time_subtract
int rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait)
Definition: win32.c:3130
rb_w32_Sleep
int WINAPI rb_w32_Sleep(unsigned long msec)
DWORD
IUnknown DWORD
Definition: win32ole.c:33