#define THREAD_INFO_TYPE MonoThreadInfo
#endif
+/* Mono Threads internal configuration knows*/
+
+/* Logging - enable them below if you need specific logging for the category you need */
+#define MOSTLY_ASYNC_SAFE_PRINTF(...) do { \
+ char __buff[1024]; __buff [0] = '\0'; \
+ snprintf (__buff, sizeof (__buff), __VA_ARGS__); \
+ write (1, __buff, strlen (__buff)); \
+} while (0)
+
+
+#if 1
+#define THREADS_DEBUG(...)
+#else
+#define THREADS_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
+#endif
+
+#if 1
+#define THREADS_STW_DEBUG(...)
+#else
+#define THREADS_STW_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
+#endif
+
+#if 1
+#define THREADS_SUSPEND_DEBUG(...)
+#else
+#define THREADS_SUSPEND_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
+#endif
+
+#if 1
+#define THREADS_STATE_MACHINE_DEBUG(...)
+#else
+#define THREADS_STATE_MACHINE_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
+#endif
+
+/* If this is defined, use the signals backed on Mach. Debug only as signals can't be made usable on OSX. */
+// #define USE_SIGNALS_ON_MACH
+
+
+#if defined (USE_COOP_GC)
+#define USE_COOP_BACKEND
+#define MONO_THREADS_PLATFORM_REQUIRES_UNIFIED_SUSPEND 1
+
+#elif defined (_POSIX_VERSION) || defined (__native_client__)
+#define MONO_THREADS_PLATFORM_REQUIRES_UNIFIED_SUSPEND 0
+
+#if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
+#define USE_MACH_BACKEND
+#else
+#define USE_POSIX_BACKEND
+#endif
+
+#elif HOST_WIN32
+#define MONO_THREADS_PLATFORM_REQUIRES_UNIFIED_SUSPEND 0
+#define USE_WINDOWS_BACKEND
+
+#endif
+
enum {
- STATE_STARTING = 0x00,
- STATE_RUNNING = 0x01,
- STATE_SHUTTING_DOWN = 0x02,
- STATE_DEAD = 0x03,
- RUN_STATE_MASK = 0x0F,
-
- STATE_SUSPENDED = 0x10,
- STATE_SELF_SUSPENDED = 0x20,
- SUSPEND_STATE_MASK = 0xF0,
+ STATE_STARTING = 0x00,
+ STATE_RUNNING = 0x01,
+ STATE_DETACHED = 0x02,
+
+ STATE_ASYNC_SUSPENDED = 0x03,
+ STATE_SELF_SUSPENDED = 0x04,
+ STATE_ASYNC_SUSPEND_REQUESTED = 0x05,
+ STATE_SELF_SUSPEND_REQUESTED = 0x06,
+ STATE_BLOCKING = 0x07,
+ STATE_BLOCKING_AND_SUSPENDED = 0x8,
+
+ STATE_MAX = 0x08,
+
+ THREAD_STATE_MASK = 0x00FF,
+ THREAD_SUSPEND_COUNT_MASK = 0xFF00,
+ THREAD_SUSPEND_COUNT_SHIFT = 8,
+ THREAD_SUSPEND_COUNT_MAX = 0xFF,
+
+ SELF_SUSPEND_STATE_INDEX = 0,
+ ASYNC_SUSPEND_STATE_INDEX = 1,
};
/*
MONO_SERVICE_REQUEST_SAMPLE = 1,
} MonoAsyncJob;
-#define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & RUN_STATE_MASK)
-#define mono_thread_info_suspend_state(info) (((MonoThreadInfo*)info)->thread_state & SUSPEND_STATE_MASK)
-
typedef struct {
MonoLinkedListSetNode node;
guint32 small_id; /*Used by hazard pointers */
/* Tells if this thread should be ignored or not by runtime services such as GC and profiling */
gboolean tools_thread;
+ /* Max stack bounds, all valid addresses must be between [stack_start_limit, stack_end[ */
+ void *stack_start_limit, *stack_end;
+
/* suspend machinery, fields protected by suspend_semaphore */
MonoSemType suspend_semaphore;
int suspend_count;
- MonoSemType finish_resume_semaphore;
- MonoSemType resume_semaphore;
+ MonoSemType resume_semaphore;
/* only needed by the posix backend */
-#if (defined(_POSIX_VERSION) || defined(__native_client__)) && !defined (__MACH__)
- MonoSemType begin_suspend_semaphore;
+#if defined(USE_POSIX_BACKEND)
+ MonoSemType finish_resume_semaphore;
gboolean syscall_break_signal;
gboolean suspend_can_continue;
+ int signal;
+
#endif
/*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/
- MonoThreadUnwindState suspend_state;
+ MonoThreadUnwindState thread_saved_state [2]; //0 is self suspend, 1 is async suspend.
/*async call machinery, thread MUST be suspended before accessing those fields*/
void (*async_target)(void*);
* In the future the signaling should be part of the API, but for now, it's only for massaging the bits.
*/
volatile gint32 service_requests;
+
+ void *jit_data;
} MonoThreadInfo;
typedef struct {
void (*thread_detach)(THREAD_INFO_TYPE *info);
void (*thread_attach)(THREAD_INFO_TYPE *info);
gboolean (*mono_method_is_critical) (void *method);
+ gboolean (*mono_thread_in_critical_region) (THREAD_INFO_TYPE *info);
void (*thread_exit)(void *retval);
#ifndef HOST_WIN32
int (*mono_gc_pthread_create) (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
gboolean (*thread_state_init_from_handle) (MonoThreadUnwindState *tctx, MonoThreadInfo *info);
} MonoThreadInfoRuntimeCallbacks;
+//Not using 0 and 1 to ensure callbacks are not returning bad data
+typedef enum {
+ MonoResumeThread = 0x1234,
+ KeepSuspended = 0x4321,
+} SuspendThreadResult;
+
+typedef SuspendThreadResult (*MonoSuspendThreadCallback) (THREAD_INFO_TYPE *info, gpointer user_data);
+
static inline gboolean
mono_threads_filter_tools_threads (THREAD_INFO_TYPE *info)
{
* a single block with info from both camps.
*/
void
-mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t thread_info_size) MONO_INTERNAL;
+mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t thread_info_size);
void
-mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks) MONO_INTERNAL;
+mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks);
MonoThreadInfoCallbacks *
-mono_threads_get_callbacks (void) MONO_INTERNAL;
+mono_threads_get_callbacks (void);
MonoThreadInfoRuntimeCallbacks *
-mono_threads_get_runtime_callbacks (void) MONO_INTERNAL;
+mono_threads_get_runtime_callbacks (void);
int
-mono_thread_info_register_small_id (void) MONO_INTERNAL;
+mono_thread_info_register_small_id (void);
THREAD_INFO_TYPE *
-mono_thread_info_attach (void *baseptr) MONO_INTERNAL;
+mono_thread_info_attach (void *baseptr);
void
-mono_thread_info_detach (void) MONO_INTERNAL;
+mono_thread_info_detach (void);
gboolean
-mono_thread_info_is_exiting (void) MONO_INTERNAL;
+mono_thread_info_is_exiting (void);
THREAD_INFO_TYPE *
-mono_thread_info_current (void) MONO_INTERNAL;
+mono_thread_info_current (void);
+
+THREAD_INFO_TYPE*
+mono_thread_info_current_unchecked (void);
int
-mono_thread_info_get_small_id (void) MONO_INTERNAL;
+mono_thread_info_get_small_id (void);
MonoLinkedListSet*
-mono_thread_info_list_head (void) MONO_INTERNAL;
+mono_thread_info_list_head (void);
THREAD_INFO_TYPE*
-mono_thread_info_lookup (MonoNativeThreadId id) MONO_INTERNAL;
+mono_thread_info_lookup (MonoNativeThreadId id);
THREAD_INFO_TYPE*
-mono_thread_info_safe_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel) MONO_INTERNAL;
+mono_thread_info_safe_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel);
gboolean
-mono_thread_info_resume (MonoNativeThreadId tid) MONO_INTERNAL;
+mono_thread_info_resume (MonoNativeThreadId tid);
void
-mono_thread_info_set_name (MonoNativeThreadId tid, const char *name) MONO_INTERNAL;
+mono_thread_info_set_name (MonoNativeThreadId tid, const char *name);
void
-mono_thread_info_finish_suspend (MonoThreadInfo *info) MONO_INTERNAL;
+mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data);
+//XXX new API, fix the world
void
-mono_thread_info_finish_suspend_and_resume (MonoThreadInfo *info) MONO_INTERNAL;
+mono_thread_info_begin_self_suspend (void);
void
-mono_thread_info_self_suspend (void) MONO_INTERNAL;
+mono_thread_info_end_self_suspend (void);
+
+//END of new API
+
+gboolean
+mono_thread_info_new_interrupt_enabled (void);
gboolean
-mono_thread_info_new_interrupt_enabled (void) MONO_INTERNAL;
+mono_thread_info_unified_management_enabled (void);
void
-mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data) MONO_INTERNAL;
+mono_thread_info_setup_async_call (THREAD_INFO_TYPE *info, void (*target_func)(void*), void *user_data);
void
-mono_thread_info_suspend_lock (void) MONO_INTERNAL;
+mono_thread_info_suspend_lock (void);
void
-mono_thread_info_suspend_unlock (void) MONO_INTERNAL;
+mono_thread_info_suspend_unlock (void);
void
-mono_thread_info_disable_new_interrupt (gboolean disable) MONO_INTERNAL;
+mono_thread_info_disable_new_interrupt (gboolean disable);
void
-mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid) MONO_INTERNAL;
+mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid);
void
-mono_thread_info_set_is_async_context (gboolean async_context) MONO_INTERNAL;
+mono_thread_info_set_is_async_context (gboolean async_context);
gboolean
-mono_thread_info_is_async_context (void) MONO_INTERNAL;
+mono_thread_info_is_async_context (void);
void
mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize);
gboolean
-mono_thread_info_yield (void) MONO_INTERNAL;
+mono_thread_info_yield (void);
gpointer
mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key);
void
mono_thread_info_clear_interruption (void);
+gboolean
+mono_thread_info_is_live (THREAD_INFO_TYPE *info);
+
HANDLE
mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid);
int
-mono_threads_get_max_stack_size (void) MONO_INTERNAL;
+mono_threads_get_max_stack_size (void);
HANDLE
-mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) MONO_INTERNAL;
+mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
/*
This is the async job submission/consumption API.
If you want to use/extend it anywhere else, understand that you'll have to do some API design work to better fit this puppy.
*/
gboolean
-mono_threads_add_async_job (THREAD_INFO_TYPE *info, MonoAsyncJob job) MONO_INTERNAL;
+mono_threads_add_async_job (THREAD_INFO_TYPE *info, MonoAsyncJob job);
MonoAsyncJob
-mono_threads_consume_async_jobs (void) MONO_INTERNAL;
+mono_threads_consume_async_jobs (void);
-void
+MONO_API void
mono_threads_attach_tools_thread (void);
/*Use this instead of pthread_kill */
int
-mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum) MONO_INTERNAL;
+mono_threads_pthread_kill (THREAD_INFO_TYPE *info, int signum);
#endif /* !defined(HOST_WIN32) */
/* Plartform specific functions DON'T use them */
-void mono_threads_init_platform (void) MONO_INTERNAL; //ok
-gboolean mono_threads_core_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel) MONO_INTERNAL;
-gboolean mono_threads_core_resume (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-void mono_threads_platform_register (THREAD_INFO_TYPE *info) MONO_INTERNAL; //ok
-void mono_threads_platform_free (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-void mono_threads_core_interrupt (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-gboolean mono_threads_core_needs_abort_syscall (void) MONO_INTERNAL;
-HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid) MONO_INTERNAL;
-void mono_threads_core_resume_created (THREAD_INFO_TYPE *info, MonoNativeThreadId tid) MONO_INTERNAL;
-void mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize) MONO_INTERNAL;
-gboolean mono_threads_core_yield (void) MONO_INTERNAL;
-void mono_threads_core_exit (int exit_code) MONO_INTERNAL;
-void mono_threads_core_unregister (THREAD_INFO_TYPE *info) MONO_INTERNAL;
-HANDLE mono_threads_core_open_handle (void) MONO_INTERNAL;
-HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid) MONO_INTERNAL;
-void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name) MONO_INTERNAL;
+void mono_threads_init_platform (void); //ok
+gboolean mono_threads_core_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
+gboolean mono_threads_core_resume (THREAD_INFO_TYPE *info);
+void mono_threads_platform_register (THREAD_INFO_TYPE *info); //ok
+void mono_threads_platform_free (THREAD_INFO_TYPE *info);
+void mono_threads_core_interrupt (THREAD_INFO_TYPE *info);
+void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info);
+gboolean mono_threads_core_needs_abort_syscall (void);
+HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid);
+void mono_threads_core_resume_created (THREAD_INFO_TYPE *info, MonoNativeThreadId tid);
+void mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize);
+gboolean mono_threads_core_yield (void);
+void mono_threads_core_exit (int exit_code);
+void mono_threads_core_unregister (THREAD_INFO_TYPE *info);
+HANDLE mono_threads_core_open_handle (void);
+HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
+void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name);
+
+/* Internal API between mono-threads and its backends. */
+
+/* Backend functions - a backend must implement all of the following */
+/*
+This is called very early in the runtime, it cannot access any runtime facilities.
+
+*/
+void mono_threads_init_platform (void); //ok
+
+/*
+This begins async suspend. This function must do the following:
+
+-Ensure the target will EINTR any syscalls if @interrupt_kernel is true
+-Call mono_threads_transition_finish_async_suspend as part of its async suspend.
+-Register the thread for pending suspend with mono_threads_add_to_pending_operation_set if needed.
+
+If begin suspend fails the thread must be left uninterrupted and resumed.
+*/
+gboolean mono_threads_core_begin_async_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
+
+/*
+This verifies the outcome of an async suspend operation.
+
+Some targets, such as posix, verify suspend results assynchronously. Suspend results must be
+available (in a non blocking way) after mono_threads_wait_pending_operations completes.
+*/
+gboolean mono_threads_core_check_suspend_result (THREAD_INFO_TYPE *info);
+
+/*
+This begins async resume. This function must do the following:
+
+- Install an async target if one was requested.
+- Notify the target to resume.
+- Register the thread for pending ack with mono_threads_add_to_pending_operation_set if needed.
+*/
+gboolean mono_threads_core_begin_async_resume (THREAD_INFO_TYPE *info);
+
+void mono_threads_platform_register (THREAD_INFO_TYPE *info); //ok
+void mono_threads_platform_free (THREAD_INFO_TYPE *info);
+void mono_threads_core_abort_syscall (THREAD_INFO_TYPE *info);
+gboolean mono_threads_core_needs_abort_syscall (void);
+HANDLE mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid);
+void mono_threads_core_resume_created (THREAD_INFO_TYPE *info, MonoNativeThreadId tid);
+void mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize);
+gboolean mono_threads_core_yield (void);
+void mono_threads_core_exit (int exit_code);
+void mono_threads_core_unregister (THREAD_INFO_TYPE *info);
+HANDLE mono_threads_core_open_handle (void);
+HANDLE mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
+void mono_threads_core_set_name (MonoNativeThreadId tid, const char *name);
gpointer mono_threads_core_prepare_interrupt (HANDLE thread_handle);
void mono_threads_core_finish_interrupt (gpointer wait_handle);
void mono_threads_core_self_interrupt (void);
void mono_threads_core_clear_interruption (void);
-MonoNativeThreadId mono_native_thread_id_get (void) MONO_INTERNAL;
+MonoNativeThreadId mono_native_thread_id_get (void);
-gboolean mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2) MONO_INTERNAL;
+gboolean mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2);
gboolean
-mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg) MONO_INTERNAL;
+mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg);
/*Mach specific internals */
-void mono_threads_init_dead_letter (void) MONO_INTERNAL;
-void mono_threads_install_dead_letter (void) MONO_INTERNAL;
+void mono_threads_init_dead_letter (void);
+void mono_threads_install_dead_letter (void);
+
+/* mono-threads internal API used by the backends. */
+/*
+This tells the suspend initiator that we completed suspend and will now be waiting for resume.
+*/
+void mono_threads_notify_initiator_of_suspend (THREAD_INFO_TYPE* info);
+/*
+This tells the resume initiator that we completed resume duties and will return to runnable state.
+*/
+void mono_threads_notify_initiator_of_resume (THREAD_INFO_TYPE* info);
+
+/* Thread state machine functions */
+
+typedef enum {
+ ResumeError,
+ ResumeOk,
+ ResumeInitSelfResume,
+ ResumeInitAsyncResume,
+ ResumeInitBlockingResume,
+} MonoResumeResult;
+
+typedef enum {
+ SelfSuspendResumed,
+ SelfSuspendWait,
+ SelfSuspendNotifyAndWait,
+} MonoSelfSupendResult;
+
+typedef enum {
+ AsyncSuspendAlreadySuspended,
+ AsyncSuspendWait,
+ AsyncSuspendInitSuspend,
+} MonoRequestAsyncSuspendResult;
+
+typedef enum {
+ DoBlockingContinue, //in blocking mode, continue
+ DoBlockingPollAndRetry, //async suspend raced blocking and won, pool and retry
+} MonoDoBlockingResult;
+
+typedef enum {
+ DoneBlockingAborted, //blocking was aborted and not properly restored, poll the state
+ DoneBlockingOk, //exited blocking fine
+ DoneBlockingWait, //thread should end suspended
+} MonoDoneBlockingResult;
+
+
+typedef enum {
+ AbortBlockingIgnore, //Ignore
+ AbortBlockingIgnoreAndPoll, //Ignore and pool
+ AbortBlockingOk, //Abort worked
+ AbortBlockingOkAndPool, //Abort worked, but pool before
+} MonoAbortBlockingResult;
+
+
+void mono_threads_transition_attach (THREAD_INFO_TYPE* info);
+gboolean mono_threads_transition_detach (THREAD_INFO_TYPE *info);
+void mono_threads_transition_request_self_suspension (THREAD_INFO_TYPE *info);
+MonoRequestAsyncSuspendResult mono_threads_transition_request_async_suspension (THREAD_INFO_TYPE *info);
+MonoSelfSupendResult mono_threads_transition_state_poll (THREAD_INFO_TYPE *info);
+MonoResumeResult mono_threads_transition_request_resume (THREAD_INFO_TYPE* info);
+gboolean mono_threads_transition_finish_async_suspend (THREAD_INFO_TYPE* info);
+void mono_threads_transition_async_suspend_compensation (THREAD_INFO_TYPE* info);
+MonoDoBlockingResult mono_threads_transition_do_blocking (THREAD_INFO_TYPE* info);
+MonoDoneBlockingResult mono_threads_transition_done_blocking (THREAD_INFO_TYPE* info);
+MonoAbortBlockingResult mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info);
+
+MonoThreadUnwindState* mono_thread_info_get_suspend_state (THREAD_INFO_TYPE *info);
+
+/* Advanced suspend API, used for suspending multiple threads as once. */
+gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info);
+gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info);
+int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info);
+gboolean mono_thread_info_in_critical_location (THREAD_INFO_TYPE *info);
+gboolean mono_thread_info_begin_suspend (THREAD_INFO_TYPE *info, gboolean interrupt_kernel);
+gboolean mono_thread_info_begin_resume (THREAD_INFO_TYPE *info);
+
+
+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
+gboolean mono_threads_wait_pending_operations (void);
+void mono_threads_begin_global_suspend (void);
+void mono_threads_end_global_suspend (void);
#endif /* __MONO_THREADS_H__ */