1
/***********************************************************************/
5
/* Xavier Leroy and Pascal Cuoq, INRIA Rocquencourt */
7
/* Copyright 1995 Institut National de Recherche en Informatique et */
8
/* en Automatique. All rights reserved. This file is distributed */
9
/* under the terms of the GNU Library General Public License, with */
10
/* the special exception on linking described in file ../../LICENSE. */
12
/***********************************************************************/
14
/* $Id: win32.c 8468 2007-10-31 09:12:29Z xleroy $ */
16
/* Thread interface for Win32 threads */
24
#include "backtrace.h"
42
/* Initial size of stack when a thread is created (4 Ko) */
43
#define Thread_stack_size (Stack_size / 4)
45
/* Max computation time before rescheduling, in milliseconds (50ms) */
46
#define Thread_timeout 50
48
/* Signal used for timer preemption (any unused, legal signal number) */
49
#define SIGTIMER SIGTERM
51
/* The ML value describing a thread (heap-allocated) */
53
struct caml_thread_handle {
54
value final_fun; /* Finalization function */
55
HANDLE handle; /* Windows handle */
58
struct caml_thread_descr {
59
value ident; /* Unique integer ID */
60
value start_closure; /* The closure to start this thread */
61
struct caml_thread_handle * thread_handle; /* Finalized object with handle */
64
#define Ident(v) (((struct caml_thread_descr *)(v))->ident)
65
#define Start_closure(v) (((struct caml_thread_descr *)(v))->start_closure)
66
#define Threadhandle(v) (((struct caml_thread_descr *)(v))->thread_handle)
68
/* The infos on threads (allocated via malloc()) */
70
struct caml_thread_struct {
71
HANDLE wthread; /* The Windows thread handle */
72
value descr; /* The heap-allocated descriptor (root) */
73
struct caml_thread_struct * next; /* Double linking of running threads */
74
struct caml_thread_struct * prev;
76
char * bottom_of_stack; /* Saved value of caml_bottom_of_stack */
77
uintnat last_retaddr; /* Saved value of caml_last_return_address */
78
value * gc_regs; /* Saved value of caml_gc_regs */
79
char * exception_pointer; /* Saved value of caml_exception_pointer */
80
struct caml__roots_block * local_roots; /* Saved value of local_roots */
82
value * stack_low; /* The execution stack for this thread */
84
value * stack_threshold;
85
value * sp; /* Saved value of extern_sp for this thread */
86
value * trapsp; /* Saved value of trapsp for this thread */
87
struct caml__roots_block * local_roots; /* Saved value of local_roots */
88
struct longjmp_buffer * external_raise; /* Saved external_raise */
89
int backtrace_pos; /* Saved backtrace_pos */
90
code_t * backtrace_buffer; /* Saved backtrace_buffer */
91
value backtrace_last_exn; /* Saved backtrace_last_exn (root) */
95
typedef struct caml_thread_struct * caml_thread_t;
97
/* The descriptor for the currently executing thread (thread-specific) */
99
static caml_thread_t curr_thread = NULL;
101
/* The global mutex used to ensure that at most one thread is running
103
static HANDLE caml_mutex;
105
/* The key used for storing the thread descriptor in the specific data
106
of the corresponding Posix thread. */
107
static DWORD thread_descriptor_key;
109
/* The key used for unlocking I/O channels on exceptions */
110
static DWORD last_channel_locked_key;
112
/* Identifier for next thread creation */
113
static intnat thread_next_ident = 0;
115
/* Forward declarations */
117
static void caml_wthread_error (char * msg);
119
/* Hook for scanning the stacks of the other threads */
121
static void (*prev_scan_roots_hook) (scanning_action);
123
static void caml_thread_scan_roots(scanning_action action)
129
(*action)(th->descr, &th->descr);
131
(*action)(th->backtrace_last_exn, &th->backtrace_last_exn);
133
/* Don't rescan the stack of the current thread, it was done already */
134
if (th != curr_thread) {
136
if (th->bottom_of_stack != NULL)
137
do_local_roots(action, th->bottom_of_stack, th->last_retaddr,
138
th->gc_regs, th->local_roots);
140
do_local_roots(action, th->sp, th->stack_high, th->local_roots);
144
} while (th != curr_thread);
146
if (prev_scan_roots_hook != NULL) (*prev_scan_roots_hook)(action);
149
/* Hooks for enter_blocking_section and leave_blocking_section */
151
static void caml_thread_enter_blocking_section(void)
153
/* Save the stack-related global variables in the thread descriptor
154
of the current thread */
156
curr_thread->bottom_of_stack = caml_bottom_of_stack;
157
curr_thread->last_retaddr = caml_last_return_address;
158
curr_thread->gc_regs = caml_gc_regs;
159
curr_thread->exception_pointer = caml_exception_pointer;
160
curr_thread->local_roots = local_roots;
162
curr_thread->stack_low = stack_low;
163
curr_thread->stack_high = stack_high;
164
curr_thread->stack_threshold = stack_threshold;
165
curr_thread->sp = extern_sp;
166
curr_thread->trapsp = trapsp;
167
curr_thread->local_roots = local_roots;
168
curr_thread->external_raise = external_raise;
169
curr_thread->backtrace_pos = backtrace_pos;
170
curr_thread->backtrace_buffer = backtrace_buffer;
171
curr_thread->backtrace_last_exn = backtrace_last_exn;
173
/* Release the global mutex */
174
ReleaseMutex(caml_mutex);
177
static void caml_thread_leave_blocking_section(void)
179
WaitForSingleObject(caml_mutex, INFINITE);
180
/* Update curr_thread to point to the thread descriptor corresponding
181
to the thread currently executing */
182
curr_thread = TlsGetValue(thread_descriptor_key);
183
/* Restore the stack-related global variables */
185
caml_bottom_of_stack= curr_thread->bottom_of_stack;
186
caml_last_return_address = curr_thread->last_retaddr;
187
caml_gc_regs = curr_thread->gc_regs;
188
caml_exception_pointer = curr_thread->exception_pointer;
189
local_roots = curr_thread->local_roots;
191
stack_low = curr_thread->stack_low;
192
stack_high = curr_thread->stack_high;
193
stack_threshold = curr_thread->stack_threshold;
194
extern_sp = curr_thread->sp;
195
trapsp = curr_thread->trapsp;
196
local_roots = curr_thread->local_roots;
197
external_raise = curr_thread->external_raise;
198
backtrace_pos = curr_thread->backtrace_pos;
199
backtrace_buffer = curr_thread->backtrace_buffer;
200
backtrace_last_exn = curr_thread->backtrace_last_exn;
204
static int caml_thread_try_leave_blocking_section(void)
206
/* Disable immediate processing of signals (PR#3659).
207
try_leave_blocking_section always fails, forcing the signal to be
208
recorded and processed at the next leave_blocking_section or
213
/* Hooks for I/O locking */
215
static void caml_io_mutex_free(struct channel * chan)
217
HANDLE mutex = chan->mutex;
223
static void caml_io_mutex_lock(struct channel * chan)
225
if (chan->mutex == NULL) {
226
HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
227
if (mutex == NULL) caml_wthread_error("Thread.iolock");
228
chan->mutex = (void *) mutex;
230
/* PR#4351: first try to acquire mutex without releasing the master lock */
231
if (WaitForSingleObject((HANDLE) chan->mutex, 0) == WAIT_OBJECT_0) {
232
TlsSetValue(last_channel_locked_key, (void *) chan);
235
enter_blocking_section();
236
WaitForSingleObject((HANDLE) chan->mutex, INFINITE);
237
/* Problem: if a signal occurs at this point,
238
and the signal handler raises an exception, we will not
239
unlock the mutex. The alternative (doing the setspecific
240
before locking the mutex is also incorrect, since we could
241
then unlock a mutex that is unlocked or locked by someone else. */
242
TlsSetValue(last_channel_locked_key, (void *) chan);
243
leave_blocking_section();
246
static void caml_io_mutex_unlock(struct channel * chan)
248
ReleaseMutex((HANDLE) chan->mutex);
249
TlsSetValue(last_channel_locked_key, NULL);
252
static void caml_io_mutex_unlock_exn(void)
254
struct channel * chan = TlsGetValue(last_channel_locked_key);
255
if (chan != NULL) caml_io_mutex_unlock(chan);
258
/* The "tick" thread fakes a signal at regular intervals. */
260
static DWORD WINAPI caml_thread_tick(void * arg)
263
Sleep(Thread_timeout);
264
caml_pending_signals[SIGTIMER] = 1;
265
caml_signals_are_pending = 1;
267
young_limit = young_end;
274
static void caml_thread_finalize(value vthread)
276
CloseHandle(((struct caml_thread_handle *)vthread)->handle);
279
/* Initialize the thread machinery */
281
CAMLprim value caml_thread_initialize(value unit)
283
value vthread = Val_unit;
288
/* Protect against repeated initialization (PR#1325) */
289
if (curr_thread != NULL) return Val_unit;
290
Begin_root (vthread);
291
/* Initialize the main mutex and acquire it */
292
caml_mutex = CreateMutex(NULL, TRUE, NULL);
293
if (caml_mutex == NULL) caml_wthread_error("Thread.init");
294
/* Initialize the TLS keys */
295
thread_descriptor_key = TlsAlloc();
296
last_channel_locked_key = TlsAlloc();
297
/* Create a finalized value to hold thread handle */
298
vthread = alloc_final(sizeof(struct caml_thread_handle) / sizeof(value),
299
caml_thread_finalize, 1, 1000);
300
((struct caml_thread_handle *)vthread)->handle = NULL;
301
/* Create a descriptor for the current thread */
302
descr = alloc_tuple(sizeof(struct caml_thread_descr) / sizeof(value));
303
Ident(descr) = Val_long(thread_next_ident);
304
Start_closure(descr) = Val_unit;
305
Threadhandle(descr) = (struct caml_thread_handle *) vthread;
307
/* Create an info block for the current thread */
309
(caml_thread_t) stat_alloc(sizeof(struct caml_thread_struct));
310
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
311
GetCurrentProcess(), &(curr_thread->wthread),
312
0, FALSE, DUPLICATE_SAME_ACCESS);
313
if (curr_thread->wthread == NULL) caml_wthread_error("Thread.init");
314
((struct caml_thread_handle *)vthread)->handle = curr_thread->wthread;
315
curr_thread->descr = descr;
316
curr_thread->next = curr_thread;
317
curr_thread->prev = curr_thread;
318
/* The stack-related fields will be filled in at the next
319
enter_blocking_section */
320
/* Associate the thread descriptor with the thread */
321
TlsSetValue(thread_descriptor_key, (void *) curr_thread);
322
/* Set up the hooks */
323
prev_scan_roots_hook = scan_roots_hook;
324
scan_roots_hook = caml_thread_scan_roots;
325
enter_blocking_section_hook = caml_thread_enter_blocking_section;
326
leave_blocking_section_hook = caml_thread_leave_blocking_section;
327
try_leave_blocking_section_hook = caml_thread_try_leave_blocking_section;
328
caml_channel_mutex_free = caml_io_mutex_free;
329
caml_channel_mutex_lock = caml_io_mutex_lock;
330
caml_channel_mutex_unlock = caml_io_mutex_unlock;
331
caml_channel_mutex_unlock_exn = caml_io_mutex_unlock_exn;
332
/* Fork the tick thread */
333
tick_thread = CreateThread(NULL, 0, caml_thread_tick, NULL, 0, &th_id);
334
if (tick_thread == NULL) caml_wthread_error("Thread.init");
335
CloseHandle(tick_thread);
340
/* Create a thread */
342
static DWORD WINAPI caml_thread_start(void * arg)
344
caml_thread_t th = (caml_thread_t) arg;
347
/* Associate the thread descriptor with the thread */
348
TlsSetValue(thread_descriptor_key, (void *) th);
349
TlsSetValue(last_channel_locked_key, NULL);
350
/* Acquire the global mutex and set up the stack variables */
351
leave_blocking_section();
352
/* Callback the closure */
353
clos = Start_closure(th->descr);
354
modify(&(Start_closure(th->descr)), Val_unit);
355
callback_exn(clos, Val_unit);
356
/* Remove th from the doubly-linked list of threads */
357
th->next->prev = th->prev;
358
th->prev->next = th->next;
359
/* Release the main mutex (forever) */
360
ReleaseMutex(caml_mutex);
362
/* Free the memory resources */
363
stat_free(th->stack_low);
364
if (th->backtrace_buffer != NULL) free(th->backtrace_buffer);
366
/* Free the thread descriptor */
368
/* The thread now stops running */
372
CAMLprim value caml_thread_new(value clos)
375
value vthread = Val_unit;
379
Begin_roots2 (clos, vthread)
380
/* Create a finalized value to hold thread handle */
381
vthread = alloc_final(sizeof(struct caml_thread_handle) / sizeof(value),
382
caml_thread_finalize, 1, 1000);
383
((struct caml_thread_handle *)vthread)->handle = NULL;
384
/* Create a descriptor for the new thread */
385
descr = alloc_tuple(sizeof(struct caml_thread_descr) / sizeof(value));
386
Ident(descr) = Val_long(thread_next_ident);
387
Start_closure(descr) = clos;
388
Threadhandle(descr) = (struct caml_thread_handle *) vthread;
390
/* Create an info block for the current thread */
391
th = (caml_thread_t) stat_alloc(sizeof(struct caml_thread_struct));
394
th->bottom_of_stack = NULL;
395
th->exception_pointer = NULL;
396
th->local_roots = NULL;
398
/* Allocate the stacks */
399
th->stack_low = (value *) stat_alloc(Thread_stack_size);
400
th->stack_high = th->stack_low + Thread_stack_size / sizeof(value);
401
th->stack_threshold = th->stack_low + Stack_threshold / sizeof(value);
402
th->sp = th->stack_high;
403
th->trapsp = th->stack_high;
404
th->local_roots = NULL;
405
th->external_raise = NULL;
406
th->backtrace_pos = 0;
407
th->backtrace_buffer = NULL;
408
th->backtrace_last_exn = Val_unit;
410
/* Add thread info block to the list of threads */
411
th->next = curr_thread->next;
412
th->prev = curr_thread;
413
curr_thread->next->prev = th;
414
curr_thread->next = th;
415
/* Fork the new thread */
417
CreateThread(NULL, 0, caml_thread_start, (void *) th, 0, &th_id);
418
if (th->wthread == NULL) {
419
/* Fork failed, remove thread info block from list of threads */
420
th->next->prev = curr_thread;
421
curr_thread->next = th->next;
423
stat_free(th->stack_low);
426
caml_wthread_error("Thread.create");
428
((struct caml_thread_handle *)vthread)->handle = th->wthread;
433
/* Return the current thread */
435
CAMLprim value caml_thread_self(value unit)
437
if (curr_thread == NULL) invalid_argument("Thread.self: not initialized");
438
return curr_thread->descr;
441
/* Return the identifier of a thread */
443
CAMLprim value caml_thread_id(value th)
448
/* Print uncaught exception and backtrace */
450
CAMLprim value caml_thread_uncaught_exception(value exn)
452
char * msg = format_caml_exception(exn);
453
fprintf(stderr, "Thread %d killed on uncaught exception %s\n",
454
Int_val(Ident(curr_thread->descr)), msg);
457
if (backtrace_active) print_exception_backtrace();
463
/* Allow re-scheduling */
465
CAMLprim value caml_thread_yield(value unit)
467
enter_blocking_section();
469
leave_blocking_section();
473
/* Suspend the current thread until another thread terminates */
475
CAMLprim value caml_thread_join(value th)
479
Begin_root(th) /* prevent deallocation of handle */
480
h = Threadhandle(th)->handle;
481
enter_blocking_section();
482
WaitForSingleObject(h, INFINITE);
483
leave_blocking_section();
488
/* Mutex operations */
490
#define Mutex_val(v) (*((HANDLE *) Data_custom_val(v)))
491
#define Max_mutex_number 1000
493
static void caml_mutex_finalize(value mut)
495
CloseHandle(Mutex_val(mut));
498
static int caml_mutex_compare(value wrapper1, value wrapper2)
500
HANDLE h1 = Mutex_val(wrapper1);
501
HANDLE h2 = Mutex_val(wrapper2);
502
return h1 == h2 ? 0 : h1 < h2 ? -1 : 1;
505
static struct custom_operations caml_mutex_ops = {
510
custom_serialize_default,
511
custom_deserialize_default
514
CAMLprim value caml_mutex_new(value unit)
517
mut = alloc_custom(&caml_mutex_ops, sizeof(HANDLE), 1, Max_mutex_number);
518
Mutex_val(mut) = CreateMutex(0, FALSE, NULL);
519
if (Mutex_val(mut) == NULL) caml_wthread_error("Mutex.create");
523
CAMLprim value caml_mutex_lock(value mut)
526
/* PR#4351: first try to acquire mutex without releasing the master lock */
527
retcode = WaitForSingleObject(Mutex_val(mut), 0);
528
if (retcode == WAIT_OBJECT_0) return Val_unit;
529
Begin_root(mut) /* prevent deallocation of mutex */
530
enter_blocking_section();
531
retcode = WaitForSingleObject(Mutex_val(mut), INFINITE);
532
leave_blocking_section();
534
if (retcode == WAIT_FAILED) caml_wthread_error("Mutex.lock");
538
CAMLprim value caml_mutex_unlock(value mut)
541
/* PR#4351: no need to release and reacquire master lock */
542
retcode = ReleaseMutex(Mutex_val(mut));
543
if (!retcode) caml_wthread_error("Mutex.unlock");
547
CAMLprim value caml_mutex_try_lock(value mut)
550
retcode = WaitForSingleObject(Mutex_val(mut), 0);
551
if (retcode == WAIT_FAILED || retcode == WAIT_ABANDONED)
552
caml_wthread_error("Mutex.try_lock");
553
return Val_bool(retcode == WAIT_OBJECT_0);
558
CAMLprim value caml_thread_delay(value val)
560
enter_blocking_section();
561
Sleep((DWORD)(Double_val(val)*1000)); /* milliseconds */
562
leave_blocking_section();
566
/* Conditions operations */
568
struct caml_condvar {
569
uintnat count; /* Number of waiting threads */
570
HANDLE sem; /* Semaphore on which threads are waiting */
573
#define Condition_val(v) ((struct caml_condvar *) Data_custom_val(v))
574
#define Max_condition_number 1000
576
static void caml_condition_finalize(value cond)
578
CloseHandle(Condition_val(cond)->sem);
581
static int caml_condition_compare(value wrapper1, value wrapper2)
583
HANDLE h1 = Condition_val(wrapper1)->sem;
584
HANDLE h2 = Condition_val(wrapper2)->sem;
585
return h1 == h2 ? 0 : h1 < h2 ? -1 : 1;
588
static struct custom_operations caml_condition_ops = {
590
caml_condition_finalize,
591
caml_condition_compare,
593
custom_serialize_default,
594
custom_deserialize_default
597
CAMLprim value caml_condition_new(value unit)
600
cond = alloc_custom(&caml_condition_ops, sizeof(struct caml_condvar),
601
1, Max_condition_number);
602
Condition_val(cond)->sem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
603
if (Condition_val(cond)->sem == NULL)
604
caml_wthread_error("Condition.create");
605
Condition_val(cond)->count = 0;
609
CAMLprim value caml_condition_wait(value cond, value mut)
612
HANDLE m = Mutex_val(mut);
613
HANDLE s = Condition_val(cond)->sem;
616
Condition_val(cond)->count ++;
617
Begin_roots2(cond, mut) /* prevent deallocation of cond and mutex */
618
enter_blocking_section();
621
/* Wait for semaphore to be non-null, and decrement it.
622
Simultaneously, re-acquire mutex. */
625
retcode = WaitForMultipleObjects(2, handles, TRUE, INFINITE);
626
leave_blocking_section();
628
if (retcode == WAIT_FAILED) caml_wthread_error("Condition.wait");
632
CAMLprim value caml_condition_signal(value cond)
634
HANDLE s = Condition_val(cond)->sem;
636
if (Condition_val(cond)->count > 0) {
637
Condition_val(cond)->count --;
638
/* Increment semaphore by 1, waking up one waiter */
639
ReleaseSemaphore(s, 1, NULL);
644
CAMLprim value caml_condition_broadcast(value cond)
646
HANDLE s = Condition_val(cond)->sem;
647
uintnat c = Condition_val(cond)->count;
650
Condition_val(cond)->count = 0;
651
/* Increment semaphore by c, waking up all waiters */
652
ReleaseSemaphore(s, c, NULL);
659
static void caml_wthread_error(char * msg)
662
sprintf(errmsg, "%s: error code %lx", msg, GetLastError());
663
raise_sys_error(copy_string(errmsg));