Fixes bugs 34263 and 31333.
(All tests still behave the same way - 4 fails)
2003-01-23 Dick Porter <dick@ximian.com>
* threads.c (start_wrapper): Create a Thread object if needed, so
the Main() thread can do the class initialisation in a subthread
that has been set up to allow managed code execution.
Pass the thread ID instead of the MonoThread pointer to the thread
start and attach callbacks. This change is required, because the
jit thread start callback must be called _before_ the Thread
object can be created.
(mono_thread_init): Removed much object creation code that is no
longer needed. No managed code is called from here now.
* object.c (mono_runtime_exec_managed_code): Create a subthread
for Main, and call back to the runtime to use it.
Set the exit code when Main exits.
* gc.c: Make sure domain finalisation happens in a subthread.
Re-enable threaded GC, fixing bug 31333 (again).
* environment.c: System.Environment internall calls (so far just
ExitCode is here, the others are still in icall.c)
* appdomain.c (mono_runtime_cleanup): All threads running managed
code should have finished before mono_runtime_cleanup() is
reached, so no need to clean up threads.
2003-01-23 Dick Porter <dick@ximian.com>
* mono.c: Use mono_runtime_exec_managed_code() to run all managed
code in a subthread.
* jit.c: Changed thread start and attach callbacks to pass the
thread ID, not the MonoThread pointer. Arrange that managed code
execution will fail an assertion in the main thread, just to be
sure.
2003-01-23 Dick Porter <dick@ximian.com>
* interp.c: Use mono_runtime_exec_managed_code() to run all
managed code in a subthread.
svn path=/trunk/mono/; revision=10838
+2003-01-23 Dick Porter <dick@ximian.com>
+
+ * interp.c: Use mono_runtime_exec_managed_code() to run all
+ managed code in a subthread.
+
2002-11-15 Dick Porter <dick@ximian.com>
* interp.c: mono_runtime_init() now has an extra parameter for
#include <mono/metadata/socket-io.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/marshal.h>
+#include <mono/metadata/environment.h>
#include <mono/os/util.h>
/*#include <mono/cli/types.h>*/
return NULL;
}
+typedef struct
+{
+ MonoDomain *domain;
+ char *file;
+ int argc;
+ char **argv;
+} MainThreadArgs;
+
+static void main_thread_handler (gpointer user_data)
+{
+ MainThreadArgs *main_args=(MainThreadArgs *)user_data;
+ MonoAssembly *assembly;
+ char *error;
+
+ assembly = mono_domain_assembly_open (main_args->domain,
+ main_args->file);
+
+ if (!assembly){
+ fprintf (stderr, "Can not open image %s\n", main_args->file);
+ exit (1);
+ }
+
+
+#ifdef RUN_TEST
+ test_load_class (assembly->image);
+#else
+ error = mono_verify_corlib ();
+ if (error) {
+ fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
+ exit (1);
+ }
+ segv_exception = mono_get_exception_null_reference ();
+ segv_exception->message = mono_string_new (main_args->domain, "Segmentation fault");
+ signal (SIGSEGV, segv_handler);
+
+ ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
+#endif
+}
+
int
main (int argc, char *argv [])
{
MonoDomain *domain;
- MonoAssembly *assembly;
int retval = 0, i, ocount = 0;
- char *file, *error, *config_file = NULL;
-
+ char *file, *config_file = NULL;
+ MainThreadArgs main_args;
+
if (argc < 2)
usage ();
domain = mono_init (file);
mono_runtime_init (domain, NULL, NULL);
- assembly = mono_domain_assembly_open (domain, file);
-
- if (!assembly){
- fprintf (stderr, "Can not open image %s\n", file);
- exit (1);
- }
-
-
-#ifdef RUN_TEST
- test_load_class (assembly->image);
-#else
- error = mono_verify_corlib ();
- if (error) {
- fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
- exit (1);
- }
- segv_exception = mono_get_exception_null_reference ();
- segv_exception->message = mono_string_new (domain, "Segmentation fault");
- signal (SIGSEGV, segv_handler);
-
- retval = ves_exec (domain, assembly, argc - i, argv + i);
-#endif
+ main_args.domain=domain;
+ main_args.file=file;
+ main_args.argc=argc-i;
+ main_args.argv=argv+i;
+
+ mono_runtime_exec_managed_code (domain, main_thread_handler,
+ &main_args);
+
mono_profiler_shutdown ();
mono_runtime_cleanup (domain);
mono_domain_unload (domain, TRUE);
+ /* Get the return value from System.Environment.ExitCode */
+ retval=mono_environment_exitcode_get ();
+
#if DEBUG_INTERP
if (ocount) {
fprintf (stderr, "opcode count: %ld\n", opcode_count);
+2003-01-23 Dick Porter <dick@ximian.com>
+
+ * mono.c: Use mono_runtime_exec_managed_code() to run all managed
+ code in a subthread.
+
+ * jit.c: Changed thread start and attach callbacks to pass the
+ thread ID, not the MonoThread pointer. Arrange that managed code
+ execution will fail an assertion in the main thread, just to be
+ sure.
+
2003-01-22 Martin Baulig <martin@ximian.com>
* debug.c: Reverted Gonzalo's last change since it is wrong.
}
static void
-mono_thread_start_cb (MonoThread *thread, gpointer stack_start, gpointer func)
+mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
{
MonoJitTlsData *jit_tls;
MonoLMF *lmf;
jit_tls->lmf = lmf;
- mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED, thread, func);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED, (gpointer)tid, func);
}
void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
}
static void
-mono_thread_attach_cb (MonoThread *thread, gpointer stack_start)
+mono_thread_attach_cb (guint32 tid, gpointer stack_start)
{
MonoJitTlsData *jit_tls;
MonoLMF *lmf;
InitializeCriticalSection (metadata_section);
mono_jit_tls_id = TlsAlloc ();
- mono_thread_start_cb (NULL, (gpointer)-1, NULL);
+
+ /* Don't set up the main thread for managed code execution -
+ * this will give a handy assertion fail in
+ * mono_get_lmf_addr() if any buggy runtime code tries to run
+ * managed code in this thread.
+ */
+ /* mono_thread_start_cb (GetCurrentThreadId (), (gpointer)-1, NULL); */
mono_install_compile_method (mono_jit_compile_method);
mono_install_trampoline (arch_create_jit_trampoline);
void
mono_jit_cleanup (MonoDomain *domain)
{
-
- /*
- * mono_runtime_cleanup() needs to be called early since
- * it needs the execution engine still fully working (it will
- * wait for other threads to finish).
- */
mono_runtime_cleanup (domain);
mono_domain_finalize (domain);
#include "mono/metadata/threadpool.h"
#include "mono/metadata/mono-config.h"
#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/environment.h>
#include <mono/os/util.h>
#include <locale.h>
exit (1);
}
+typedef struct
+{
+ MonoDomain *domain;
+ char *file;
+ gboolean testjit;
+ char *debug_args;
+ char *compile_class;
+ int compile_times;
+ GList *precompile_classes;
+ int verbose;
+ int break_on_main;
+ int argc;
+ char **argv;
+} MainThreadArgs;
+
+static void main_thread_handler (gpointer user_data)
+{
+ MainThreadArgs *main_args=(MainThreadArgs *)user_data;
+ MonoAssembly *assembly;
+ MonoDebugHandle *debug = NULL;
+
+ assembly = mono_domain_assembly_open (main_args->domain,
+ main_args->file);
+ if (!assembly){
+ fprintf (stderr, "Can not open image %s\n", main_args->file);
+ exit (1);
+ }
+
+ if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) {
+ gchar **args;
+
+ args = g_strsplit (main_args->debug_args ?
+ main_args->debug_args : "", ",", -1);
+ debug = mono_debug_open (assembly, mono_debug_format, (const char **) args);
+ g_strfreev (args);
+ }
+
+ if (main_args->testjit) {
+ mono_jit_compile_image (assembly->image, TRUE);
+ } else if (main_args->compile_class) {
+ mono_jit_compile_class (assembly, main_args->compile_class, main_args->compile_times, TRUE);
+ } else {
+ GList *tmp;
+
+ for (tmp = main_args->precompile_classes; tmp; tmp = tmp->next)
+ mono_jit_compile_class (assembly, tmp->data, 1,
+ main_args->verbose);
+
+ if (main_args->break_on_main) {
+ MonoImage *image = assembly->image;
+ MonoMethodDesc *desc;
+ MonoMethod *method;
+
+ method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
+ desc = mono_method_desc_from_method (method);
+ mono_insert_breakpoint_full (desc, FALSE);
+ }
+
+ mono_jit_exec (main_args->domain, assembly, main_args->argc,
+ main_args->argv);
+ }
+}
+
int
main (int argc, char *argv [])
{
MonoDomain *domain;
- MonoAssembly *assembly;
int retval = 0, i;
int compile_times = 1000;
char *compile_class = NULL;
int verbose = FALSE;
GList *precompile_classes = NULL;
int break_on_main = FALSE;
- MonoDebugHandle *debug = NULL;
-
+ MainThreadArgs main_args;
setlocale(LC_ALL, "");
g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
exit (1);
}
-
- assembly = mono_domain_assembly_open (domain, file);
- if (!assembly){
- fprintf (stderr, "Can not open image %s\n", file);
- exit (1);
- }
-
- if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) {
- gchar **args;
-
- args = g_strsplit (debug_args ? debug_args : "", ",", -1);
- debug = mono_debug_open (assembly, mono_debug_format, (const char **) args);
- g_strfreev (args);
- }
-
- if (testjit) {
- mono_jit_compile_image (assembly->image, TRUE);
- } else if (compile_class) {
- mono_jit_compile_class (assembly, compile_class, compile_times, TRUE);
- } else {
- GList *tmp;
-
- for (tmp = precompile_classes; tmp; tmp = tmp->next)
- mono_jit_compile_class (assembly, tmp->data, 1, verbose);
-
- if (break_on_main) {
- MonoImage *image = assembly->image;
- MonoMethodDesc *desc;
- MonoMethod *method;
-
- method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
- desc = mono_method_desc_from_method (method);
- mono_insert_breakpoint_full (desc, FALSE);
- }
-
- retval = mono_jit_exec (domain, assembly, argc - i, argv + i);
- }
+
+ main_args.domain=domain;
+ main_args.file=file;
+ main_args.testjit=testjit;
+ main_args.debug_args=debug_args;
+ main_args.compile_class=compile_class;
+ main_args.compile_times=compile_times;
+ main_args.precompile_classes=precompile_classes;
+ main_args.verbose=verbose;
+ main_args.break_on_main=break_on_main;
+ main_args.argc=argc-i;
+ main_args.argv=argv+i;
+
+ mono_runtime_exec_managed_code (domain, main_thread_handler,
+ &main_args);
mono_profiler_shutdown ();
mono_jit_cleanup (domain);
+ /* Look up return value from System.Environment.ExitCode */
+ retval=mono_environment_exitcode_get ();
+
return retval;
}
+2003-01-23 Dick Porter <dick@ximian.com>
+
+ * threads.c (start_wrapper): Create a Thread object if needed, so
+ the Main() thread can do the class initialisation in a subthread
+ that has been set up to allow managed code execution.
+
+ Pass the thread ID instead of the MonoThread pointer to the thread
+ start and attach callbacks. This change is required, because the
+ jit thread start callback must be called _before_ the Thread
+ object can be created.
+
+ (mono_thread_init): Removed much object creation code that is no
+ longer needed. No managed code is called from here now.
+
+ * object.c (mono_runtime_exec_managed_code): Create a subthread
+ for Main, and call back to the runtime to use it.
+ Set the exit code when Main exits.
+
+ * gc.c: Make sure domain finalisation happens in a subthread.
+ Re-enable threaded GC, fixing bug 31333 (again).
+
+ * environment.c: System.Environment internall calls (so far just
+ ExitCode is here, the others are still in icall.c)
+
+ * appdomain.c (mono_runtime_cleanup): All threads running managed
+ code should have finished before mono_runtime_cleanup() is
+ reached, so no need to clean up threads.
+
2003-01-22 Martin Baulig <martin@ximian.com>
* appdomain.h (MonoThreadStartCB): Added `MonoThread *thread' and
sysmath.h \
sysmath.c \
process.c \
- process.h
+ process.h \
+ environment.c \
+ environment.h
libmetadata_la_SOURCES = \
assembly.c \
debug-mono-symfile.h \
threadpool.h \
threads-types.h \
- threads.h
+ threads.h \
+ environment.h
libmetadatainclude_HEADERS = \
assembly.h \
g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
InitializeCriticalSection (&mono_delegate_section);
- mono_thread_init (domain, start_cb, attach_cb);
+ mono_thread_init (start_cb, attach_cb);
/* GC init has to happen after thread init */
mono_gc_init ();
return;
}
+/* This must not be called while there are still running threads executing
+ * managed code.
+ */
void
mono_runtime_cleanup (MonoDomain *domain)
{
- mono_thread_cleanup ();
-
- /* Do this after the thread cleanup, because subthreads might
- * still be doing socket calls.
- */
+ /* Not really needed, but do it anyway */
+ mono_gc_cleanup ();
+
mono_network_cleanup ();
}
#include <mono/utils/mono-hash.h>
#include <mono/io-layer/io-layer.h>
-typedef void (*MonoThreadStartCB) (MonoThread *thread, gpointer stack_start, gpointer func);
-typedef void (*MonoThreadAttachCB) (MonoThread *thread, gpointer stack_start);
+typedef void (*MonoThreadStartCB) (guint32 tid, gpointer stack_start,
+ gpointer func);
+typedef void (*MonoThreadAttachCB) (guint32 tid, gpointer stack_start);
/* This is a copy of System.AppDomainSetup */
typedef struct {
--- /dev/null
+/*
+ * environment.c: System.Environment support internal calls
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ *
+ * (C) 2002 Ximian, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/environment.h>
+
+static gint32 exitcode=0;
+
+gint32 mono_environment_exitcode_get (void)
+{
+ return(exitcode);
+}
+
+void mono_environment_exitcode_set (gint32 value)
+{
+ exitcode=value;
+}
--- /dev/null
+/*
+ * environment.h: System.Environment support internal calls
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ *
+ * (C) 2002 Ximian, Inc
+ */
+
+#ifndef _MONO_METADATA_ENVIRONMENT_H_
+#define _MONO_METADATA_ENVIRONMENT_H_
+
+extern gint32 mono_environment_exitcode_get (void);
+extern void mono_environment_exitcode_set (gint32 value);
+
+#endif /* _MONO_METADATA_ENVIRONMENT_H_ */
finalize_fields (class, vtable->data, FALSE, todo);
}
-void
-mono_domain_finalize (MonoDomain *domain) {
-
+static guint32
+internal_domain_finalize (gpointer data) {
+ MonoDomain *domain=(MonoDomain *)data;
GHashTable *todo = g_hash_table_new (NULL, NULL);
+
+ mono_new_thread_init (GetCurrentThreadId (), todo, NULL);
+
#if HAVE_BOEHM_GC
GC_gcollect ();
#endif
mono_g_hash_table_foreach (domain->class_vtable_hash, (GHFunc)finalize_static_data, todo);
/* FIXME: finalize objects in todo... */
g_hash_table_destroy (todo);
+
+ return(0);
+}
+
+void
+mono_domain_finalize (MonoDomain *domain)
+{
+ HANDLE finalize_thread;
+
+ /* Need to run managed code in a subthread.
+ * Mono_domain_finalize() is called from the main thread in
+ * the jit and the embedded example, hence the thread creation
+ * here.
+ */
+ finalize_thread=CreateThread (NULL, 0, internal_domain_finalize, domain, 0, NULL);
+ if(finalize_thread==NULL) {
+ g_assert_not_reached ();
+ }
+ WaitForSingleObject (finalize_thread, INFINITE);
+ CloseHandle (finalize_thread);
}
void
{
guint32 stack_start;
- mono_new_thread_init (NULL, &stack_start, NULL);
+ mono_new_thread_init (GetCurrentThreadId (), &stack_start, NULL);
while(!finished) {
/* Wait to be notified that there's at least one
* It's currently disabled because it still requires some
* work in the rest of the runtime.
*/
-#undef ENABLE_FINALIZER_THREAD
+#define ENABLE_FINALIZER_THREAD
void mono_gc_init (void)
{
#include <mono/metadata/string-icalls.h>
#include <mono/metadata/debug-mono-symfile.h>
#include <mono/metadata/process.h>
+#include <mono/metadata/environment.h>
#include <mono/io-layer/io-layer.h>
#include <mono/utils/strtod.h>
"System.Environment::get_TickCount", ves_icall_System_Environment_get_TickCount,
"System.Environment::Exit", ves_icall_System_Environment_Exit,
"System.Environment::get_Platform", ves_icall_System_Environment_get_Platform,
+ "System.Environment::get_ExitCode", mono_environment_exitcode_get,
+ "System.Environment::set_ExitCode", mono_environment_exitcode_set,
/*
* System.Runtime.Remoting
#include <mono/metadata/marshal.h>
#include "mono/metadata/debug-helpers.h"
#include "mono/metadata/marshal.h"
+#include <mono/metadata/threads.h>
+#include <mono/metadata/environment.h>
#include "mono/metadata/profiler-private.h"
#include <mono/os/gc_wrapper.h>
}
}
+/*
+ * Launch a new thread to start all setup that requires managed code
+ * to be executed.
+ *
+ * main_func is called back from the thread with main_args as the
+ * parameter. The callback function is expected to start Main()
+ * eventually. This function then waits for all managed threads to
+ * finish.
+ */
+void
+mono_runtime_exec_managed_code (MonoDomain *domain,
+ MonoMainThreadFunc main_func,
+ gpointer main_args)
+{
+ mono_thread_create (domain, main_func, main_args);
+
+ mono_thread_manage ();
+}
+
/*
* Execute a standard Main() method (args doesn't contain the
* executable name).
rval = *(guint32 *)((char *)res + sizeof (MonoObject));
else
rval = -1;
+
+ mono_environment_exitcode_set (rval);
} else {
mono_runtime_invoke (method, NULL, pa, exc);
if (!exc || !*exc)
rval = 0;
- else
+ else {
+ /* If the return type of Main is void, only
+ * set the exitcode if an exception was thrown
+ * (we don't want to blow away an
+ * explicitly-set exit code)
+ */
rval = -1;
+ mono_environment_exitcode_set (rval);
+ }
}
return rval;
typedef MonoObject* (*MonoInvokeFunc) (MonoMethod *method, void *obj, void **params, MonoObject **exc);
typedef gpointer (*MonoCompileFunc) (MonoMethod *method);
+typedef void (*MonoMainThreadFunc) (gpointer user_data);
#define mono_object_class(obj) (((MonoObject*)(obj))->vtable->klass)
#define mono_object_domain(obj) (((MonoObject*)(obj))->vtable->domain)
MonoArray*
mono_runtime_get_main_args (void);
+void
+mono_runtime_exec_managed_code (MonoDomain *domain,
+ MonoMainThreadFunc main_func,
+ gpointer main_args);
+
int
mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
MonoObject **exc);
ReleaseSemaphore (mono_delegate_semaphore, 1, NULL);
if (workers == 0) {
- MonoThread *thread;
workers++;
- thread = mono_thread_create (domain, async_invoke_thread,
- NULL);
- g_assert (thread != NULL);
+ mono_thread_create (domain, async_invoke_thread, NULL);
}
LeaveCriticalSection (&mono_delegate_section);
#include <mono/metadata/threads.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/environment.h>
#include <mono/io-layer/io-layer.h>
#include <mono/os/gc_wrapper.h>
{
guint32 (*func)(void *);
MonoThread *obj;
+ gboolean fake_thread;
void *this;
MonoDomain *domain;
};
*/
static MonoGHashTable *threads=NULL;
-/* The MonoObject associated with the main thread */
-static MonoThread *main_thread;
-
/* The TLS key that holds the MonoObject assigned to each thread */
static guint32 current_object_key;
* the window in which the thread exists but we haven't
* recorded it.
*/
+ mono_g_hash_table_remove (threads, &thread->tid);
/* We don't need to duplicate thread->handle, because it is
* only closed when the thread object is finalized by the GC.
guint32 (*start_func)(void *);
void *this;
guint32 tid;
+ MonoThread *thread;
#ifdef THREAD_DEBUG
g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
#endif
- start_func = start_info->func;
+ /* We can be sure start_info->obj->tid and
+ * start_info->obj->handle have been set, because the thread
+ * was created suspended, and these values were set before the
+ * thread resumed
+ */
+
+ tid=start_info->obj->tid;
+
mono_domain_set (start_info->domain);
- this = start_info->this;
- tid=GetCurrentThreadId ();
- /* Set the thread ID here as well as in the parent thread,
- * because we don't know whether the thread object will
- * already have its ID set before we get to it. This isn't a
- * race condition, because if we're not guaranteed to get the
- * same number in both the parent and child threads, then
- * something else is seriously broken.
+ /* This MUST be called before any managed code can be
+ * executed, as it calls the callback function that (for the
+ * jit) sets the lmf marker.
*/
- start_info->obj->tid=tid;
+ mono_new_thread_init (tid, &tid, start_func);
+
+ if(start_info->fake_thread) {
+ thread = (MonoThread *)mono_object_new (start_info->domain, mono_defaults.thread_class);
+
+ thread->handle=start_info->obj->handle;
+ thread->tid=tid;
+ } else {
+ thread=start_info->obj;
+ }
- handle_store(start_info->obj);
+ start_func = start_info->func;
+ this = start_info->this;
- mono_profiler_thread_start (tid);
+ TlsSetValue (current_object_key, thread);
- mono_new_thread_init (start_info->obj, &tid, start_func);
+ handle_store(thread);
+
+ if(start_info->fake_thread) {
+ /* This has to happen _after_ handle_store(), because
+ * the fake thread is still in the threads hash until
+ * this call.
+ */
+ g_free (start_info->obj);
+ }
+
+ mono_profiler_thread_start (tid);
g_free (start_info);
return(0);
}
-void mono_new_thread_init (MonoThread *thread_object, gpointer stack_start, gpointer func)
+void mono_new_thread_init (guint32 tid, gpointer stack_start, gpointer func)
{
- /* FIXME: GC problem here with recorded object
- * pointer!
- *
- * This is recorded so CurrentThread can return the
- * Thread object.
- */
- TlsSetValue (current_object_key, thread_object);
-
if (mono_thread_start_cb) {
- mono_thread_start_cb (thread_object, stack_start, func);
+ mono_thread_start_cb (tid, stack_start, func);
}
}
-MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
- gpointer arg)
+void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
{
MonoThread *thread;
HANDLE thread_handle;
struct StartInfo *start_info;
guint32 tid;
- thread = (MonoThread *)mono_object_new (domain,
- mono_defaults.thread_class);
+ /* This is just a temporary allocation. The object will be
+ * created properly with mono_object_new() inside
+ * start_wrapper(). (This is so the main thread can be
+ * created without needing to run any managed code.)
+ */
+ thread=g_new0 (MonoThread, 1);
start_info=g_new0 (struct StartInfo, 1);
start_info->func = func;
start_info->obj = thread;
+ start_info->fake_thread = TRUE;
start_info->domain = domain;
start_info->this = arg;
- thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
+ /* Create suspended, so we can do some housekeeping before the thread
+ * starts
+ */
+ thread_handle = CreateThread(NULL, 0, start_wrapper, start_info,
+ CREATE_SUSPENDED, &tid);
#ifdef THREAD_DEBUG
g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
tid, thread_handle);
handle_store(thread);
- return thread;
+ ResumeThread (thread_handle);
}
MonoThread *
if ((thread = mono_thread_current ())) {
g_warning ("mono_thread_attach called for an already attached thread");
if (mono_thread_attach_cb) {
- mono_thread_attach_cb (thread, &tid);
+ mono_thread_attach_cb (tid, &tid);
}
return thread;
}
mono_domain_set (domain);
if (mono_thread_attach_cb) {
- mono_thread_attach_cb (thread, &tid);
+ mono_thread_attach_cb (tid, &tid);
}
return(thread);
start_info->func = start_func;
start_info->this = delegate;
start_info->obj = this;
+ start_info->fake_thread = FALSE;
start_info->domain = mono_domain_get ();
thread=CreateThread(NULL, 0, start_wrapper, start_info,
MONO_ARCH_SAVE_REGS;
#ifdef THREAD_LOCK_DEBUG
- g_message("(%d) Pulsing %p", GetCurrentThreadId (), obj);
+ g_message(G_GNUC_PRETTY_FUNCTION "(%d) Pulsing %p",
+ GetCurrentThreadId (), obj);
#endif
EnterCriticalSection(&monitor_mutex);
mon=obj->synchronisation;
if(mon==NULL) {
+#ifdef THREAD_LOCK_DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION
+ "(%d) object %p not locked", GetCurrentThreadId (),
+ obj);
+#endif
+
LeaveCriticalSection(&monitor_mutex);
return;
}
if(mon->tid!=GetCurrentThreadId()) {
+#ifdef THREAD_LOCK_DEBUG
+ g_message (G_GNUC_PRETTY_FUNCTION
+ "(%d) doesn't own lock (owned by %d)",
+ GetCurrentThreadId (), mon->tid);
+#endif
+
LeaveCriticalSection(&monitor_mutex);
return;
}
MONO_ARCH_SAVE_REGS;
#ifdef THREAD_LOCK_DEBUG
- g_message("(%d) Trying to wait for %p with timeout %dms",
+ g_message(G_GNUC_PRETTY_FUNCTION
+ "(%d) Trying to wait for %p with timeout %dms",
GetCurrentThreadId (), obj, ms);
#endif
}
}
-void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
+void mono_thread_init (MonoThreadStartCB start_cb,
+ MonoThreadAttachCB attach_cb)
{
- /* Build a System.Threading.Thread object instance to return
- * for the main line's Thread.CurrentThread property.
- */
-
- /* I wonder what happens if someone tries to destroy this
- * object? In theory, I guess the whole program should act as
- * though exit() were called :-)
- */
-#ifdef THREAD_DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Starting to build main Thread object");
-#endif
- main_thread = (MonoThread *)mono_object_new (domain, mono_defaults.thread_class);
-
- main_thread->handle = GetCurrentThread ();
-
-#ifdef THREAD_DEBUG
- g_message(G_GNUC_PRETTY_FUNCTION
- ": Finished building main Thread object: %p", main_thread);
-#endif
-
InitializeCriticalSection(&threads_mutex);
InitializeCriticalSection(&monitor_mutex);
InitializeCriticalSection(&interlocked_mutex);
current_object_key);
#endif
- TlsSetValue(current_object_key, main_thread);
-
mono_thread_start_cb = start_cb;
mono_thread_attach_cb = attach_cb;
}
}
-void mono_thread_cleanup(void)
+void mono_thread_manage (void)
{
struct wait_data *wait=g_new0 (struct wait_data, 1);
mono_g_hash_table_destroy(threads);
threads=NULL;
}
+
+static void terminate_thread (gpointer key, gpointer value, gpointer user)
+{
+ MonoThread *thread=(MonoThread *)value;
+ guint32 self=GPOINTER_TO_UINT (user);
+
+ if(thread->tid!=self) {
+ /*TerminateThread (thread->handle, -1);*/
+ }
+}
+
+void mono_thread_abort_all_other_threads (void)
+{
+ guint32 self=GetCurrentThreadId ();
+
+ EnterCriticalSection (&threads_mutex);
+#ifdef THREAD_DEBUG
+ g_message(G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
+ mono_g_hash_table_size (threads));
+ mono_g_hash_table_foreach (threads, print_tids, NULL);
+#endif
+
+ mono_g_hash_table_foreach (threads, terminate_thread,
+ GUINT_TO_POINTER (self));
+
+ LeaveCriticalSection (&threads_mutex);
+}
extern int mono_thread_get_abort_signal (void);
-extern void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
+extern void mono_thread_init (MonoThreadStartCB start_cb,
MonoThreadAttachCB attach_cb);
-extern void mono_thread_cleanup(void);
+extern void mono_thread_manage(void);
+extern void mono_thread_abort_all_other_threads (void);
+
extern MonoThread *mono_thread_current (void);
typedef struct {
extern void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks);
-extern void mono_new_thread_init (MonoThread *thread_object,
- gpointer stack_start,
+extern void mono_new_thread_init (guint32 tid, gpointer stack_start,
gpointer func);
-extern MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
+extern void mono_thread_create (MonoDomain *domain, gpointer func,
gpointer arg);
extern MonoThread *mono_thread_attach (MonoDomain *domain);
#include <mono/jit/jit.h>
+#include <mono/metadata/environment.h>
/*
* Very simple mono embedding example.
return mono_string_new (mono_domain_get (), "All your monos are belong to us!");
}
+typedef struct
+{
+ MonoDomain *domain;
+ const char *file;
+ int argc;
+ char **argv;
+} MainThreadArgs;
+
+static void main_thread_handler (gpointer user_data)
+{
+ MainThreadArgs *main_args=(MainThreadArgs *)user_data;
+ MonoAssembly *assembly;
+
+ assembly = mono_domain_assembly_open (main_args->domain,
+ main_args->file);
+ if (!assembly)
+ exit (2);
+ /*
+ * mono_jit_exec() will run the Main() method in the assembly.
+ * The return value needs to be looked up from
+ * System.Environment.ExitCode.
+ */
+ mono_jit_exec (main_args->domain, assembly, main_args->argc,
+ main_args->argv);
+}
+
+
int
main(int argc, char* argv[]) {
MonoDomain *domain;
- MonoAssembly *assembly;
const char *file;
int retval;
-
+ MainThreadArgs main_args;
+
if (argc < 2){
fprintf (stderr, "Please provide an assembly to load");
return 1;
* can call us back.
*/
mono_add_internal_call ("Mono::gimme", gimme);
- assembly = mono_domain_assembly_open (domain, file);
- if (!assembly)
- return 2;
- /*
- * mono_jit_exec() will run the Main() method in the assembly
- * and return the value.
- */
- retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);
+
+ main_args.domain=domain;
+ main_args.file=file;
+ main_args.argc=argc-1;
+ main_args.argv=argv+1;
+
+ mono_runtime_exec_managed_code (domain, main_thread_handler,
+ &main_args);
+
+ retval=mono_environment_exitcode_get ();
+
mono_jit_cleanup (domain);
return retval;
}