[Mono-list] P/Invoke and threading

Paolo Molaro lupus at ximian.com
Fri Aug 12 11:53:27 EDT 2005


On 08/11/05 Steven Kirk wrote:
> I am trying to wrap libjack in mono using P/Invoke but am having 
> problems with the process callback. However when libjack tries to call 
> the delegate I have registered with it, I get the following error:
> 
> ** ERROR **: Thread 0x409 calling into managed code is not registered 
> with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before 
> <pthread.h> in the file containing the thread creation code.
> 
> I assume what this is saying is that libjack is calling the delegate on 
> a thread created by itself, which the GC does not know about. I 
> obviously don't want to go adding #includes into the libjack code, is 
> there any other way around this?

This is a long standing issue. The recent work Michael Meeks did to
add a hook to the GC and the attached patch should fix it.
Care to test it?
It would be good also if people tested this with large apps that
marshal delegates and use multiple appdomains (Gtk# should be a big user
of the delegates, for example): I only did very light testing.
Thanks.

lupus

-- 
-----------------------------------------------------------------
lupus at debian.org                                     debian/rules
lupus at ximian.com                             Monkeys do it better
-------------- next part --------------
Index: metadata/marshal.c
===================================================================
--- metadata/marshal.c	(revision 48149)
+++ metadata/marshal.c	(working copy)
@@ -6267,7 +6267,57 @@
 
 	return res;
 }
-			     
+
+typedef struct {
+	MonoDomain *domain;
+	void *ptr;
+} FPtrLookup;
+
+static void
+search_domain_for_fptr (gpointer key, gpointer value, gpointer user)
+{
+	MonoDelegate *delegate;
+	MonoJitInfo *ji;
+	FPtrLookup *info = user;
+	if (info->domain)
+		return;
+	delegate = value;
+	ji = mono_jit_info_table_find (mono_object_domain (delegate), key);
+	if (ji && info->ptr >= ji->code_start && (char*)info->ptr < (char*)ji->code_start + ji->code_size) {
+		info->domain = mono_object_domain (delegate);
+	}
+}
+
+static void
+ensure_thread_is_managed (void)
+{
+	MonoDomain *domain;
+	/* FIXME: should also make sure the domain is correct */
+	if (mono_thread_current ())
+		return;
+	domain = mono_domain_get ();
+	if (!domain) {
+		/* this may be slow with lots of delegates, also because foreach can't quit early
+		 * we could change the code to pass to this function the start of the
+		 * wrapper method, so it's just a lookup in delegate_hash_table
+		 */
+		EnterCriticalSection (&marshal_mutex);
+		if (delegate_hash_table) {
+			FPtrLookup info;
+			info.domain = NULL;
+			info.ptr = __builtin_return_address (0);
+			g_hash_table_foreach (delegate_hash_table, search_domain_for_fptr, &info);
+			/*g_print ("existing domain: %p, found domain: %p (ptr: %p)\n", domain, info.domain, info.ptr);*/
+			domain = info.domain;
+		}
+		LeaveCriticalSection (&marshal_mutex);
+		/* last resort, maybe error out instead */
+		if (!domain)
+			domain = mono_get_root_domain ();
+	}
+	mono_thread_attach (domain);
+}
+
 /*
  * generates IL code to call managed methods from unmanaged code 
  */
@@ -6283,6 +6333,7 @@
 	GHashTable *cache;
 	int i, *tmp_locals;
 	EmitMarshalContext m;
+	static MonoMethodSignature *voidcsig = NULL;
 
 	g_assert (method != NULL);
 	g_assert (!mono_method_signature (method)->pinvoke);
@@ -6321,6 +6372,15 @@
 	mono_mb_emit_icon (mb, 0);
 	mono_mb_emit_byte (mb, CEE_STLOC_2);
 
+	/* emit code to ensure that the managed code will be executing in a thread
+	 * the runtime knows about.
+	 */
+	if (!voidcsig) {
+		voidcsig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+		voidcsig->ret = &mono_defaults.void_class->byval_arg;
+	}
+	mono_mb_emit_native_call (mb, voidcsig, ensure_thread_is_managed);
+
 	/* we copy the signature, so that we can modify it */
 	csig = mono_metadata_signature_dup (sig);
 	csig->hasthis = 0;


More information about the Mono-list mailing list