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