Revert some changes which don't have proper dependencies.
[mono-project.git] / mono / utils / mono-threads.h
blob532928282914f1e7a8359612581f5e9ff9bb159c
1 /**
2 * \file
3 * Low-level threading
5 * Author:
6 * Rodrigo Kumpera (kumpera@gmail.com)
8 * (C) 2011 Novell, Inc
9 */
11 #ifndef __MONO_THREADS_H__
12 #define __MONO_THREADS_H__
14 #include <mono/utils/mono-forward-internal.h>
15 #include <mono/utils/mono-os-semaphore.h>
16 #include <mono/utils/mono-stack-unwinding.h>
17 #include <mono/utils/mono-linked-list-set.h>
18 #include <mono/utils/lock-free-alloc.h>
19 #include <mono/utils/lock-free-queue.h>
20 #include <mono/utils/mono-tls.h>
21 #include <mono/utils/mono-coop-semaphore.h>
22 #include <mono/utils/os-event.h>
23 #include <mono/utils/refcount.h>
25 #include <glib.h>
26 #include <config.h>
27 #ifdef HOST_WIN32
29 #include <windows.h>
31 typedef DWORD MonoNativeThreadId;
32 typedef HANDLE MonoNativeThreadHandle; /* unused */
34 typedef DWORD mono_native_thread_return_t;
35 typedef DWORD mono_thread_start_return_t;
37 #define MONO_NATIVE_THREAD_ID_TO_UINT(tid) (tid)
38 #define MONO_UINT_TO_NATIVE_THREAD_ID(tid) ((MonoNativeThreadId)(tid))
40 typedef LPTHREAD_START_ROUTINE MonoThreadStart;
42 #else
44 #include <pthread.h>
46 #if defined(__MACH__)
47 #include <mono/utils/mach-support.h>
49 typedef thread_port_t MonoNativeThreadHandle;
51 #else
53 #include <unistd.h>
55 typedef pid_t MonoNativeThreadHandle;
57 #endif /* defined(__MACH__) */
59 typedef pthread_t MonoNativeThreadId;
61 typedef void* mono_native_thread_return_t;
62 typedef gsize mono_thread_start_return_t;
64 #define MONO_NATIVE_THREAD_ID_TO_UINT(tid) (gsize)(tid)
65 #define MONO_UINT_TO_NATIVE_THREAD_ID(tid) (MonoNativeThreadId)(gsize)(tid)
67 typedef gsize (*MonoThreadStart)(gpointer);
69 #if !defined(__HAIKU__)
70 #define MONO_THREADS_PLATFORM_HAS_ATTR_SETSCHED
71 #endif /* !defined(__HAIKU__) */
73 #endif /* #ifdef HOST_WIN32 */
75 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF)
77 typedef struct {
78 MonoRefCount ref;
79 MonoOSEvent event;
80 } MonoThreadHandle;
83 THREAD_INFO_TYPE is a way to make the mono-threads module parametric - or sort of.
84 The GC using mono-threads might extend the MonoThreadInfo struct to add its own
85 data, this avoid a pointer indirection on what is on a lot of hot paths.
87 But extending MonoThreadInfo has de disavantage that all functions here return type
88 would require a cast, something like the following:
90 typedef struct {
91 MonoThreadInfo info;
92 int stuff;
93 } MyThreadInfo;
95 ...
96 ((MyThreadInfo*)mono_thread_info_current ())->stuff = 1;
98 While porting sgen to use mono-threads, the number of casts required was too much and
99 code ended up looking horrible. So we use this cute little hack. The idea is that
100 whomever is including this header can set the expected type to be used by functions here
101 and reduce the number of casts drastically.
104 #ifndef THREAD_INFO_TYPE
105 #define THREAD_INFO_TYPE MonoThreadInfo
106 #endif
108 /* Mono Threads internal configuration knows*/
110 /* If this is defined, use the signals backed on Mach. Debug only as signals can't be made usable on OSX. */
111 // #define USE_SIGNALS_ON_MACH
113 #ifdef HOST_WASM
114 #define USE_WASM_BACKEND
115 #elif defined (_POSIX_VERSION)
116 #if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
117 #define USE_MACH_BACKEND
118 #else
119 #define USE_POSIX_BACKEND
120 #endif
121 #elif HOST_WIN32
122 #define USE_WINDOWS_BACKEND
123 #else
124 #error "no backend support for current platform"
125 #endif /* defined (_POSIX_VERSION) */
127 enum {
128 STATE_STARTING = 0x00,
129 STATE_DETACHED = 0x01,
131 STATE_RUNNING = 0x02,
132 STATE_ASYNC_SUSPENDED = 0x03,
133 STATE_SELF_SUSPENDED = 0x04,
134 STATE_ASYNC_SUSPEND_REQUESTED = 0x05,
136 STATE_BLOCKING = 0x06,
137 STATE_BLOCKING_ASYNC_SUSPENDED = 0x07,
138 /* FIXME: All the transitions from STATE_SELF_SUSPENDED and
139 * STATE_BLOCKING_SELF_SUSPENDED are the same - they should be the same
140 * state. */
141 STATE_BLOCKING_SELF_SUSPENDED = 0x08,
142 STATE_BLOCKING_SUSPEND_REQUESTED = 0x09,
144 STATE_MAX = 0x09,
146 THREAD_STATE_MASK = 0x007F,
147 THREAD_SUSPEND_COUNT_MASK = 0xFF00,
148 THREAD_SUSPEND_COUNT_SHIFT = 8,
149 THREAD_SUSPEND_COUNT_MAX = 0xFF,
151 THREAD_SUSPEND_NO_SAFEPOINTS_MASK = 0x0080,
152 THREAD_SUSPEND_NO_SAFEPOINTS_SHIFT = 7,
154 SELF_SUSPEND_STATE_INDEX = 0,
155 ASYNC_SUSPEND_STATE_INDEX = 1,
159 * These flags control how the rest of the runtime will see and interact with
160 * a thread.
162 typedef enum {
164 * No flags means it's a normal thread that takes part in all runtime
165 * functionality.
167 MONO_THREAD_INFO_FLAGS_NONE = 0,
169 * The thread will not be suspended by the STW machinery. The thread is not
170 * allowed to allocate or access managed memory at all, nor execute managed
171 * code.
173 MONO_THREAD_INFO_FLAGS_NO_GC = 1,
175 * The thread will not be subject to profiler sampling signals.
177 MONO_THREAD_INFO_FLAGS_NO_SAMPLE = 2,
178 } MonoThreadInfoFlags;
180 G_ENUM_FUNCTIONS (MonoThreadInfoFlags)
182 typedef struct _MonoThreadInfoInterruptToken MonoThreadInfoInterruptToken;
184 typedef struct _MonoThreadInfo {
185 MonoLinkedListSetNode node;
186 guint32 small_id; /*Used by hazard pointers */
187 MonoNativeThreadHandle native_handle; /* Valid on mach, android and Windows */
188 int thread_state;
191 * Must not be changed directly, and especially not by other threads. Use
192 * mono_thread_info_get/set_flags () to manipulate this.
194 volatile gint32 flags;
196 /*Tells if this thread was created by the runtime or not.*/
197 gboolean runtime_thread;
199 /* Max stack bounds, all valid addresses must be between [stack_start_limit, stack_end[ */
200 void *stack_start_limit, *stack_end;
202 /* suspend machinery, fields protected by suspend_semaphore */
203 MonoSemType suspend_semaphore;
204 int suspend_count;
206 MonoSemType resume_semaphore;
208 /* only needed by the posix backend */
209 #if defined(USE_POSIX_BACKEND)
210 MonoSemType finish_resume_semaphore;
211 gboolean syscall_break_signal;
212 int signal;
213 #endif
215 gboolean suspend_can_continue;
217 /* This memory pool is used by coop GC to save stack data roots between GC unsafe regions */
218 GByteArray *stackdata;
220 /*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/
221 MonoThreadUnwindState thread_saved_state [2]; //0 is self suspend, 1 is async suspend.
223 /*async call machinery, thread MUST be suspended before accessing those fields*/
224 void (*async_target)(void*);
225 void *user_data;
228 If true, this thread is running a critical region of code and cannot be suspended.
229 A critical session is implicitly started when you call mono_thread_info_safe_suspend_sync
230 and is ended when you call either mono_thread_info_resume or mono_thread_info_finish_suspend.
232 gboolean inside_critical_region;
235 * If TRUE, the thread is in async context. Code can use this information to avoid async-unsafe
236 * operations like locking without having to pass an 'async' parameter around.
238 gboolean is_async_context;
241 * Values of TLS variables for this thread.
242 * This can be used to obtain the values of TLS variable for threads
243 * other than the current one.
245 gpointer tls [TLS_KEY_NUM];
247 /* IO layer handle for this thread */
248 /* Set when the thread is started, or in _wapi_thread_duplicate () */
249 MonoThreadHandle *handle;
251 MonoJitTlsData *jit_data;
253 MonoThreadInfoInterruptToken *interrupt_token;
255 /* HandleStack for coop handles */
256 MonoHandleStack *handle_stack;
258 /* Stack mark for targets that explicitly require one */
259 gpointer stack_mark;
261 /* GCHandle to MonoInternalThread */
262 guint32 internal_thread_gchandle;
265 * Used by the sampling code in mini-posix.c to ensure that a thread has
266 * handled a sampling signal before sending another one.
268 gint32 profiler_signal_ack;
270 #ifdef USE_WINDOWS_BACKEND
271 gint32 win32_apc_info;
272 gpointer win32_apc_info_io_handle;
273 #endif
276 * This is where we store tools tls data so it follows our lifecycle and doesn't depends on posix tls cleanup ordering
278 * TODO support multiple values by multiple tools
280 void *tools_data;
281 } MonoThreadInfo;
283 typedef struct {
284 void* (*thread_attach)(THREAD_INFO_TYPE *info);
286 This callback is called right before thread_detach_with_lock. This is called
287 without any locks held so it's the place for complicated cleanup.
289 The thread must remain operational between this call and thread_detach_with_lock.
290 It must be possible to successfully suspend it after thread_detach completes.
292 void (*thread_detach)(THREAD_INFO_TYPE *info);
294 This callback is called with @info still on the thread list.
295 This call is made while holding the suspend lock, so don't do callbacks.
296 SMR remains functional as its small_id has not been reclaimed.
298 void (*thread_detach_with_lock)(THREAD_INFO_TYPE *info);
299 gboolean (*ip_in_critical_region) (MonoDomain *domain, gpointer ip);
300 gboolean (*thread_in_critical_region) (THREAD_INFO_TYPE *info);
302 // Called on the affected thread.
303 void (*thread_flags_changing) (MonoThreadInfoFlags old, MonoThreadInfoFlags new_);
304 void (*thread_flags_changed) (MonoThreadInfoFlags old, MonoThreadInfoFlags new_);
305 } MonoThreadInfoCallbacks;
307 typedef struct {
308 void (*setup_async_callback) (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data);
309 gboolean (*thread_state_init_from_sigctx) (MonoThreadUnwindState *state, void *sigctx);
310 gboolean (*thread_state_init_from_handle) (MonoThreadUnwindState *tctx, MonoThreadInfo *info, /*optional*/ void *sigctx);
311 void (*thread_state_init) (MonoThreadUnwindState *tctx);
312 } MonoThreadInfoRuntimeCallbacks;
314 //Not using 0 and 1 to ensure callbacks are not returning bad data
315 typedef enum {
316 MonoResumeThread = 0x1234,
317 KeepSuspended = 0x4321,
318 } SuspendThreadResult;
320 typedef SuspendThreadResult (*MonoSuspendThreadCallback) (THREAD_INFO_TYPE *info, gpointer user_data);
322 MONO_API MonoThreadInfoFlags
323 mono_thread_info_get_flags (THREAD_INFO_TYPE *info);
326 * Sets the thread info flags for the current thread. This function may invoke
327 * callbacks containing arbitrary code (e.g. locks) so it must be assumed to be
328 * async unsafe.
330 MONO_API void
331 mono_thread_info_set_flags (MonoThreadInfoFlags flags);
333 static inline gboolean
334 mono_threads_filter_exclude_flags (THREAD_INFO_TYPE *info, MonoThreadInfoFlags flags)
336 return !(mono_thread_info_get_flags (info) & flags);
339 /* Normal iteration; requires the world to be stopped. */
341 #define FOREACH_THREAD_ALL(thread) \
342 MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_lls_filter_accept_all, NULL)
344 #define FOREACH_THREAD_EXCLUDE(thread, not_flags) \
345 MONO_LLS_FOREACH_FILTERED (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_exclude_flags, not_flags)
347 #define FOREACH_THREAD_END \
348 MONO_LLS_FOREACH_END
350 /* Snapshot iteration; can be done anytime but is slower. */
352 #define FOREACH_THREAD_SAFE_ALL(thread) \
353 MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_lls_filter_accept_all, NULL)
355 #define FOREACH_THREAD_SAFE_EXCLUDE(thread, not_flags) \
356 MONO_LLS_FOREACH_FILTERED_SAFE (mono_thread_info_list_head (), THREAD_INFO_TYPE, thread, mono_threads_filter_exclude_flags, not_flags)
358 #define FOREACH_THREAD_SAFE_END \
359 MONO_LLS_FOREACH_SAFE_END
361 static inline MonoNativeThreadId
362 mono_thread_info_get_tid (THREAD_INFO_TYPE *info)
364 return MONO_UINT_TO_NATIVE_THREAD_ID (((MonoThreadInfo*) info)->node.key);
367 static inline void
368 mono_thread_info_set_tid (THREAD_INFO_TYPE *info, MonoNativeThreadId tid)
370 ((MonoThreadInfo*) info)->node.key = (uintptr_t) MONO_NATIVE_THREAD_ID_TO_UINT (tid);
373 void
374 mono_thread_info_cleanup (void);
377 * @thread_info_size is sizeof (GcThreadInfo), a struct the GC defines to make it possible to have
378 * a single block with info from both camps.
380 void
381 mono_thread_info_init (size_t thread_info_size);
384 * Wait for the above mono_thread_info_init to be called
386 void
387 mono_thread_info_wait_inited (void);
389 void
390 mono_thread_info_callbacks_init (MonoThreadInfoCallbacks *callbacks);
392 void
393 mono_thread_info_signals_init (void);
395 void
396 mono_thread_info_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks);
398 MonoThreadInfoRuntimeCallbacks *
399 mono_threads_get_runtime_callbacks (void);
401 MONO_API int
402 mono_thread_info_register_small_id (void);
404 MONO_API THREAD_INFO_TYPE *
405 mono_thread_info_attach (void);
407 MONO_API void
408 mono_thread_info_detach (void);
410 gboolean
411 mono_thread_info_try_get_internal_thread_gchandle (THREAD_INFO_TYPE *info, guint32 *gchandle);
413 void
414 mono_thread_info_set_internal_thread_gchandle (THREAD_INFO_TYPE *info, guint32 gchandle);
416 void
417 mono_thread_info_unset_internal_thread_gchandle (THREAD_INFO_TYPE *info);
419 gboolean
420 mono_thread_info_is_exiting (void);
422 #ifdef HOST_WIN32
423 G_EXTERN_C // due to THREAD_INFO_TYPE varying
424 #endif
425 THREAD_INFO_TYPE *
426 mono_thread_info_current (void);
428 MONO_API gboolean
429 mono_thread_info_set_tools_data (void *data);
431 MONO_API void*
432 mono_thread_info_get_tools_data (void);
435 THREAD_INFO_TYPE*
436 mono_thread_info_current_unchecked (void);
438 MONO_API int
439 mono_thread_info_get_small_id (void);
441 MonoLinkedListSet*
442 mono_thread_info_list_head (void);
444 THREAD_INFO_TYPE*
445 mono_thread_info_lookup (MonoNativeThreadId id);
447 gboolean
448 mono_thread_info_resume (MonoNativeThreadId tid);
450 void
451 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data);
453 void
454 mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data);
456 void
457 mono_thread_info_suspend_lock (void);
459 void
460 mono_thread_info_suspend_unlock (void);
462 void
463 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid);
465 void
466 mono_thread_info_set_is_async_context (gboolean async_context);
468 gboolean
469 mono_thread_info_is_async_context (void);
471 void
472 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize);
474 MONO_API gboolean
475 mono_thread_info_yield (void);
477 gint
478 mono_thread_info_sleep (guint32 ms, gboolean *alerted);
480 gint
481 mono_thread_info_usleep (guint64 us);
483 gpointer
484 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key);
486 void
487 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value);
489 void
490 mono_thread_info_exit (gsize exit_code);
492 MONO_PAL_API void
493 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted);
495 MONO_PAL_API void
496 mono_thread_info_uninstall_interrupt (gboolean *interrupted);
498 MonoThreadInfoInterruptToken*
499 mono_thread_info_prepare_interrupt (THREAD_INFO_TYPE *info);
501 void
502 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token);
504 void
505 mono_thread_info_self_interrupt (void);
507 void
508 mono_thread_info_clear_self_interrupt (void);
510 gboolean
511 mono_thread_info_is_interrupt_state (THREAD_INFO_TYPE *info);
513 void
514 mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE *info, GString *text);
516 G_EXTERN_C // due to THREAD_INFO_TYPE varying
517 gboolean
518 mono_thread_info_is_live (THREAD_INFO_TYPE *info);
521 mono_thread_info_get_system_max_stack_size (void);
523 MonoThreadHandle*
524 mono_threads_open_thread_handle (MonoThreadHandle *handle);
526 void
527 mono_threads_close_thread_handle (MonoThreadHandle *handle);
529 #if !defined(HOST_WIN32)
531 /*Use this instead of pthread_kill */
533 mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum);
535 #endif /* !defined(HOST_WIN32) */
537 /* Internal API between mono-threads and its backends. */
539 /* Backend functions - a backend must implement all of the following */
541 This is called very early in the runtime, it cannot access any runtime facilities.
544 void mono_threads_suspend_init (void); //ok
546 void mono_threads_suspend_init_signals (void);
548 void mono_threads_coop_init (void);
551 This begins async suspend. This function must do the following:
553 -Ensure the target will EINTR any syscalls if @interrupt_kernel is true
554 -Call mono_threads_transition_finish_async_suspend as part of its async suspend.
555 -Register the thread for pending suspend with mono_threads_add_to_pending_operation_set if needed.
557 If begin suspend fails the thread must be left uninterrupted and resumed.
559 gboolean mono_threads_suspend_begin_async_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
562 This verifies the outcome of an async suspend operation.
564 Some targets, such as posix, verify suspend results assynchronously. Suspend results must be
565 available (in a non blocking way) after mono_threads_wait_pending_operations completes.
567 gboolean mono_threads_suspend_check_suspend_result (THREAD_INFO_TYPE *info);
570 This begins async resume. This function must do the following:
572 - Install an async target if one was requested.
573 - Notify the target to resume.
574 - Register the thread for pending ack with mono_threads_add_to_pending_operation_set if needed.
576 gboolean mono_threads_suspend_begin_async_resume (THREAD_INFO_TYPE *info);
578 void mono_threads_suspend_register (THREAD_INFO_TYPE *info); //ok
579 void mono_threads_suspend_free (THREAD_INFO_TYPE *info);
580 void mono_threads_suspend_abort_syscall (THREAD_INFO_TYPE *info);
581 gint mono_threads_suspend_search_alternative_signal (void);
582 gint mono_threads_suspend_get_suspend_signal (void);
583 gint mono_threads_suspend_get_restart_signal (void);
584 gint mono_threads_suspend_get_abort_signal (void);
586 gboolean
587 mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data,
588 gsize* const stack_size, MonoNativeThreadId *tid);
590 void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize);
591 gboolean mono_threads_platform_is_main_thread (void);
592 void mono_threads_platform_init (void);
593 gboolean mono_threads_platform_in_critical_region (THREAD_INFO_TYPE *info);
594 gboolean mono_threads_platform_yield (void);
595 void mono_threads_platform_exit (gsize exit_code);
597 void mono_threads_coop_begin_global_suspend (void);
598 void mono_threads_coop_end_global_suspend (void);
600 MONO_API MonoNativeThreadId
601 mono_native_thread_id_get (void);
603 MONO_API gboolean
604 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2);
606 //FIXMEcxx typedef mono_native_thread_return_t (MONO_STDCALL * MonoNativeThreadStart)(void*);
607 // mono_native_thread_return_t func
608 // and remove the template
610 MONO_API gboolean
611 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg);
613 #ifdef __cplusplus
614 template <typename T>
615 inline gboolean
616 mono_native_thread_create (MonoNativeThreadId *tid, T func, gpointer arg)
618 return mono_native_thread_create (tid, (gpointer)func, arg);
620 #endif
622 MONO_API void
623 mono_native_thread_set_name (MonoNativeThreadId tid, const char *name);
625 size_t
626 mono_native_thread_get_name (MonoNativeThreadId tid, char *name_out, size_t max_len);
628 MONO_API gboolean
629 mono_native_thread_join (MonoNativeThreadId tid);
631 /*Mach specific internals */
632 void mono_threads_init_dead_letter (void);
633 void mono_threads_install_dead_letter (void);
635 /* mono-threads internal API used by the backends. */
637 This tells the suspend initiator that we completed suspend and will now be waiting for resume.
639 void mono_threads_notify_initiator_of_suspend (THREAD_INFO_TYPE* info);
641 This tells the resume initiator that we completed resume duties and will return to runnable state.
643 void mono_threads_notify_initiator_of_resume (THREAD_INFO_TYPE* info);
646 This tells the resume initiator that we completed abort duties and will return to previous state.
648 void mono_threads_notify_initiator_of_abort (THREAD_INFO_TYPE* info);
650 /* Thread state machine functions */
652 typedef enum {
653 ResumeError,
654 ResumeOk,
655 ResumeInitSelfResume,
656 ResumeInitAsyncResume,
657 ResumeInitBlockingResume,
658 } MonoResumeResult;
660 typedef enum {
661 PulseInitAsyncPulse,
662 } MonoPulseResult;
664 typedef enum {
665 SelfSuspendResumed,
666 SelfSuspendNotifyAndWait,
667 } MonoSelfSupendResult;
669 typedef enum {
670 ReqSuspendAlreadySuspended,
671 ReqSuspendAlreadySuspendedBlocking,
672 ReqSuspendInitSuspendRunning,
673 ReqSuspendInitSuspendBlocking,
674 } MonoRequestSuspendResult;
676 typedef enum {
677 DoBlockingContinue, //in blocking mode, continue
678 DoBlockingPollAndRetry, //async suspend raced blocking and won, pool and retry
679 } MonoDoBlockingResult;
681 typedef enum {
682 DoneBlockingOk, //exited blocking fine
683 DoneBlockingWait, //thread should end suspended and wait for resume
684 } MonoDoneBlockingResult;
687 typedef enum {
688 AbortBlockingIgnore, //Ignore
689 AbortBlockingIgnoreAndPoll, //Ignore and poll
690 AbortBlockingOk, //Abort worked
691 AbortBlockingWait, //Abort worked, but should wait for resume
692 } MonoAbortBlockingResult;
695 void mono_threads_transition_attach (THREAD_INFO_TYPE* info);
696 gboolean mono_threads_transition_detach (THREAD_INFO_TYPE *info);
697 MonoRequestSuspendResult mono_threads_transition_request_suspension (THREAD_INFO_TYPE *info);
698 MonoSelfSupendResult mono_threads_transition_state_poll (THREAD_INFO_TYPE *info);
699 MonoResumeResult mono_threads_transition_request_resume (THREAD_INFO_TYPE* info);
700 MonoPulseResult mono_threads_transition_request_pulse (THREAD_INFO_TYPE* info);
701 gboolean mono_threads_transition_finish_async_suspend (THREAD_INFO_TYPE* info);
702 MonoDoBlockingResult mono_threads_transition_do_blocking (THREAD_INFO_TYPE* info, const char* func);
703 MonoDoneBlockingResult mono_threads_transition_done_blocking (THREAD_INFO_TYPE* info, const char* func);
704 MonoAbortBlockingResult mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info, const char* func);
705 gboolean mono_threads_transition_peek_blocking_suspend_requested (THREAD_INFO_TYPE* info);
706 void mono_threads_transition_begin_no_safepoints (THREAD_INFO_TYPE* info, const char *func);
707 void mono_threads_transition_end_no_safepoints (THREAD_INFO_TYPE* info, const char *func);
709 G_EXTERN_C // due to THREAD_INFO_TYPE varying
710 MonoThreadUnwindState* mono_thread_info_get_suspend_state (THREAD_INFO_TYPE *info);
712 gpointer
713 mono_threads_enter_gc_unsafe_region_cookie (void);
716 void mono_thread_info_wait_for_resume (THREAD_INFO_TYPE *info);
717 /* Advanced suspend API, used for suspending multiple threads as once. */
718 G_EXTERN_C // due to THREAD_INFO_TYPE varying
719 gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info);
720 gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info);
721 G_EXTERN_C // due to THREAD_INFO_TYPE varying
722 int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info);
723 int mono_thread_info_current_state (THREAD_INFO_TYPE *info);
724 const char* mono_thread_state_name (int state);
725 gboolean mono_thread_is_gc_unsafe_mode (void);
726 G_EXTERN_C // due to THREAD_INFO_TYPE varying
727 gboolean mono_thread_info_will_not_safepoint (THREAD_INFO_TYPE *info);
729 /* Suspend phases:
731 * In a full coop or full preemptive suspend, there is only a single phase. In
732 * the initial phase, all threads are either cooperatively or preemptively
733 * suspended, respectively.
735 * In hybrid suspend, there may be two phases. In the initial phase, threads
736 * are invited to cooperatively suspend. Running threads are expected to
737 * finish cooperatively suspending (the phase waits for them), but blocking
738 * threads need not.
740 * If any blocking thread was encountered in the initial phase, a second
741 * "mop-up" phase runs which checks whether the blocking threads self-suspended
742 * (in which case nothing more needs to be done) or if they're still in the
743 * BLOCKING_SUSPEND_REQUESTED state, in which case they are preemptively
744 * suspended.
746 #define MONO_THREAD_SUSPEND_PHASE_INITIAL (0)
747 #define MONO_THREAD_SUSPEND_PHASE_MOPUP (1)
748 // number of phases
749 #define MONO_THREAD_SUSPEND_PHASE_COUNT (2)
750 typedef int MonoThreadSuspendPhase;
752 typedef enum {
753 MONO_THREAD_BEGIN_SUSPEND_SKIP = 0,
754 MONO_THREAD_BEGIN_SUSPEND_SUSPENDED = 1,
755 MONO_THREAD_BEGIN_SUSPEND_NEXT_PHASE = 2,
756 } MonoThreadBeginSuspendResult;
758 G_EXTERN_C // due to THREAD_INFO_TYPE varying
759 gboolean mono_thread_info_in_critical_location (THREAD_INFO_TYPE *info);
760 G_EXTERN_C // due to THREAD_INFO_TYPE varying
761 MonoThreadBeginSuspendResult mono_thread_info_begin_suspend (THREAD_INFO_TYPE *info, MonoThreadSuspendPhase phase);
762 G_EXTERN_C // due to THREAD_INFO_TYPE varying
763 gboolean mono_thread_info_begin_resume (THREAD_INFO_TYPE *info);
764 G_EXTERN_C // due to THREAD_INFO_TYPE varying
765 gboolean mono_thread_info_begin_pulse_resume_and_request_suspension (THREAD_INFO_TYPE *info);
768 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
769 gboolean mono_threads_wait_pending_operations (void);
770 void mono_threads_begin_global_suspend (void);
771 void mono_threads_end_global_suspend (void);
773 gboolean
774 mono_thread_info_is_current (THREAD_INFO_TYPE *info);
776 typedef enum {
777 MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 = 0,
778 MONO_THREAD_INFO_WAIT_RET_ALERTED = -1,
779 MONO_THREAD_INFO_WAIT_RET_TIMEOUT = -2,
780 MONO_THREAD_INFO_WAIT_RET_FAILED = -3,
781 } MonoThreadInfoWaitRet;
783 MonoThreadInfoWaitRet
784 mono_thread_info_wait_one_handle (MonoThreadHandle *handle, guint32 timeout, gboolean alertable);
786 MonoThreadInfoWaitRet
787 mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable);
789 void mono_threads_join_lock (void);
790 void mono_threads_join_unlock (void);
793 #ifdef HOST_WASM
794 typedef void (*background_job_cb)(void);
795 void mono_threads_schedule_background_job (background_job_cb cb);
796 #endif
798 #ifdef USE_WINDOWS_BACKEND
800 void
801 mono_win32_enter_alertable_wait (THREAD_INFO_TYPE *info);
803 void
804 mono_win32_leave_alertable_wait (THREAD_INFO_TYPE *info);
806 void
807 mono_win32_enter_blocking_io_call (THREAD_INFO_TYPE *info, HANDLE io_handle);
809 void
810 mono_win32_leave_blocking_io_call (THREAD_INFO_TYPE *info, HANDLE io_handle);
812 void
813 mono_win32_interrupt_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid);
815 void
816 mono_win32_abort_blocking_io_call (THREAD_INFO_TYPE *info);
818 #define W32_DEFINE_LAST_ERROR_RESTORE_POINT \
819 DWORD _last_error_restore_point = GetLastError ();
821 #define W32_RESTORE_LAST_ERROR_FROM_RESTORE_POINT \
822 /* Only restore if changed to prevent unecessary writes. */ \
823 if (GetLastError () != _last_error_restore_point) \
824 SetLastError (_last_error_restore_point);
826 #else
828 #define W32_DEFINE_LAST_ERROR_RESTORE_POINT /* nothing */
829 #define W32_RESTORE_LAST_ERROR_FROM_RESTORE_POINT /* nothing */
831 #endif
833 #endif /* __MONO_THREADS_H__ */