Use thread priority at thread start time (#3123)
[mono.git] / mono / utils / mono-threads.h
1 /*
2  * mono-threads.h: Low-level threading
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * (C) 2011 Novell, Inc
8  */
9
10 #ifndef __MONO_THREADS_H__
11 #define __MONO_THREADS_H__
12
13 #include <mono/utils/mono-os-semaphore.h>
14 #include <mono/utils/mono-stack-unwinding.h>
15 #include <mono/utils/mono-linked-list-set.h>
16 #include <mono/utils/mono-tls.h>
17 #include <mono/utils/mono-coop-semaphore.h>
18
19 #include <mono/io-layer/io-layer.h>
20
21 #include <glib.h>
22 #include <config.h>
23 #ifdef HOST_WIN32
24
25 #include <windows.h>
26
27 typedef DWORD MonoNativeThreadId;
28 typedef HANDLE MonoNativeThreadHandle; /* unused */
29
30 typedef DWORD mono_native_thread_return_t;
31
32 #define MONO_NATIVE_THREAD_ID_TO_UINT(tid) (tid)
33 #define MONO_UINT_TO_NATIVE_THREAD_ID(tid) ((MonoNativeThreadId)(tid))
34
35 #else
36
37 #include <pthread.h>
38
39 #if defined(__MACH__)
40 #include <mono/utils/mach-support.h>
41
42 typedef thread_port_t MonoNativeThreadHandle;
43
44 #else
45
46 #include <unistd.h>
47
48 typedef pid_t MonoNativeThreadHandle;
49
50 #endif /* defined(__MACH__) */
51
52 typedef pthread_t MonoNativeThreadId;
53
54 typedef void* mono_native_thread_return_t;
55
56 #define MONO_NATIVE_THREAD_ID_TO_UINT(tid) (gsize)(tid)
57 #define MONO_UINT_TO_NATIVE_THREAD_ID(tid) (MonoNativeThreadId)(gsize)(tid)
58
59 #endif /* #ifdef HOST_WIN32 */
60
61 /*
62 THREAD_INFO_TYPE is a way to make the mono-threads module parametric - or sort of.
63 The GC using mono-threads might extend the MonoThreadInfo struct to add its own
64 data, this avoid a pointer indirection on what is on a lot of hot paths.
65
66 But extending MonoThreadInfo has de disavantage that all functions here return type
67 would require a cast, something like the following:
68
69 typedef struct {
70         MonoThreadInfo info;
71         int stuff;
72 }  MyThreadInfo;
73
74 ...
75 ((MyThreadInfo*)mono_thread_info_current ())->stuff = 1;
76
77 While porting sgen to use mono-threads, the number of casts required was too much and
78 code ended up looking horrible. So we use this cute little hack. The idea is that
79 whomever is including this header can set the expected type to be used by functions here
80 and reduce the number of casts drastically.
81
82 */
83 #ifndef THREAD_INFO_TYPE
84 #define THREAD_INFO_TYPE MonoThreadInfo
85 #endif
86
87 /* Mono Threads internal configuration knows*/
88
89 /* Logging - enable them below if you need specific logging for the category you need */
90 #define MOSTLY_ASYNC_SAFE_PRINTF(...) do { \
91         char __buff[1024];      __buff [0] = '\0'; \
92         g_snprintf (__buff, sizeof (__buff), __VA_ARGS__);      \
93         write (1, __buff, strlen (__buff));     \
94 } while (0)
95
96
97 #if 1
98 #define THREADS_DEBUG(...)
99 #else
100 #define THREADS_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
101 #endif
102
103 #if 1
104 #define THREADS_STW_DEBUG(...)
105 #else
106 #define THREADS_STW_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
107 #endif
108
109 #if 1
110 #define THREADS_SUSPEND_DEBUG(...)
111 #else
112 #define THREADS_SUSPEND_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
113 #endif
114
115 #if 1
116 #define THREADS_STATE_MACHINE_DEBUG(...)
117 #else
118 #define THREADS_STATE_MACHINE_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
119 #endif
120
121 #if 1
122 #define THREADS_INTERRUPT_DEBUG(...)
123 #else
124 #define THREADS_INTERRUPT_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
125 #endif
126
127 /* If this is defined, use the signals backed on Mach. Debug only as signals can't be made usable on OSX. */
128 // #define USE_SIGNALS_ON_MACH
129
130 #if defined (_POSIX_VERSION) || defined (__native_client__)
131 #if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
132 #define USE_MACH_BACKEND
133 #else
134 #define USE_POSIX_BACKEND
135 #endif
136 #elif HOST_WIN32
137 #define USE_WINDOWS_BACKEND
138 #else
139 #error "no backend support for current platform"
140 #endif /* defined (_POSIX_VERSION) || defined (__native_client__) */
141
142 enum {
143         STATE_STARTING                          = 0x00,
144         STATE_RUNNING                           = 0x01,
145         STATE_DETACHED                          = 0x02,
146
147         STATE_ASYNC_SUSPENDED                   = 0x03,
148         STATE_SELF_SUSPENDED                    = 0x04,
149         STATE_ASYNC_SUSPEND_REQUESTED   = 0x05,
150         STATE_SELF_SUSPEND_REQUESTED    = 0x06,
151         STATE_BLOCKING                                  = 0x07,
152         STATE_BLOCKING_AND_SUSPENDED    = 0x8,
153
154         STATE_MAX                                               = 0x08,
155
156         THREAD_STATE_MASK                       = 0x00FF,
157         THREAD_SUSPEND_COUNT_MASK       = 0xFF00,
158         THREAD_SUSPEND_COUNT_SHIFT      = 8,
159         THREAD_SUSPEND_COUNT_MAX        = 0xFF,
160
161         SELF_SUSPEND_STATE_INDEX = 0,
162         ASYNC_SUSPEND_STATE_INDEX = 1,
163 };
164
165 typedef struct _MonoThreadInfoInterruptToken MonoThreadInfoInterruptToken;
166
167 typedef struct {
168         MonoLinkedListSetNode node;
169         guint32 small_id; /*Used by hazard pointers */
170         MonoNativeThreadHandle native_handle; /* Valid on mach and android */
171         int thread_state;
172
173         /*Tells if this thread was created by the runtime or not.*/
174         gboolean runtime_thread;
175
176         /* Tells if this thread should be ignored or not by runtime services such as GC and profiling */
177         gboolean tools_thread;
178
179         /* Max stack bounds, all valid addresses must be between [stack_start_limit, stack_end[ */
180         void *stack_start_limit, *stack_end;
181
182         /* suspend machinery, fields protected by suspend_semaphore */
183         MonoSemType suspend_semaphore;
184         int suspend_count;
185
186         MonoSemType resume_semaphore;
187
188         /* only needed by the posix backend */
189 #if defined(USE_POSIX_BACKEND)
190         MonoSemType finish_resume_semaphore;
191         gboolean syscall_break_signal;
192         int signal;
193 #endif
194
195         gboolean suspend_can_continue;
196
197         /* This memory pool is used by coop GC to save stack data roots between GC unsafe regions */
198         GByteArray *stackdata;
199
200         /*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/
201         MonoThreadUnwindState thread_saved_state [2]; //0 is self suspend, 1 is async suspend.
202
203         /*async call machinery, thread MUST be suspended before accessing those fields*/
204         void (*async_target)(void*);
205         void *user_data;
206
207         /*
208         If true, this thread is running a critical region of code and cannot be suspended.
209         A critical session is implicitly started when you call mono_thread_info_safe_suspend_sync
210         and is ended when you call either mono_thread_info_resume or mono_thread_info_finish_suspend.
211         */
212         gboolean inside_critical_region;
213
214         /*
215          * If TRUE, the thread is in async context. Code can use this information to avoid async-unsafe
216          * operations like locking without having to pass an 'async' parameter around.
217          */
218         gboolean is_async_context;
219
220         gboolean create_suspended;
221
222         /* Semaphore used to implement CREATE_SUSPENDED */
223         MonoCoopSem create_suspended_sem;
224
225         /*
226          * Values of TLS variables for this thread.
227          * This can be used to obtain the values of TLS variable for threads
228          * other than the current one.
229          */
230         gpointer tls [TLS_KEY_NUM];
231
232         /* IO layer handle for this thread */
233         /* Set when the thread is started, or in _wapi_thread_duplicate () */
234         HANDLE handle;
235
236         void *jit_data;
237
238         MonoThreadInfoInterruptToken *interrupt_token;
239
240         /* HandleStack for coop handles */
241         gpointer handle_stack;
242
243         /* Stack mark for targets that explicitly require one */
244         gpointer stack_mark;
245 } MonoThreadInfo;
246
247 typedef struct {
248         void* (*thread_register)(THREAD_INFO_TYPE *info, void *baseaddr);
249         /*
250         This callback is called with @info still on the thread list.
251         This call is made while holding the suspend lock, so don't do callbacks.
252         SMR remains functional as its small_id has not been reclaimed.
253         */
254         void (*thread_unregister)(THREAD_INFO_TYPE *info);
255         /*
256         This callback is called right before thread_unregister. This is called
257         without any locks held so it's the place for complicated cleanup.
258
259         The thread must remain operational between this call and thread_unregister.
260         It must be possible to successfully suspend it after thread_unregister completes.
261         */
262         void (*thread_detach)(THREAD_INFO_TYPE *info);
263         void (*thread_attach)(THREAD_INFO_TYPE *info);
264         gboolean (*mono_method_is_critical) (void *method);
265         gboolean (*mono_thread_in_critical_region) (THREAD_INFO_TYPE *info);
266 } MonoThreadInfoCallbacks;
267
268 typedef struct {
269         void (*setup_async_callback) (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data);
270         gboolean (*thread_state_init_from_sigctx) (MonoThreadUnwindState *state, void *sigctx);
271         gboolean (*thread_state_init_from_handle) (MonoThreadUnwindState *tctx, MonoThreadInfo *info);
272         void (*thread_state_init) (MonoThreadUnwindState *tctx);
273 } MonoThreadInfoRuntimeCallbacks;
274
275 //Not using 0 and 1 to ensure callbacks are not returning bad data
276 typedef enum {
277         MonoResumeThread = 0x1234,
278         KeepSuspended = 0x4321,
279 } SuspendThreadResult;
280
281 typedef SuspendThreadResult (*MonoSuspendThreadCallback) (THREAD_INFO_TYPE *info, gpointer user_data);
282
283 /*
284  * Parameters to pass for thread creation
285  */
286 typedef struct {
287         int priority;
288         guint32 creation_flags; 
289         guint32 stack_size;             
290 } MonoThreadParm;
291
292 static inline gboolean
293 mono_threads_filter_tools_threads (THREAD_INFO_TYPE *info)
294 {
295         return !((MonoThreadInfo*)info)->tools_thread;
296 }
297
298 /*
299 Requires the world to be stoped
300 */
301 #define FOREACH_THREAD(thread) \
302         MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_tools_threads)
303
304 #define FOREACH_THREAD_END \
305         MONO_LLS_FOREACH_END
306
307 /*
308 Snapshot iteration.
309 */
310 #define FOREACH_THREAD_SAFE(thread) \
311         MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_tools_threads)
312
313 #define FOREACH_THREAD_SAFE_END \
314         MONO_LLS_FOREACH_SAFE_END
315
316 static inline MonoNativeThreadId
317 mono_thread_info_get_tid (THREAD_INFO_TYPE *info)
318 {
319         return MONO_UINT_TO_NATIVE_THREAD_ID (((MonoThreadInfo*) info)->node.key);
320 }
321
322 static inline void
323 mono_thread_info_set_tid (THREAD_INFO_TYPE *info, MonoNativeThreadId tid)
324 {
325         ((MonoThreadInfo*) info)->node.key = (uintptr_t) MONO_NATIVE_THREAD_ID_TO_UINT (tid);
326 }
327
328 /*
329  * @thread_info_size is sizeof (GcThreadInfo), a struct the GC defines to make it possible to have
330  * a single block with info from both camps. 
331  */
332 void
333 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t thread_info_size);
334
335 void
336 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks);
337
338 MonoThreadInfoRuntimeCallbacks *
339 mono_threads_get_runtime_callbacks (void);
340
341 int
342 mono_thread_info_register_small_id (void);
343
344 THREAD_INFO_TYPE *
345 mono_thread_info_attach (void *baseptr);
346
347 MONO_API void
348 mono_thread_info_detach (void);
349
350 gboolean
351 mono_thread_info_is_exiting (void);
352
353 THREAD_INFO_TYPE *
354 mono_thread_info_current (void);
355
356 THREAD_INFO_TYPE*
357 mono_thread_info_current_unchecked (void);
358
359 int
360 mono_thread_info_get_small_id (void);
361
362 MonoLinkedListSet*
363 mono_thread_info_list_head (void);
364
365 THREAD_INFO_TYPE*
366 mono_thread_info_lookup (MonoNativeThreadId id);
367
368 gboolean
369 mono_thread_info_resume (MonoNativeThreadId tid);
370
371 void
372 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data);
373
374 //XXX new API, fix the world
375 void
376 mono_thread_info_begin_self_suspend (void);
377
378 void
379 mono_thread_info_end_self_suspend (void);
380
381 //END of new API
382
383 gboolean
384 mono_thread_info_unified_management_enabled (void);
385
386 void
387 mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data);
388
389 void
390 mono_thread_info_suspend_lock (void);
391
392 void
393 mono_thread_info_suspend_unlock (void);
394
395 void
396 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid);
397
398 void
399 mono_thread_info_set_is_async_context (gboolean async_context);
400
401 gboolean
402 mono_thread_info_is_async_context (void);
403
404 void
405 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize);
406
407 gboolean
408 mono_thread_info_yield (void);
409
410 gint
411 mono_thread_info_sleep (guint32 ms, gboolean *alerted);
412
413 gint
414 mono_thread_info_usleep (guint64 us);
415
416 gpointer
417 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key);
418
419 void
420 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value);
421
422 void
423 mono_thread_info_exit (void);
424
425 HANDLE
426 mono_thread_info_open_handle (void);
427
428 void
429 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted);
430
431 void
432 mono_thread_info_uninstall_interrupt (gboolean *interrupted);
433
434 MonoThreadInfoInterruptToken*
435 mono_thread_info_prepare_interrupt (THREAD_INFO_TYPE *info);
436
437 void
438 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token);
439
440 void
441 mono_thread_info_self_interrupt (void);
442
443 void
444 mono_thread_info_clear_self_interrupt (void);
445
446 gboolean
447 mono_thread_info_is_interrupt_state (THREAD_INFO_TYPE *info);
448
449 void
450 mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE *info, GString *text);
451
452 gboolean
453 mono_thread_info_is_live (THREAD_INFO_TYPE *info);
454
455 HANDLE
456 mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid);
457
458 int
459 mono_threads_get_max_stack_size (void);
460
461 HANDLE
462 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
463
464 MONO_API void
465 mono_threads_attach_tools_thread (void);
466
467
468 #if !defined(HOST_WIN32)
469
470 /*Use this instead of pthread_kill */
471 int
472 mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum);
473
474 #endif /* !defined(HOST_WIN32) */
475
476 /* Internal API between mono-threads and its backends. */
477
478 /* Backend functions - a backend must implement all of the following */
479 /*
480 This is called very early in the runtime, it cannot access any runtime facilities.
481
482 */
483 void mono_threads_init_platform (void); //ok
484
485 void mono_threads_init_coop (void);
486
487 void mono_threads_init_abort_syscall (void);
488
489 /*
490 This begins async suspend. This function must do the following:
491
492 -Ensure the target will EINTR any syscalls if @interrupt_kernel is true
493 -Call mono_threads_transition_finish_async_suspend as part of its async suspend.
494 -Register the thread for pending suspend with mono_threads_add_to_pending_operation_set if needed.
495
496 If begin suspend fails the thread must be left uninterrupted and resumed.
497 */
498 gboolean mono_threads_core_begin_async_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
499
500 /*
501 This verifies the outcome of an async suspend operation.
502
503 Some targets, such as posix, verify suspend results assynchronously. Suspend results must be
504 available (in a non blocking way) after mono_threads_wait_pending_operations completes.
505 */
506 gboolean mono_threads_core_check_suspend_result (THREAD_INFO_TYPE *info);
507
508 /*
509 This begins async resume. This function must do the following:
510
511 - Install an async target if one was requested.
512 - Notify the target to resume.
513 - Register the thread for pending ack with mono_threads_add_to_pending_operation_set if needed.
514 */
515 gboolean mono_threads_core_begin_async_resume (THREAD_INFO_TYPE *info);
516
517 void mono_threads_platform_register (THREAD_INFO_TYPE *info); //ok
518 void mono_threads_platform_free (THREAD_INFO_TYPE *info);
519 void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info);
520 gboolean mono_threads_core_needs_abort_syscall (void);
521 HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, MonoThreadParm *, MonoNativeThreadId *out_tid);
522 void mono_threads_core_resume_created (THREAD_INFO_TYPE *info, MonoNativeThreadId tid);
523 void mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize);
524 gboolean mono_threads_core_yield (void);
525 void mono_threads_core_exit (int exit_code);
526 void mono_threads_core_unregister (THREAD_INFO_TYPE *info);
527 HANDLE mono_threads_core_open_handle (void);
528 HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
529
530 void mono_threads_coop_begin_global_suspend (void);
531 void mono_threads_coop_end_global_suspend (void);
532
533 MONO_API MonoNativeThreadId
534 mono_native_thread_id_get (void);
535
536 gboolean
537 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2);
538
539 gboolean
540 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg);
541
542 MONO_API void
543 mono_native_thread_set_name (MonoNativeThreadId tid, const char *name);
544
545 /*Mach specific internals */
546 void mono_threads_init_dead_letter (void);
547 void mono_threads_install_dead_letter (void);
548
549 /* mono-threads internal API used by the backends. */
550 /*
551 This tells the suspend initiator that we completed suspend and will now be waiting for resume.
552 */
553 void mono_threads_notify_initiator_of_suspend (THREAD_INFO_TYPE* info);
554 /*
555 This tells the resume initiator that we completed resume duties and will return to runnable state.
556 */
557 void mono_threads_notify_initiator_of_resume (THREAD_INFO_TYPE* info);
558
559 /*
560 This tells the resume initiator that we completed abort duties and will return to previous state.
561 */
562 void mono_threads_notify_initiator_of_abort (THREAD_INFO_TYPE* info);
563
564 /* Thread state machine functions */
565
566 typedef enum {
567         ResumeError,
568         ResumeOk,
569         ResumeInitSelfResume,
570         ResumeInitAsyncResume,
571         ResumeInitBlockingResume,
572 } MonoResumeResult;
573
574 typedef enum {
575         SelfSuspendResumed,
576         SelfSuspendWait,
577         SelfSuspendNotifyAndWait,
578 } MonoSelfSupendResult;
579
580 typedef enum {
581         AsyncSuspendAlreadySuspended,
582         AsyncSuspendWait,
583         AsyncSuspendInitSuspend,
584         AsyncSuspendBlocking,
585 } MonoRequestAsyncSuspendResult;
586
587 typedef enum {
588         DoBlockingContinue, //in blocking mode, continue
589         DoBlockingPollAndRetry, //async suspend raced blocking and won, pool and retry
590 } MonoDoBlockingResult;
591
592 typedef enum {
593         DoneBlockingOk, //exited blocking fine
594         DoneBlockingWait, //thread should end suspended
595 } MonoDoneBlockingResult;
596
597
598 typedef enum {
599         AbortBlockingIgnore, //Ignore
600         AbortBlockingIgnoreAndPoll, //Ignore and poll
601         AbortBlockingOk, //Abort worked
602         AbortBlockingWait, //Abort worked, but should wait for resume
603 } MonoAbortBlockingResult;
604
605
606 void mono_threads_transition_attach (THREAD_INFO_TYPE* info);
607 gboolean mono_threads_transition_detach (THREAD_INFO_TYPE *info);
608 void mono_threads_transition_request_self_suspension (THREAD_INFO_TYPE *info);
609 MonoRequestAsyncSuspendResult mono_threads_transition_request_async_suspension (THREAD_INFO_TYPE *info);
610 MonoSelfSupendResult mono_threads_transition_state_poll (THREAD_INFO_TYPE *info);
611 MonoResumeResult mono_threads_transition_request_resume (THREAD_INFO_TYPE* info);
612 gboolean mono_threads_transition_finish_async_suspend (THREAD_INFO_TYPE* info);
613 MonoDoBlockingResult mono_threads_transition_do_blocking (THREAD_INFO_TYPE* info);
614 MonoDoneBlockingResult mono_threads_transition_done_blocking (THREAD_INFO_TYPE* info);
615 MonoAbortBlockingResult mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info);
616
617 MonoThreadUnwindState* mono_thread_info_get_suspend_state (THREAD_INFO_TYPE *info);
618
619 gpointer
620 mono_threads_enter_gc_unsafe_region_cookie (void);
621
622
623 void mono_thread_info_wait_for_resume (THREAD_INFO_TYPE *info);
624 /* Advanced suspend API, used for suspending multiple threads as once. */
625 gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info);
626 gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info);
627 int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info);
628 int mono_thread_info_current_state (THREAD_INFO_TYPE *info);
629 const char* mono_thread_state_name (int state);
630
631 gboolean mono_thread_info_in_critical_location (THREAD_INFO_TYPE *info);
632 gboolean mono_thread_info_begin_suspend (THREAD_INFO_TYPE *info);
633 gboolean mono_thread_info_begin_resume (THREAD_INFO_TYPE *info);
634
635 void mono_threads_add_to_pending_operation_set (THREAD_INFO_TYPE* info); //XXX rename to something to reflect the fact that this is used for both suspend and resume
636 gboolean mono_threads_wait_pending_operations (void);
637 void mono_threads_begin_global_suspend (void);
638 void mono_threads_end_global_suspend (void);
639
640 gboolean
641 mono_thread_info_is_current (THREAD_INFO_TYPE *info);
642
643 #endif /* __MONO_THREADS_H__ */