#include <mono/utils/mono-linked-list-set.h>
#include <mono/utils/mono-mutex.h>
#include <mono/utils/mono-tls.h>
+#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-threads-api.h>
#include <glib.h>
-
+#include <config.h>
#ifdef HOST_WIN32
#include <windows.h>
/* 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__); \
+ g_snprintf (__buff, sizeof (__buff), __VA_ARGS__); \
write (1, __buff, strlen (__buff)); \
} while (0)
#define THREADS_STATE_MACHINE_DEBUG MOSTLY_ASYNC_SAFE_PRINTF
#endif
+#if 1
+#define THREADS_INTERRUPT_DEBUG(...)
+#else
+#define THREADS_INTERRUPT_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 (_POSIX_VERSION) || defined (__native_client__)
+
+#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
+
+#else
+#error "no backend support for current platform"
+#endif /* defined (USE_COOP_GC) */
+
+#if defined (_POSIX_VERSION) || defined (__native_client__)
+#if defined (__MACH__) && !defined (USE_SIGNALS_ON_MACH)
+#define USE_MACH_SYSCALL_ABORT
+#else
+#define USE_POSIX_SYSCALL_ABORT
#endif
+#elif HOST_WIN32
+#define USE_WINDOWS_SYSCALL_ABORT
+
+#else
+#error "no syscall abort support for current platform"
+#endif /* defined (_POSIX_VERSION) || defined (__native_client__) */
enum {
STATE_STARTING = 0x00,
STATE_SELF_SUSPENDED = 0x04,
STATE_ASYNC_SUSPEND_REQUESTED = 0x05,
STATE_SELF_SUSPEND_REQUESTED = 0x06,
- // STATE_SUSPEND_IN_PROGRESS = 0x07,
- // STATE_SUSPEND_PROMOTED_TO_ASYNC = 0x08,
- STATE_MAX = 0x06,
+ STATE_BLOCKING = 0x07,
+ STATE_BLOCKING_AND_SUSPENDED = 0x8,
+
+ STATE_MAX = 0x08,
THREAD_STATE_MASK = 0x00FF,
THREAD_SUSPEND_COUNT_MASK = 0xFF00,
MONO_SERVICE_REQUEST_SAMPLE = 1,
} MonoAsyncJob;
+typedef struct _MonoThreadInfoInterruptToken MonoThreadInfoInterruptToken;
+
typedef struct {
MonoLinkedListSetNode node;
guint32 small_id; /*Used by hazard pointers */
MonoSemType resume_semaphore;
- /* only needed by the posix backend */
-#if defined(USE_POSIX_BACKEND)
+ /* only needed by the posix backend */
+#if defined(USE_POSIX_BACKEND) || defined(USE_POSIX_SYSCALL_ABORT)
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.*/
volatile gint32 service_requests;
void *jit_data;
+
+ MonoThreadInfoInterruptToken *interrupt_token;
} MonoThreadInfo;
typedef struct {
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);
-#endif
} MonoThreadInfoCallbacks;
typedef struct {
void (*setup_async_callback) (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data);
gboolean (*thread_state_init_from_sigctx) (MonoThreadUnwindState *state, void *sigctx);
gboolean (*thread_state_init_from_handle) (MonoThreadUnwindState *tctx, MonoThreadInfo *info);
+ void (*thread_state_init) (MonoThreadUnwindState *tctx);
} MonoThreadInfoRuntimeCallbacks;
//Not using 0 and 1 to ensure callbacks are not returning bad data
void
mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks);
-MonoThreadInfoCallbacks *
-mono_threads_get_callbacks (void);
-
MonoThreadInfoRuntimeCallbacks *
mono_threads_get_runtime_callbacks (void);
//END of new API
-gboolean
-mono_thread_info_new_interrupt_enabled (void);
-
gboolean
mono_thread_info_unified_management_enabled (void);
void
mono_thread_info_suspend_unlock (void);
-void
-mono_thread_info_disable_new_interrupt (gboolean disable);
-
void
mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid);
HANDLE
mono_thread_info_open_handle (void);
-gpointer
-mono_thread_info_prepare_interrupt (HANDLE thread_handle);
+void
+mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted);
void
-mono_thread_info_finish_interrupt (gpointer wait_handle);
+mono_thread_info_uninstall_interrupt (gboolean *interrupted);
+
+MonoThreadInfoInterruptToken*
+mono_thread_info_prepare_interrupt (THREAD_INFO_TYPE *info);
void
-mono_thread_info_interrupt (HANDLE thread_handle);
+mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token);
void
mono_thread_info_self_interrupt (void);
void
-mono_thread_info_clear_interruption (void);
+mono_thread_info_clear_self_interrupt (void);
+
+gboolean
+mono_thread_info_is_interrupt_state (THREAD_INFO_TYPE *info);
+
+void
+mono_thread_info_describe_interrupt_token (THREAD_INFO_TYPE *info, GString *text);
gboolean
mono_thread_info_is_live (THREAD_INFO_TYPE *info);
#endif /* !defined(HOST_WIN32) */
-/* Plartform specific functions DON'T use them */
-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 */
*/
void mono_threads_init_platform (void); //ok
+void mono_threads_init_abort_syscall (void);
+
/*
This begins async suspend. This function must do the following:
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);
+
+void mono_threads_core_begin_global_suspend (void);
+void mono_threads_core_end_global_suspend (void);
MonoNativeThreadId mono_native_thread_id_get (void);
*/
void mono_threads_notify_initiator_of_resume (THREAD_INFO_TYPE* info);
+/*
+This tells the resume initiator that we completed abort duties and will return to previous state.
+*/
+void mono_threads_notify_initiator_of_abort (THREAD_INFO_TYPE* info);
+
/* Thread state machine functions */
typedef enum {
ResumeOk,
ResumeInitSelfResume,
ResumeInitAsyncResume,
+ ResumeInitBlockingResume,
} MonoResumeResult;
typedef enum {
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);
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);
+
+void mono_thread_info_wait_for_resume (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);
+int mono_thread_info_current_state (THREAD_INFO_TYPE *info);
+const char* mono_thread_state_name (int state);
+
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);