6 * Rodrigo Kumpera (kumpera@gmail.com)
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>
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
;
47 #include <mono/utils/mach-support.h>
49 typedef thread_port_t MonoNativeThreadHandle
;
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)
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:
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
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
114 #define USE_WASM_BACKEND
115 #elif defined (_POSIX_VERSION)
116 #if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
117 #define USE_MACH_BACKEND
119 #define USE_POSIX_BACKEND
122 #define USE_WINDOWS_BACKEND
124 #error "no backend support for current platform"
125 #endif /* defined (_POSIX_VERSION) */
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
141 STATE_BLOCKING_SELF_SUSPENDED
= 0x08,
142 STATE_BLOCKING_SUSPEND_REQUESTED
= 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
164 * No flags means it's a normal thread that takes part in all runtime
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
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 */
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
;
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
;
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*);
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 */
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
;
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
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
;
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
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
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 \
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
);
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
);
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.
381 mono_thread_info_init (size_t thread_info_size
);
384 * Wait for the above mono_thread_info_init to be called
387 mono_thread_info_wait_inited (void);
390 mono_thread_info_callbacks_init (MonoThreadInfoCallbacks
*callbacks
);
393 mono_thread_info_signals_init (void);
396 mono_thread_info_runtime_init (MonoThreadInfoRuntimeCallbacks
*callbacks
);
398 MonoThreadInfoRuntimeCallbacks
*
399 mono_threads_get_runtime_callbacks (void);
402 mono_thread_info_register_small_id (void);
404 MONO_API THREAD_INFO_TYPE
*
405 mono_thread_info_attach (void);
408 mono_thread_info_detach (void);
411 mono_thread_info_try_get_internal_thread_gchandle (THREAD_INFO_TYPE
*info
, guint32
*gchandle
);
414 mono_thread_info_set_internal_thread_gchandle (THREAD_INFO_TYPE
*info
, guint32 gchandle
);
417 mono_thread_info_unset_internal_thread_gchandle (THREAD_INFO_TYPE
*info
);
420 mono_thread_info_is_exiting (void);
423 G_EXTERN_C
// due to THREAD_INFO_TYPE varying
426 mono_thread_info_current (void);
429 mono_thread_info_set_tools_data (void *data
);
432 mono_thread_info_get_tools_data (void);
436 mono_thread_info_current_unchecked (void);
439 mono_thread_info_get_small_id (void);
442 mono_thread_info_list_head (void);
445 mono_thread_info_lookup (MonoNativeThreadId id
);
448 mono_thread_info_resume (MonoNativeThreadId tid
);
451 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id
, gboolean interrupt_kernel
, MonoSuspendThreadCallback callback
, gpointer user_data
);
454 mono_thread_info_setup_async_call (THREAD_INFO_TYPE
*info
, void (*target_func
)(void*), void *user_data
);
457 mono_thread_info_suspend_lock (void);
460 mono_thread_info_suspend_unlock (void);
463 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid
);
466 mono_thread_info_set_is_async_context (gboolean async_context
);
469 mono_thread_info_is_async_context (void);
472 mono_thread_info_get_stack_bounds (guint8
**staddr
, size_t *stsize
);
475 mono_thread_info_yield (void);
478 mono_thread_info_sleep (guint32 ms
, gboolean
*alerted
);
481 mono_thread_info_usleep (guint64 us
);
484 mono_thread_info_tls_get (THREAD_INFO_TYPE
*info
, MonoTlsKey key
);
487 mono_thread_info_tls_set (THREAD_INFO_TYPE
*info
, MonoTlsKey key
, gpointer value
);
490 mono_thread_info_exit (gsize exit_code
);
493 mono_thread_info_install_interrupt (void (*callback
) (gpointer data
), gpointer data
, gboolean
*interrupted
);
496 mono_thread_info_uninstall_interrupt (gboolean
*interrupted
);
498 MonoThreadInfoInterruptToken
*
499 mono_thread_info_prepare_interrupt (THREAD_INFO_TYPE
*info
);
502 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken
*token
);
505 mono_thread_info_self_interrupt (void);
508 mono_thread_info_clear_self_interrupt (void);
511 mono_thread_info_is_interrupt_state (THREAD_INFO_TYPE
*info
);
514 mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE
*info
, GString
*text
);
516 G_EXTERN_C
// due to THREAD_INFO_TYPE varying
518 mono_thread_info_is_live (THREAD_INFO_TYPE
*info
);
521 mono_thread_info_get_system_max_stack_size (void);
524 mono_threads_open_thread_handle (MonoThreadHandle
*handle
);
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);
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);
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
611 mono_native_thread_create (MonoNativeThreadId
*tid
, gpointer func
, gpointer arg
);
614 template <typename T
>
616 mono_native_thread_create (MonoNativeThreadId
*tid
, T func
, gpointer arg
)
618 return mono_native_thread_create (tid
, (gpointer
)func
, arg
);
623 mono_native_thread_set_name (MonoNativeThreadId tid
, const char *name
);
626 mono_native_thread_get_name (MonoNativeThreadId tid
, char *name_out
, size_t max_len
);
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 */
655 ResumeInitSelfResume
,
656 ResumeInitAsyncResume
,
657 ResumeInitBlockingResume
,
666 SelfSuspendNotifyAndWait
,
667 } MonoSelfSupendResult
;
670 ReqSuspendAlreadySuspended
,
671 ReqSuspendAlreadySuspendedBlocking
,
672 ReqSuspendInitSuspendRunning
,
673 ReqSuspendInitSuspendBlocking
,
674 } MonoRequestSuspendResult
;
677 DoBlockingContinue
, //in blocking mode, continue
678 DoBlockingPollAndRetry
, //async suspend raced blocking and won, pool and retry
679 } MonoDoBlockingResult
;
682 DoneBlockingOk
, //exited blocking fine
683 DoneBlockingWait
, //thread should end suspended and wait for resume
684 } MonoDoneBlockingResult
;
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
);
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
);
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
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
746 #define MONO_THREAD_SUSPEND_PHASE_INITIAL (0)
747 #define MONO_THREAD_SUSPEND_PHASE_MOPUP (1)
749 #define MONO_THREAD_SUSPEND_PHASE_COUNT (2)
750 typedef int MonoThreadSuspendPhase
;
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);
774 mono_thread_info_is_current (THREAD_INFO_TYPE
*info
);
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);
794 typedef void (*background_job_cb
)(void);
795 void mono_threads_schedule_background_job (background_job_cb cb
);
798 #ifdef USE_WINDOWS_BACKEND
801 mono_win32_enter_alertable_wait (THREAD_INFO_TYPE
*info
);
804 mono_win32_leave_alertable_wait (THREAD_INFO_TYPE
*info
);
807 mono_win32_enter_blocking_io_call (THREAD_INFO_TYPE
*info
, HANDLE io_handle
);
810 mono_win32_leave_blocking_io_call (THREAD_INFO_TYPE
*info
, HANDLE io_handle
);
813 mono_win32_interrupt_wait (PVOID thread_info
, HANDLE native_thread_handle
, DWORD tid
);
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_UPDATE_LAST_ERROR_RESTORE_POINT \
822 _last_error_restore_point = GetLastError ();
824 #define W32_RESTORE_LAST_ERROR_FROM_RESTORE_POINT \
825 /* Only restore if changed to prevent unecessary writes. */ \
826 if (GetLastError () != _last_error_restore_point) \
827 SetLastError (_last_error_restore_point);
831 #define W32_DEFINE_LAST_ERROR_RESTORE_POINT /* nothing */
832 #define W32_UPDATE_LAST_ERROR_RESTORE_POINT /* nothing */
833 #define W32_RESTORE_LAST_ERROR_FROM_RESTORE_POINT /* nothing */
837 #endif /* __MONO_THREADS_H__ */