ORBit2 / GMainContext locking: nurgh ...



Hi guys,

	So - we have an evil problem in OO.o - and I was hoping there would be
an easy solution; but - it turns out to be substantially more ugly than
you might imagine. Just posting my notes & current (non-working) patch
before I abandon trying to fix it (for now).

	The problem is essentially that ORBit2 remembers what the 'main' thread
is (which it is initialized with). It does this for compatibility
purposes, and when you invoke a CORBA method on an in-process
implementation that is not tagged as thread-safe, it tries to proxy that
call into this known-in-advance 'main' thread.

	There are 2 problems I've seen so far with this:

	a) if you init the ORB from a short-lived thread, (ie. not at
	   startup), then really-bad-things-happen when that thread dies
	   ie. this 'main-thread' assymetry has to be reflected in the
	   callers code.
		+ This -unfortunately- means we have to initialize 
		  ORBit2 (& gnome-vfs) at OO.o startup => ugly
		  performance issue.

	b) if you have a thread which wins the GMainContext ownership
	   (as can easily happen with multiple threads using the same
	    context), then if you call a CORBA method to an object that
	    does not have this 'thread-safe' tag set - from a different
	    thread to that in which the ORB was initialize - you 
	    deadlock.
		+ This happened with the a11y code - but as long as we
		  restrict our CORBA use to remote CORBA impl.s (which
		  is easy there) this should be no problem.

	Anyhow - I had a good go at fixing it. This is particularly hindered by
the rather inflexible & unpleasant GMainContext API pwrt. determining
whether the current thread owns that context, and the
'g_main_context_wait' API being useless [ since it doesn't wake the main
thread -> you can block forever easily ].

	Unfortunately I ran out of steam debugging the proposed solution; it's
still not clear to me which thread queue to mux incoming requests to -
quite likely I need to re-work the per-thread queue concept
substantially, perhaps removing it in favour of a single, more simply
locked central request pool.

	Either way - for OO.o / a11y the moral is clear - do only remote CORBA
IPC; ie. don't use Bonobo_Unknown_unref in-process in OO.o, but only
bonobo_object_unref - etc.

	Another point to mention is that currently ORBit2 allows a rather
un-advertised feature whereby if you are in the 'main' thread and issue
an *explicitely* async call [using the custom ORBit2 stub API for this ]
it will give you an async callback in the glib mainloop, otherwise you
may get an async call in the same thread. Since this is an unsafe &
minority & mostly unused feature; and it's impossible to distinguish
reliably from anywhere but the calling app which is required -
henceforth the unsafe/random-thread-foo thing needs to go away - all
async callbacks must be processed in <whatever> thread that holds the
GMainContext lock.

	So - if you didn't understand a word of that - fine :-) life is good;
the patch will make everything clear ;-)

	Regards,

		Michael.

-- 
 michael meeks novell com  <><, Pseudo Engineer, itinerant idiot
? depcomp
? gtk-doc.make
? orbit2-zip
? test/client
? test/echo-server.iorfile
? test/server
? test/everything/iorfile
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/ORBit2/ChangeLog,v
retrieving revision 1.736
diff -u -p -u -r1.736 ChangeLog
--- ChangeLog	11 Nov 2005 09:27:13 -0000	1.736
+++ ChangeLog	17 Nov 2005 16:15:22 -0000
@@ -1,3 +1,42 @@
+2005-11-17  Michael Meeks  <michael meeks novell com>
+
+	* src/orb/GIOP/giop.c (giop_incoming_signal_T): use
+	broadcast instead of signal.
+
+2005-11-16  Michael Meeks  <michael meeks novell com>
+
+	* src/orb/GIOP/giop.c (giop_set_incoming_handler): always
+	set request handler regardless of if (!giop_thread_safe ()).
+
+	* test/everything/client.c (test_thread, run_threaded_tests): run
+	the glib mainloop while in-proc thread tests run.
+	(main): re-enable in-proc threading tests.
+
+	* src/orb/GIOP/giop-recv-buffer.c (giop_recv_list_setup_queue_entry_async),
+	* src/orb/GIOP/giop.c (giop_invoke_async): force async callbacks into the
+	'main' appartment - we have no way to distinguish if we want an async
+	callback on the 'same thread', or at g_idle without a bogus 'main' thread,
+	so, this (unused) behavior changes slightly. All _async callbacks happen
+	in the g_idle/main appartment.
+	(giop_get_gmain_pseudo_thread): impl. Non 'pseuedo' appartments should
+	now only have replies queued on them.
+	Audited all g_thread_self calls.
+
+	* src/orb/GIOP/giop.c (giop_init): pass the 'main' psuedo-thread into
+	(giop_thread_request_push): treat NULL as the 'gmain context thread'
+	(giop_mainloop_handle_input): use 'data' pointer not 'thread_self'.
+	Audited all thread private bits, except for giop_thread_self deps.
+
+	* src/orb/GIOP/giop.c (giop_init): set giop_init_thread instead of
+	giop_main_thread - now used only to detect new thread use & hence I/O
+	loop spawning.
+	(giop_thread_new_check): check vs. init thread.
+	(giop_thread_get_main): remove.
+
+	* src/orb/GIOP/giop.c (giop_thread_set_main_handler): rename to
+	(giop_set_incoming_handler): this, nothing to do with threads.
+	* src/orb/poa/poa.c (ORBit_poa_init): upd.
+
 2005-11-11  Jens Granseuer  <jensgr gmx net>
 
 	* src/idl-compiler/orbit-idl-c-skelimpl.c
Index: include/orbit/GIOP/giop-types.h
===================================================================
RCS file: /cvs/gnome/ORBit2/include/orbit/GIOP/giop-types.h,v
retrieving revision 1.21
diff -u -p -u -r1.21 giop-types.h
--- include/orbit/GIOP/giop-types.h	27 Oct 2003 16:14:12 -0000	1.21
+++ include/orbit/GIOP/giop-types.h	17 Nov 2005 16:15:22 -0000
@@ -33,6 +33,9 @@ struct _GIOPThread {
 	void        (*request_handler) (gpointer poa_object,
 					gpointer recv_buffer,
 					gpointer dummy);
+
+	GIOPThread   *context_holder;
+	int           context_count;
 };
 
 #define GIOP_INITIAL_MSG_SIZE_LIMIT 256*1024
Index: include/orbit/GIOP/giop.h
===================================================================
RCS file: /cvs/gnome/ORBit2/include/orbit/GIOP/giop.h,v
retrieving revision 1.23
diff -u -p -u -r1.23 giop.h
--- include/orbit/GIOP/giop.h	4 Mar 2004 17:49:35 -0000	1.23
+++ include/orbit/GIOP/giop.h	17 Nov 2005 16:15:22 -0000
@@ -27,8 +27,9 @@ void        giop_recv_set_limit    (glon
 void        giop_incoming_signal_T (GIOPThread *tdata, GIOPMsgType t);
 
 typedef struct _GIOPQueue GIOPQueue;
-GIOPThread *giop_thread_get_main  (void);
-void        giop_thread_set_main_handler (gpointer    request_handler);
+void        giop_set_incoming_handler    (gpointer    request_handler);
+#define     GIOP_GMAIN_CONTEXT_THREAD NULL
+GIOPThread *giop_get_gmain_pseudo_thread (void);
 void        giop_thread_request_push     (GIOPThread *tdata,
 					  gpointer   *poa_object,
 					  gpointer   *recv_buffer);
@@ -44,6 +45,14 @@ void        giop_thread_new_check       
 void        giop_thread_queue_process    (GIOPThread *tdata);
 gboolean    giop_thread_queue_empty_T    (GIOPThread *tdata);
 void        giop_thread_queue_tail_wakeup(GIOPThread *tdata);
+
+/* Acquire back-compatible 'single threaded' / 'no-threading policy'
+   apartment lock. ie. this work happens in multiple threads, but
+   only with the default GMainContext lock held. */
+gboolean    giop_thread_apartment_acquire(void);
+void        giop_thread_apartment_release(void);
+void        giop_context_enter           (GIOPThread *tdata);
+void        giop_context_leave           (GIOPThread *tdata);
 
 #endif /* ORBIT2_INTERNAL_API */
 
Index: include/orbit/poa/poa.h
===================================================================
RCS file: /cvs/gnome/ORBit2/include/orbit/poa/poa.h,v
retrieving revision 1.26
diff -u -p -u -r1.26 poa.h
--- include/orbit/poa/poa.h	9 Jan 2004 15:59:26 -0000	1.26
+++ include/orbit/poa/poa.h	17 Nov 2005 16:15:22 -0000
@@ -154,7 +154,8 @@ void ORBit_classinfo_register  (Portable
 PortableServer_ClassInfo *ORBit_classinfo_lookup                 (const char *type_id);
 void                      ORBit_POAObject_post_invoke            (ORBit_POAObject obj);
 gboolean                  ORBit_poa_allow_cross_thread_call      (ORBit_POAObject   pobj,
-								  ORBit_IMethodFlag method_flags);
+								  ORBit_IMethodFlag method_flags,
+								  gboolean         *release_appartment);
 void                      ORBit_recv_buffer_return_sys_exception (GIOPRecvBuffer    *buf,
 								  CORBA_Environment *ev);
 void                      ORBit_poa_init (void);
Index: linc2/ChangeLog
===================================================================
RCS file: /cvs/gnome/ORBit2/linc2/ChangeLog,v
retrieving revision 1.250
diff -u -p -u -r1.250 ChangeLog
--- linc2/ChangeLog	11 Nov 2005 09:27:13 -0000	1.250
+++ linc2/ChangeLog	17 Nov 2005 16:15:22 -0000
@@ -1,3 +1,8 @@
+2005-11-16  Michael Meeks  <michael meeks novell com>
+
+	* include/linc/linc.h: make link_in_io_thread module
+	public.
+
 2005-11-11  Jens Granseuer  <jensgr gmx net>
 
 	* src/linc-protocols.c (get_netid): fix // comment.
Index: linc2/include/linc/linc-protocol.h
===================================================================
RCS file: /cvs/gnome/ORBit2/linc2/include/linc/linc-protocol.h,v
retrieving revision 1.22
diff -u -p -u -r1.22 linc-protocol.h
--- linc2/include/linc/linc-protocol.h	26 Jul 2005 12:03:54 -0000	1.22
+++ linc2/include/linc/linc-protocol.h	17 Nov 2005 16:15:22 -0000
@@ -78,9 +78,9 @@ typedef enum {
 } LinkNetIdType;
 
 
-LinkProtocolInfo * const link_protocol_find     (const char *name);
-LinkProtocolInfo * const link_protocol_find_num (const int   family);
-LinkProtocolInfo * const link_protocol_all      (void);
+LinkProtocolInfo        *link_protocol_find     (const char *name);
+LinkProtocolInfo        *link_protocol_find_num (const int   family);
+LinkProtocolInfo        *link_protocol_all      (void);
 char                    *link_get_tmpdir        (void);
 void                     link_set_tmpdir        (const char *dir);
 void                     link_use_local_hostname (LinkNetIdType use);
Index: linc2/include/linc/linc.h
===================================================================
RCS file: /cvs/gnome/ORBit2/linc2/include/linc/linc.h,v
retrieving revision 1.17
diff -u -p -u -r1.17 linc.h
--- linc2/include/linc/linc.h	28 Jan 2005 12:34:57 -0000	1.17
+++ linc2/include/linc/linc.h	17 Nov 2005 16:15:22 -0000
@@ -37,6 +37,7 @@ void       link_wait             (void);
 void       link_signal           (void);
 
 gboolean   link_thread_io        (void);
+gboolean   link_in_io_thread     (void);
 gboolean   link_thread_safe      (void);
 
 #ifdef G_OS_WIN32
Index: linc2/src/linc-private.h
===================================================================
RCS file: /cvs/gnome/ORBit2/linc2/src/linc-private.h,v
retrieving revision 1.37
diff -u -p -u -r1.37 linc-private.h
--- linc2/src/linc-private.h	15 Apr 2005 14:05:21 -0000	1.37
+++ linc2/src/linc-private.h	17 Nov 2005 16:15:22 -0000
@@ -204,7 +204,6 @@ void             link_watch_move_io     
 
 GMainContext    *link_main_get_context      (void);
 GMainContext    *link_thread_io_context     (void);
-gboolean         link_in_io_thread          (void);
 gboolean         link_mutex_is_locked       (GMutex *lock);
 void             link_lock                  (void);
 void             link_unlock                (void);
Index: linc2/src/linc-protocols.c
===================================================================
RCS file: /cvs/gnome/ORBit2/linc2/src/linc-protocols.c,v
retrieving revision 1.74
diff -u -p -u -r1.74 linc-protocols.c
--- linc2/src/linc-protocols.c	11 Nov 2005 09:27:13 -0000	1.74
+++ linc2/src/linc-protocols.c	17 Nov 2005 16:15:22 -0000
@@ -1127,7 +1127,7 @@ link_protocol_destroy_addr (const LinkPr
  *
  * Return Value: an array of #LinkProtocolInfo structures.
  */
-LinkProtocolInfo * const
+LinkProtocolInfo *
 link_protocol_all (void)
 {
 	return static_link_protocols;
@@ -1142,7 +1142,7 @@ link_protocol_all (void)
  * Return Value: a pointer to a valid #LinkProtocolInfo structure if 
  *               the protocol is supported by linc, NULL otherwise.
  */
-LinkProtocolInfo * const
+LinkProtocolInfo *
 link_protocol_find (const char *name)
 {
 	int i;
@@ -1164,7 +1164,7 @@ link_protocol_find (const char *name)
  * Return Value: a pointer to a valid #LinkProtocolInfo structure if
  *               the protocol is supported by linc, NULL otherwise.
  */
-LinkProtocolInfo * const
+LinkProtocolInfo *
 link_protocol_find_num (const int family)
 {
 	int i;
Index: src/orb/GIOP/giop-recv-buffer.c
===================================================================
RCS file: /cvs/gnome/ORBit2/src/orb/GIOP/giop-recv-buffer.c,v
retrieving revision 1.79
diff -u -p -u -r1.79 giop-recv-buffer.c
--- src/orb/GIOP/giop-recv-buffer.c	19 Aug 2004 15:30:14 -0000	1.79
+++ src/orb/GIOP/giop-recv-buffer.c	17 Nov 2005 16:15:22 -0000
@@ -577,6 +577,7 @@ giop_recv_list_setup_queue_entry_async (
 {
 	g_return_if_fail (ent != NULL);
 
+	ent->src_thread = giop_get_gmain_pseudo_thread ();
 	ent->async_cb = cb;
 }
 
@@ -699,14 +700,20 @@ giop_recv_buffer_get (GIOPMessageQueueEn
 	if (giop_thread_io ()) {
 		ent_lock (ent);
 
+		giop_context_enter (tdata);
+
 		for (; !check_got (ent); ) {
 			if (!giop_thread_queue_empty_T (tdata)) {
 				ent_unlock (ent);
 				giop_thread_queue_process (tdata);
 				ent_lock (ent);
-			} else
+			} else {
+				dprintf (GIOP, "wait on %d\n", tdata);
 				g_cond_wait (tdata->incoming, tdata->lock);
+			}
 		}
+
+		giop_context_leave (tdata);
 		
 		ent_unlock (ent);
 
@@ -1075,10 +1082,10 @@ handle_reply (GIOPRecvBuffer *buf)
 		error = TRUE;
 
 	} else {
-#ifdef DEBUG
-		g_warning ("Pop XX:%p:%p - %d",
-			   ent, ent->async_cb,
-			   g_list_length (giop_queued_messages));
+#ifdef G_ENABLE_DEBUG
+		dprintf (GIOP, "Pop XX:%p:%p - %d\n",
+			 ent, ent->async_cb,
+			 g_list_length (giop_queued_messages));
 #endif
 		giop_queued_messages = g_list_delete_link
 			(giop_queued_messages, l);
@@ -1091,6 +1098,9 @@ handle_reply (GIOPRecvBuffer *buf)
 
 		ent_lock (ent);
 		ent->buffer = buf;
+#ifdef G_ENABLE_DEBUG
+		dprintf (GIOP, "Assign buffer on ent %p\n", ent);
+#endif
 
 		if (giop_thread_io () && !ent->async_cb)
 			giop_incoming_signal_T (ent->src_thread,
Index: src/orb/GIOP/giop.c
===================================================================
RCS file: /cvs/gnome/ORBit2/src/orb/GIOP/giop.c,v
retrieving revision 1.53
diff -u -p -u -r1.53 giop.c
--- src/orb/GIOP/giop.c	8 Sep 2005 09:03:58 -0000	1.53
+++ src/orb/GIOP/giop.c	17 Nov 2005 16:15:22 -0000
@@ -22,12 +22,17 @@ static int      corba_wakeup_fds[2];
 #define WAKEUP_POLL  corba_wakeup_fds [0]
 #define WAKEUP_WRITE corba_wakeup_fds [1]
 static GSource *giop_main_source = NULL;
-static GIOPThread *giop_main_thread = NULL;
+static GIOPThread *giop_init_thread = NULL;
+/* Not really a thread - but a queue for the default GMainContext */
+static GIOPThread *giop_gmain_pseudo_thread = NULL;
+static void      (*giop_incoming_request_handler_fn) (gpointer, gpointer, gpointer) = NULL;
 
 /* Incoming dispatch thread pool */
 static GThreadPool *giop_thread_pool    = NULL;
 static GMutex      *giop_pool_hash_lock = NULL;
 static GHashTable  *giop_pool_hash      = NULL;
+static GMutex      *giop_apartment_lock = NULL;
+static GCond       *giop_apartment_cond = NULL;
 
 const char giop_version_ids [GIOP_NUM_VERSIONS][2] = {
 	{1,0},
@@ -291,9 +296,7 @@ giop_thread_new (GMainContext *context)
 	tdata->keys = NULL;
 	tdata->async_ents = NULL;
 	tdata->request_queue = NULL;
-
-	if (giop_main_thread)
-		tdata->request_handler = giop_main_thread->request_handler;
+	tdata->request_handler = NULL;
 
 	G_LOCK (giop_thread_list);
 	giop_thread_list = g_list_prepend (giop_thread_list, tdata);
@@ -370,7 +373,6 @@ giop_thread_self (void)
 	return tdata;
 }
 
-
 void
 giop_thread_key_add (GIOPThread *tdata, gpointer key)
 {
@@ -449,7 +451,7 @@ giop_mainloop_handle_input (GIOChannel  
 			    gpointer        data)
 {
 	char c;
-	GIOPThread *tdata = giop_thread_self ();
+	GIOPThread *tdata = data;
 
 #ifdef HAVE_WINSOCK2_H
 	recv (WAKEUP_POLL, &c, sizeof (c), 0);
@@ -465,7 +467,6 @@ giop_mainloop_handle_input (GIOChannel  
 	}
 	LINK_MUTEX_UNLOCK (tdata->lock);
 
-
 	return TRUE;
 }
 
@@ -501,6 +502,7 @@ giop_request_handler_thread (gpointer da
 	dprintf (GIOP, "Thread %p returning to pool\n", tdata);
 
 	giop_thread_free (tdata);
+
 	g_private_set (giop_tdata_private, NULL);
 }
 
@@ -517,14 +519,11 @@ giop_init (gboolean thread_safe, gboolea
 	link_init (thread_safe);
 
 	if (thread_safe) {
-		GIOPThread *tdata;
-
 		/* We need a destructor to clean up if giopthreads are used
 		 * outside of ORBit controlled threads */
 		giop_tdata_private = g_private_new ((GDestroyNotify)giop_thread_free);
 
-		giop_main_thread = tdata = giop_thread_new (
-			g_main_context_default ()); /* main thread */
+		giop_gmain_pseudo_thread = giop_thread_new (g_main_context_default ());
 
 		if (link_pipe (corba_wakeup_fds) < 0) /* cf. g_main_context_init_pipe */
 			g_error ("Can't create CORBA main-thread wakeup pipe");
@@ -540,15 +539,20 @@ giop_init (gboolean thread_safe, gboolea
 		giop_main_source = link_source_create_watch (
 			g_main_context_default (), WAKEUP_POLL,
 			NULL, (G_IO_IN | G_IO_PRI),
-			giop_mainloop_handle_input, NULL);
+			giop_mainloop_handle_input,
+			giop_gmain_pseudo_thread );
 		
-		g_private_set (giop_tdata_private, tdata);
+		/* For detecting other thread use */
+		giop_init_thread = giop_thread_new (NULL);
+		g_private_set (giop_tdata_private, giop_init_thread);
 
 		/* Setup thread pool for incoming requests */
 		giop_thread_pool = g_thread_pool_new
 			(giop_request_handler_thread, NULL, -1, FALSE, NULL);
-		giop_pool_hash_lock = link_mutex_new ();
+		giop_pool_hash_lock = g_mutex_new ();
 		giop_pool_hash = g_hash_table_new (NULL, NULL);
+		giop_apartment_lock = g_mutex_new ();
+		giop_apartment_cond = g_cond_new ();
 	}
 
 	giop_tmpdir_init ();
@@ -582,7 +586,17 @@ wakeup_mainloop (void)
 void
 giop_incoming_signal_T (GIOPThread *tdata, GIOPMsgType t)
 {
-	g_cond_signal (tdata->incoming);
+	dprintf (GIOP, "signal %d\n");
+
+	g_cond_broadcast (tdata->incoming);
+
+	if (tdata->context_holder)
+	{
+		g_mutex_lock (tdata->context_holder->lock);
+		dprintf (GIOP, "signal holder %d\n", tdata->context_holder);
+		g_cond_broadcast (tdata->context_holder->incoming);
+		g_mutex_unlock (tdata->context_holder->lock);
+	}
 
 	if (t != GIOP_REPLY && tdata->wake_context)
 		wakeup_mainloop ();
@@ -593,17 +607,22 @@ giop_invoke_async (GIOPMessageQueueEntry
 {
 	GIOPRecvBuffer *buf = ent->buffer;
 
+	g_return_if_fail (ent->async_cb != NULL);
+	g_return_if_fail (ent->src_thread == giop_gmain_pseudo_thread);
+
 	dprintf (GIOP, "About to invoke %p:%p (%d) (%p:%p)\n",
 		 ent, ent->async_cb, giop_thread_io(),
-		 ent->src_thread, giop_main_thread);
+		 ent->src_thread, giop_init_thread);
 
 	if (!giop_thread_io ())
 		ent->async_cb (ent);
 
-	else if (ent->src_thread == giop_thread_self ())
+	else if (!link_in_io_thread () &&
+		 giop_thread_apartment_acquire()) {
 		ent->async_cb (ent);
+		giop_thread_apartment_release();
 
-	else {
+	} else {
 		GIOPThread *tdata = ent->src_thread;
 		
 		g_mutex_lock (tdata->lock); /* ent_lock */
@@ -613,7 +632,7 @@ giop_invoke_async (GIOPMessageQueueEntry
 		giop_incoming_signal_T (tdata, GIOP_REQUEST);
 		
 		g_mutex_unlock (tdata->lock); /* ent_unlock */
-	}
+	} 
 
 	/* NB. At the tail end of async_cb 'Ent' is invalid / freed */
 	giop_recv_buffer_unuse (buf);
@@ -771,7 +790,10 @@ giop_thread_queue_process (GIOPThread *t
 		giop_invoke_async (ent);
 
 	if (qe) {
-		tdata->request_handler (qe->poa_object, qe->recv_buffer, NULL);
+		if (tdata->request_handler)
+			tdata->request_handler (qe->poa_object, qe->recv_buffer, NULL);
+		else
+			giop_incoming_request_handler_fn (qe->poa_object, qe->recv_buffer, NULL);
 		g_free (qe);
 	}
 }
@@ -797,10 +819,14 @@ giop_thread_request_push (GIOPThread *td
 {
 	GIOPQueueEntry *qe;
 
-	g_return_if_fail (tdata != NULL);
 	g_return_if_fail (poa_object != NULL);
 	g_return_if_fail (recv_buffer != NULL);
 
+	if (!tdata)
+		tdata = giop_gmain_pseudo_thread;
+
+	g_return_if_fail (tdata != NULL);
+
 	qe = g_new (GIOPQueueEntry, 1);
 
 	qe->poa_object  = *poa_object;
@@ -816,20 +842,10 @@ giop_thread_request_push (GIOPThread *td
 	LINK_MUTEX_UNLOCK (tdata->lock);
 }
 
-GIOPThread *
-giop_thread_get_main (void)
-{
-	return giop_main_thread;
-}
-
 void
-giop_thread_set_main_handler (gpointer request_handler)
+giop_set_incoming_handler (gpointer request_handler)
 {
-	if (!giop_thread_safe ())
-		return;
-	g_assert (giop_main_thread != NULL);
-
-	giop_main_thread->request_handler = request_handler;
+	giop_incoming_request_handler_fn = request_handler;
 }
 
 void
@@ -842,7 +858,89 @@ giop_thread_new_check (GIOPThread *opt_s
 		opt_self = giop_thread_self ();
 
 	if (opt_self &&
-	    opt_self != giop_thread_get_main () &&
+	    opt_self != giop_init_thread &&
 	    !link_thread_io ())
 		link_set_io_thread (TRUE);
+}
+
+gboolean
+giop_thread_apartment_acquire (void)
+{
+	GMainContext *context;
+
+	if (!giop_thread_io())
+		return TRUE;
+
+	context = g_main_context_default();
+	if (g_main_context_acquire (context))
+		return TRUE;
+
+	return FALSE;
+#if 0
+	/* FIXME: it'd be nice if we could ask for & get
+	   the g_main_context quickly - unfortunately that's
+	   not possible efficiently */
+	g_mutex_lock (giop_apartment_lock);
+	g_main_context_wakeup ();
+	/* the lock & cond are not really useful but ... */	
+	while (!g_main_context_wait (context,
+				     giop_apartment_cond,
+				     giop_apartment_lock))
+	{
+		dprintf (GIOP, "Thread %p waiting for main appartment\n",
+			 giop_thread_self ());
+	}
+	g_mutex_unlock (giop_apartment_lock);
+	dprintf (GIOP, "Thread %p locked main appartment\n",
+		 giop_thread_self ());
+#endif
+}
+
+void
+giop_thread_apartment_release (void)
+{
+	if (!giop_thread_io())
+		return;
+
+	dprintf (GIOP, "Thread %p released main appartment\n",
+		 giop_thread_self ());
+	g_main_context_release (g_main_context_default());
+}
+
+GIOPThread *
+giop_get_gmain_pseudo_thread (void)
+{
+	return giop_gmain_pseudo_thread;
+}
+
+void
+giop_context_enter (GIOPThread *tdata)
+{
+	/* recursion ... urgh ...*/
+	if (tdata->context_holder)
+	{
+		tdata->context_count++;
+		return;
+	}
+	if (g_main_context_acquire (g_main_context_default ()))
+	{
+		tdata->context_count++;
+		tdata->context_holder = giop_gmain_pseudo_thread;
+		giop_gmain_pseudo_thread->context_holder = tdata;
+	}
+}
+
+void
+giop_context_leave (GIOPThread *tdata)
+{
+	if (!tdata->context_holder)
+		return;
+
+	if (--(tdata->context_count))
+		return;
+
+	giop_gmain_pseudo_thread->context_holder = NULL; /* FIXME - thread unsafe */
+	tdata->context_holder = NULL;
+	
+	g_main_context_release (g_main_context_default ());
 }
Index: src/orb/orb-core/orbit-small.c
===================================================================
RCS file: /cvs/gnome/ORBit2/src/orb/orb-core/orbit-small.c,v
retrieving revision 1.96
diff -u -p -u -r1.96 orbit-small.c
--- src/orb/orb-core/orbit-small.c	19 Aug 2004 15:30:14 -0000	1.96
+++ src/orb/orb-core/orbit-small.c	17 Nov 2005 16:15:23 -0000
@@ -591,6 +591,7 @@ ORBit_small_invoke_stub (CORBA_Object   
 	GIOPRecvBuffer         *recv_buffer = NULL;
 	CORBA_Object            xt_proxy = CORBA_OBJECT_NIL;
 	ORBitPolicy            *invoke_policy = CORBA_OBJECT_NIL;
+	gboolean                release_appartment = FALSE;
 
 	if (!obj) {
 		dprintf (MESSAGES, "Cannot invoke method on null object\n");
@@ -609,11 +610,13 @@ ORBit_small_invoke_stub (CORBA_Object   
 	if (adaptor_obj) {
 		/* FIXME: unchecked cast */
 		if (ORBit_poa_allow_cross_thread_call ((ORBit_POAObject) adaptor_obj,
-						       m_data->flags)) {
+						       m_data->flags, &release_appartment)) {
 			tprintf_header (obj, m_data);
 			tprintf ("[in-proc]");
 			ORBit_small_handle_request (adaptor_obj, m_data->name, ret,
 						    args, ctx, NULL, ev);
+			if (release_appartment)
+				giop_thread_apartment_release();
 			goto clean_out;
 		} else {
 			tprintf ("[in-proc-XT]");
Index: src/orb/poa/poa.c
===================================================================
RCS file: /cvs/gnome/ORBit2/src/orb/poa/poa.c,v
retrieving revision 1.118
diff -u -p -u -r1.118 poa.c
--- src/orb/poa/poa.c	8 Nov 2005 09:02:44 -0000	1.118
+++ src/orb/poa/poa.c	17 Nov 2005 16:15:23 -0000
@@ -1577,7 +1577,7 @@ ORBit_POA_handle_request (PortableServer
 		switch (poa->p_thread) {
 			case PortableServer_SINGLE_THREAD_MODEL:
 				if (giop_thread_io ())
-					push_request_T (giop_thread_get_main (),
+					push_request_T (GIOP_GMAIN_CONTEXT_THREAD,
 							&pobj, &recv_buffer);
 				break;
 			case PortableServer_ORB_CTRL_MODEL: {
@@ -1607,7 +1607,7 @@ ORBit_POA_handle_request (PortableServer
 
 				case ORBIT_THREAD_HINT_ONEWAY_AT_IDLE:
 					if (!poa_recv_is_oneway (pobj, recv_buffer))
-						push_request_T (giop_thread_get_main (),
+						push_request_T (GIOP_GMAIN_CONTEXT_THREAD,
 								&pobj, &recv_buffer);
 					/* drop through */
 				case ORBIT_THREAD_HINT_ALL_AT_IDLE:
@@ -1620,7 +1620,7 @@ ORBit_POA_handle_request (PortableServer
 
 				case ORBIT_THREAD_HINT_NONE:
 					if (giop_thread_io ())
-						push_request_T (giop_thread_get_main (),
+						push_request_T (GIOP_GMAIN_CONTEXT_THREAD,
 								&pobj, &recv_buffer);
 					break;
 				default:
@@ -2488,23 +2488,22 @@ ORBit_poa_init (void)
 {
 	ORBit_class_assignment_lock = link_mutex_new ();
 	_ORBit_poa_manager_lock = link_mutex_new ();
-	giop_thread_set_main_handler (ORBit_POAObject_invoke_incoming_request);
+	giop_set_incoming_handler (ORBit_POAObject_invoke_incoming_request);
 }
 
 gboolean
 ORBit_poa_allow_cross_thread_call (ORBit_POAObject   pobj,
-				   ORBit_IMethodFlag method_flags)
-
+				   ORBit_IMethodFlag method_flags,
+				   gboolean         *release_apartment)
 {
 	gpointer key = NULL;
-	GIOPThread *self;
 	PortableServer_POA poa = pobj->poa;
 
+	*release_apartment = FALSE;
+
 	if (!poa)
 		return TRUE;
 
-	self = giop_thread_self ();
-
 	switch (poa->p_thread) {
 	case PortableServer_SINGLE_THREAD_MODEL:
 		break;
@@ -2542,10 +2541,12 @@ ORBit_poa_allow_cross_thread_call (ORBit
 	}
 	}
 
-	giop_thread_new_check (self);
+	giop_thread_new_check (NULL);
 
-	if (!key)
-		return (self == giop_thread_get_main ());
+	if (!key) {
+		*release_apartment = giop_thread_apartment_acquire();
+		return *release_apartment;
+	}
 	else
 		return giop_thread_same_key (key, TRUE);
 }
@@ -2555,7 +2556,8 @@ get_c_method (CORBA_Object              
 	      glong                        class_id,
 	      PortableServer_ServantBase **servant,
 	      glong                        method_offset,
-	      ORBit_IMethodFlag            method_flags)
+	      ORBit_IMethodFlag            method_flags,
+	      gboolean                    *release_apartment)
 {
 	guchar *epv_start;
 	ORBit_POAObject pobj;
@@ -2569,7 +2571,8 @@ get_c_method (CORBA_Object              
 	if (method_offset <= 0 || class_id <= 0)
 		return NULL;
 
-	if (!ORBit_poa_allow_cross_thread_call (pobj, method_flags))
+	if (!ORBit_poa_allow_cross_thread_call (pobj, method_flags,
+						release_apartment))
 		return NULL;
 
 	if (ORBit_small_flags & ORBIT_SMALL_FORCE_GENERIC_MARSHAL)
@@ -2605,6 +2608,7 @@ ORBit_c_stub_invoke (CORBA_Object       
 		     ORBitSmallSkeleton  skel_impl)
 {
 	gpointer method_impl;
+	gboolean release_appartment = FALSE;
 	PortableServer_ServantBase *servant;
 
 	if (method_index < 0 || method_index > methods->_length) {
@@ -2616,7 +2620,8 @@ ORBit_c_stub_invoke (CORBA_Object       
 	if (skel_impl &&
 	    (method_impl = get_c_method (obj, class_id,
 					 &servant, method_offset,
-					 methods->_buffer[method_index].flags))) {
+					 methods->_buffer[method_index].flags,
+					 &release_appartment))) {
 		
 		/* Unwound PreCall
 		   POA_LOCK (((ORBit_POAObject)(obj)->adaptor_obj)->poa);
@@ -2640,6 +2645,8 @@ ORBit_c_stub_invoke (CORBA_Object       
 		   POA_UNLOCK (((ORBit_POAObject)(obj)->adaptor_obj)->poa);
 		*/
 
+		if (release_appartment)
+			giop_thread_apartment_release();
 	} else
 		ORBit_small_invoke_stub_n
 			(obj, methods, method_index,
Index: test/everything/client.c
===================================================================
RCS file: /cvs/gnome/ORBit2/test/everything/client.c,v
retrieving revision 1.128
diff -u -p -u -r1.128 client.c
--- test/everything/client.c	11 Feb 2005 15:16:21 -0000	1.128
+++ test/everything/client.c	17 Nov 2005 16:15:24 -0000
@@ -2475,6 +2475,10 @@ run_tests (test_TestFactory   factory, 
 #endif
 }
 
+static GStaticMutex thread_count_lock = G_STATIC_MUTEX_INIT;
+static int thread_count = 0;
+static GMainLoop *thread_loop = NULL;
+
 static gpointer
 test_thread (gpointer data)
 {
@@ -2485,6 +2489,11 @@ test_thread (gpointer data)
 	run_tests (factory, TRUE, ev);
 	CORBA_exception_free (ev);
 
+	g_static_mutex_lock (&thread_count_lock);
+	if (thread_count--)
+		g_main_loop_quit (thread_loop);
+	g_static_mutex_unlock (&thread_count_lock);
+
 	return data;
 }
 
@@ -2503,12 +2512,17 @@ run_threaded_tests (test_TestFactory   f
 
 	threads = g_new0 (GThread *, NUM_THREADS);
 
+	thread_count = NUM_THREADS;
+	thread_loop = g_main_loop_new (NULL, TRUE);
+
 	for (i = 0; i < NUM_THREADS; i++) {
 		threads [i] = g_thread_create
 			( test_thread, factory, TRUE, &error);
 		g_assert (!error);
 	}
 
+	g_main_loop_run (thread_loop);
+
 	for (i = 0; i < NUM_THREADS; i++) {
 		if (!(g_thread_join (threads [i]) == factory))
 			g_error ("Wierd thread join problem '%d'", i);
@@ -2619,8 +2633,11 @@ main (int argc, char *argv [])
 	test_time_noop (factory, ev);
 	run_tests (factory, FALSE, ev);
 	if (thread_tests)
-		g_warning ("FIXME: disabled in-proc threaded tests for now");
-/*		run_threaded_tests (factory, ev); */
+	{
+		//		g_warning ("FIXME: re-enabled in-proc threaded tests for now");
+		//		run_threaded_tests (factory, ev); 
+		g_warning ("FIXME: disabled in-proc threaded tests");
+	}
 
 	CORBA_Object_release (factory, ev);
 	g_assert (ev->_major == CORBA_NO_EXCEPTION);





Chasing misc. a11y issues:



Is Bill's work in cvs. ?

(gdb) bt
#0  0x423fbc62 in g_log () from /opt/gnome/lib/libglib-2.0.so.0
#1  0x4232415d in atk_object_get_role (accessible=Variable "accessible" is not available.
) at atkobject.c:714
#2  0x42824ff3 in gail_toplevel_show_event_watcher (ihint=0xbfffe538, n_param_values=1, param_values=0xbfffe650, data=0x80f0d80)
    at gailtoplevel.c:252

(gdb) t 3
[Switching to thread 3 (Thread 16386 (LWP 20348))]#0  0x414992a4 in __pthread_sigsuspend (set=0x414a0484)
    at ../linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c:54
54        INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8);
(gdb) bt
#0  0x414992a4 in __pthread_sigsuspend (set=0x414a0484) at ../linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c:54
#1  0x41498028 in __pthread_wait_for_restart_signal (self=0xbf7ffbe0) at pthread.c:1216
#2  0x4149580c in __pthread_cond_wait (cond=Variable "cond" is not available.
) at restart.h:34
#3  0x4296be19 in giop_recv_buffer_get () from /opt/gnome/lib/libORBit-2.so.0
#4  0x42970962 in ORBit_small_invoke_stub () from /opt/gnome/lib/libORBit-2.so.0
#5  0x42970b00 in ORBit_small_invoke_stub_n () from /opt/gnome/lib/libORBit-2.so.0
#6  0x4297d982 in ORBit_c_stub_invoke () from /opt/gnome/lib/libORBit-2.so.0
#7  0x428c048c in Accessibility_EventListener_notifyEvent (_obj=0x81170c8, e=0xfffffffc, ev=0x428405d8) at Accessibility-stubs.c:754
#8  0x4283d72c in spi_atk_emit_eventv (gobject=Variable "gobject" is not available.
) at bridge.c:654
#9  0x4283dc9e in spi_atk_bridge_signal_listener (signal_hint=Variable "signal_hint" is not available.
) at bridge.c:1034
#10 0x423a8ec6 in signal_emit_unlocked_R () from /opt/gnome/lib/libgobject-2.0.so.0
#11 0x423aa371 in g_signal_emit_valist () from /opt/gnome/lib/libgobject-2.0.so.0
#12 0x423aa575 in g_signal_emit_by_name () from /opt/gnome/lib/libgobject-2.0.so.0
#13 0x41f683dc in AtkListener::handleChildRemoved (this=0x939ddf0, rxParent= 0xbf7ff404, rxChild= 0xbf7ff3f4)
    at /opt/OpenOffice/src680-m137/vcl/unx/gtk/a11y/atklistener.cxx:184
#14 0x41f6862f in AtkListener::notifyEvent (this=0x939ddf0, aEvent= 0xbf7ff524)
    at /opt/OpenOffice/src680-m137/vcl/unx/gtk/a11y/atklistener.cxx:226
#15 0x40cbd2f8 in comphelper::AccessibleEventNotifier::addEvent () from ./libcomphelp4gcc3.so
#16 0x40cab7d3 in comphelper::OAccessibleContextHelper::NotifyAccessibleEvent () from ./libcomphelp4gcc3.so
#17 0x411b009a in VCLXAccessibleComponent::ProcessWindowEvent () from ./libtk680li.so
#18 0x411af885 in VCLXAccessibleComponent::WindowEventListener () from ./libtk680li.so
#19 0x411af814 in VCLXAccessibleComponent::LinkStubWindowEventListener () from ./libtk680li.so
#20 0x401e0e34 in Link::Call (this=0x542d90c0, pCaller=0xbf7ff6e4) at link.hxx:155
#21 0x401f81dc in VclEventListeners::Call (this=0x939e360, pEvent=0xbf7ff6e4) at /opt/OpenOffice/src680-m137/vcl/source/app/vclevent.cxx:49
#22 0x403f74a7 in Window::CallEventListeners (this=0x939e198, nEvent=501, pData=0x939d890)
    at /opt/OpenOffice/src680-m137/vcl/source/window/window.cxx:5286
#23 0x403f73eb in Window::ImplCallEventListeners (this=0x939e198, nEvent=501, pData=0x939d890)
    at /opt/OpenOffice/src680-m137/vcl/source/window/window.cxx:5267
#24 0x403f2e0c in ~Window (this=0x939d890) at /opt/OpenOffice/src680-m137/vcl/source/window/window.cxx:4311
#25 0x40421f5c in ~Control (this=0x939d890) at /opt/OpenOffice/src680-m137/vcl/source/control/ctrl.cxx:109
#26 0x4041266f in ~Button (this=0x939d890) at /opt/OpenOffice/src680-m137/vcl/source/control/button.cxx:187
#27 0x4041771f in ~PushButton (this=0x939d890) at /opt/OpenOffice/src680-m137/vcl/source/control/button.cxx:1508
#28 0x40420de3 in ~ImageButton (this=0x939d890) at /opt/OpenOffice/src680-m137/vcl/source/control/button.cxx:4078
#29 0x407f866b in svt::CloserButton_Impl::~CloserButton_Impl () from ./libsvt680li.so
#30 0x407f82de in svt::HelpAgentWindow::~HelpAgentWindow () from ./libsvt680li.so
#31 0x510bc49f in framework::HelpAgentDispatcher::closeAgentWindow () from /opt/OOInstall/program/./libfwk680li.so
#32 0x510bc23d in framework::HelpAgentDispatcher::timerExpired () from /opt/OOInstall/program/./libfwk680li.so
#33 0x510eeab2 in framework::OTimerHelper::onShot () from /opt/OOInstall/program/./libfwk680li.so
#34 0x40dd897d in vos::OTimerManager::checkForTimeout () from ./libvos3gcc3.so
#35 0x40dd8ab6 in vos::OTimerManager::run () from ./libvos3gcc3.so
#36 0x40dd6702 in vos::_cpp_OThread_WorkerFunction () from ./libvos3gcc3.so
#37 0x40dd66e9 in _OThread_WorkerFunction () from ./libvos3gcc3.so
#38 0x40e8e8a0 in osl_thread_start_Impl () from ./libuno_sal.so.3
#39 0x4149628b in pthread_start_thread (arg=Variable "arg" is not available.
) at manager.c:310
#40 0x4149631f in pthread_start_thread_event (arg=0xbf7ffbe0) at manager.c:334
#41 0x4173f55a in clone () from /lib/libc.so.6

vs.

(gdb) t 1
[Switching to thread 1 (Thread 16384 (LWP 20328))]#0  0x414992a4 in __pthread_sigsuspend (set=0x414a0484)
    at ../linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c:54
54        INTERNAL_SYSCALL (rt_sigsuspend, err, 2, set, _NSIG / 8);
(gdb) bt
#0  0x414992a4 in __pthread_sigsuspend (set=0x414a0484) at ../linuxthreads/sysdeps/unix/sysv/linux/pt-sigsuspend.c:54
#1  0x41498028 in __pthread_wait_for_restart_signal (self=0x4149fbc0) at pthread.c:1216
#2  0x4149b4fc in __pthread_lock (lock=Variable "lock" is not available.
) at restart.h:34
#3  0x414977c5 in *__GI___pthread_mutex_lock (mutex=Variable "mutex" is not available.
) at mutex.c:112
#4  0x40e8df36 in osl_acquireMutex () from ./libuno_sal.so.3
#5  0x40dd199a in vos::OMutex::acquire () from ./libvos3gcc3.so
#6  0x424ea6a6 in SalYieldMutex::acquire (this=0x80a9040) at /opt/OpenOffice/src680-m137/vcl/unx/source/app/salinst.cxx:93
#7  0x41f4a981 in GtkHookedYieldMutex::acquire (this=0x80a9040) at /opt/OpenOffice/src680-m137/vcl/unx/gtk/app/gtkinst.cxx:91
#8  0x424eac65 in X11SalInstance::AcquireYieldMutex (this=0x80a8f58, nCount=1)
    at /opt/OpenOffice/src680-m137/vcl/unx/source/app/salinst.cxx:284
#9  0x41f4a3ad in ~YieldMutexReleaser (this=0xbfffe930) at saldata.hxx:153
#10 0x41f49522 in GtkXLib::Yield (this=0x80a9108, bWait=1 '\001') at /opt/OpenOffice/src680-m137/vcl/unx/gtk/app/gtkdata.cxx:687
#11 0x424eaca9 in X11SalInstance::Yield (this=0x80a8f58, bWait=1 '\001') at /opt/OpenOffice/src680-m137/vcl/unx/source/app/salinst.cxx:290
#12 0x401eac50 in Application::Yield () at /opt/OpenOffice/src680-m137/vcl/source/app/svapp.cxx:539
#13 0x401eab41 in Application::Execute () at /opt/OpenOffice/src680-m137/vcl/source/app/svapp.cxx:501
#14 0x0806e0a8 in desktop::Desktop::Main ()
#15 0x401f3510 in ImplSVMain () at /opt/OpenOffice/src680-m137/vcl/source/app/svmain.cxx:242
#16 0x401f361b in SVMain () at /opt/OpenOffice/src680-m137/vcl/source/app/svmain.cxx:273
#17 0x08067971 in sal_main ()
#18 0x0806790c in main ()


** What is happening **

+ we are writing down a socket to the same process & blocking until it returns ...
+ unfortunately - we are also holding the Solar Mutex ..
+ even more unfortunately - the impl. is in the current process & the mainloop is blocked by this.

** Foo ! ... **

+ so ... same problem as idle gnome-vfs init at startup (?) 
    + need to be more intelligent about the 'main' GThread
	+ in this case it is us: we 'own' *world* at this stage.


+ ORBit2/src/orb/orb-core/orbit-small.c:
    + ORBit_small_invoke_stub:
	+ calls ORBit_objref_get_proxy
	    + urgh...

+ What can we do here ?
    + can we 

The problem is perhaps here:

2003-05-29  Michael Meeks  <michael ximian com>

        * src/orb/orb-core/orbit-small.c
        (ORBit_small_invoke_stub): check cross-thread calls,
        and generate an in-proc proxy for non-allowed xt cases.

        * src/orb/poa/poa.c (ORBit_poa_allow_cross_thread_call): impl.
        (get_c_method): use it.

        * src/orb/GIOP/giop.c (giop_thread_same_key): impl.

** Same as the VFS problem:

=> ORB initialization ...
    + assuming we initialize the ORB 1st ...
	+ that -does- store a 'primary thread' concept.

    + giop.c (giop_init)
	+ sets 'giop_main_thread' to be the one with the
	  g_main_context_default() association;
	+ sets that thread's thread data to be that ...

    ** Instead **
	+ we need to implement 'g_main_context_is_owner' [ or sim. ]

=> Test:
    ** Need an idle timeout in 1 thread (same [default] mainloop)
       to be locked by another thread etc.

	+ a condition to fire ?
	+ spawn another thread ?

=> Is there a 'default' mainloop ? - does gtk+ assume this ?
    + Yes a default context: "g_main_context_default ()"
    + can we assume it to slave ORBit2 locking from it ?

    + g_main_context_acquire / release
	+ closest equivalent to recursive Solar Mutex ...

    'bool IsMainThread'
	+ if (g_main_context_acquire (NULL))
	  {
	    g_main_context_release (NULL); return TRUE;
	  }
	else return FALSE;

    + etc.

	+ Would - a) check not in I/O thread
	          b) try to grab glib lock to process in-line ?
	  work ?

	+ ST gtk+ apps - biggest concern ...
		+ non-issue; this won't occur.

	+ in our 'client' case:
		+ call 'stub-invoke' from N threads
		+ goes to I/O thread ...
		+ then what ?
			+ no 'glib' thread anyway,
			+ => who should process this ?

	+ whomever is 1st - process in-thread ?
		+ but - if we don't spin the mainloop ...
			+ what happens !?

	+ can we / should we rely on someone running a
	  (default) glib mainloop somewhere ?
		+ [ prolly yes ... ]

	+ The real problem is one of deadlock.
		+ 2 'locks'
			+ g_main_context - to process a request
			+ gdk_threads - to use gtk+

	+ To determine whether to invoke XYZ in-process
	  via fake I/O
		+ need to know if it's possible to process it:
			+ if we can get the g_main_context it is not.
			=> certain that we would block otherwise ?
			=> are we certain that we will deadlock though ?

	+ What about a thread -> I/O to the I/O thread -> but there is no glib mainloop ?

	+ Should we then just do it in-process in the thread ?
		+ if not, 

	+ can we special case 'unrefs' ?
		+ ... urgh ...
		+ can we 'g_idle_add (foo, unref)'

	+ URGH - why don't we just do 'bonobo_object_unref()' ...

	+ foo ...

	+ Can we think of a scenario we would break by doing XYZ ?
		+ when do we spawn the I/O as a separate thread ?
			+ idly ? - when another thread emits a call ...

	+ So - the single-threaded GConf case will still work.
		+ not a problem ...

	+ If we have the 'g_main_context' lock - it is *possible* that
	  we don't have the gdk lock.

	+ what do we break:
		+ the case where thread a) didn't have a glib mainloop,
		+ and thread b) was running it - but not 'in' the loop

	+ g_main_context_acquire/release called top/tail of
		+ g_main_context_iterate ...
		+ with a g_main_run type thing
			+ we ~always hold the context - if we're doing
			  anything useful.

	+ => only 1 thread can be processing 'stuff' on that glib
	  mainloop concurrently.

	+ this is the behavior we want.
		+ not 'thread affine' but 'context affine'

	+ If we hold the Solar mutex to do stuff - the more the merrier.

** Problem:
	+ what about multiple slave threads - only 1 can get the context
		+ but this thread will not process any calls but it's
		  own (probably)
		+ [ in this case - should we spin the glib mainloop a bit ?
** NO:		    *Evil* re-enterancy hazard ... ]

	+ => all these threads need to wait for the main context (?)
		+ [ the I/O thread will do the I/O for us prolly ]
		+ 

	+ So - use g_main_context_wait (context, cont, mutex)
		+ [ this will kick the main-loop & not be a problem ]
		+ [ possibly we also need a 'wakeup' before that ]

	+ moral - your STA shouldn't run the default glib mainloop ? ;->
		+ *OR* your 'other' thread, shouldn't run the default glib mainloop ?
		+ thread-affine gtk+ mainloop in VCL ?

	+ Can we then process the request in-process -if-we-have-that-lock ?
		+ avoids marshalling => also a speedup :-)

	need a:
		+ g_main_really_acquire:
			++ (g_main_context_default())
			while (!g_main_context_wait ()) ;
			... [ call method in-process ] ...
		+ g_main_context_release ();

	* so far:
		+ orbit-policy.c: clean anyway
		+ 
		+ giop.c: fixed.
		+ 

	* ORBit2/src/orb/GIOP/giop.c:
		+ [foo]
		+ give up with this approach - just 'get_main_context'
		  & do it in-line (or emit idly ... [async])

	+ giop_thread_new_check:
		+ the only -legitimiate- use of giop_thread_main
			+ rename to ORB_init_thread
	+ giop_thread_set_main_handler
		+ Needs re-naming to be 'giop_set_incoming_handler'
	+ giop_thread_get_main
		+ needs to die ...
	+ giop_thread_same_key
		+ 1 use in poa.c
	+ giop_thread_self:
		+ dangerous if pushing to a queue eg.

	* ORBit2/src/orb/GIOP/giop-recv-buffer.c:
		+ set src_thread ...
		+ giop_recv_buffer_get - seems sane still.

	* ORBit2/src/orb/orb-core/orbit-policy.c:
		+ clean.

	* ORBit2/src/orb/poa/poa.c:
		+ (ORBit_poa_allow_cross_thread_call)
			+ the main fix necessary is here
			+ the other POA bits - only called from
			  existing I/O that has happened (?)
			  and/or the I/O thread - ie. this problem
			  doesn't apply
			+ thread-same-key bit is fine ...
		+ Other:
			+ (ORBit_POA_handle_request)
				+ requires SINGLE_THREAD re-work ...
			+ ONEWAY_AT_IDLE
				+ also requires re-work.
			+ push_request_T [ take a NULL ? ]
		+ use the right main context foo ...

	* We hurt people who were not running a custom/glib integrated
	  mainloop, and were relying on nothing happening from another
	  thread. c'est-la-vie ...
		+ And were using threads
		+ and were calling 'single threaded' / main appartment
		  calls from them.

	* Linc
		+ seems linc is not thread-affine
		+ except for the I/O thread - fair enough.


* FIXME:
	+ Audit 'main' thread queue & g_main_context wakeup
	  foo ...
		+ need to make sure that whatever giop_get_self
		  returns - we do the work ...
		+ giop_mainloop_handle_input

	+ Do we need a per-thread 'tdata' - for 'is this the main thread'
		+ and also a 'giop_gmain_pseudo_thread' (?)
		+ how will this work for single-threaded case ?

	+ How does this work with people waiting for data to
	  come back ? [ single threaded etc. ? ... ]
		+ either the main 'thread context' or ... ?
		+ Audit giop_recv_list_setup_queue_entry ...

		+ what is the src_thread used for:
		    + giop.c:
			+ giop_invoke_async
				+ [bogus] - check for same thread
				  to emit async callback - needs
				  be 'get_main_appartment_foo' etc. (?)
				+ should instead try to get maincontext ?
				+ should check 'are-we-in-IO-thread?'
					+ if so ... XYZ
			+ else - signal a thread-pool-thread ...
				+ push on/off stack etc. [urgh]

			+ [perhaps detecting foo .. ]
		    + giop-recv-buffer.c
			+ ent_lock / ent_unlock ...
			+ giop_recv_list_zap
				+ giop_incoming_signal_T ...

	+ Some problem:
		+ some non-main-loop async callback functionality
		  not expected...
			+ can get an async callback from an idling
			  method / the inferior mainloop - possibly
			  useful.

	+ How do we know which queue to put it on ?
**NO:	    + For async:
		+ if (no-thread-io)
			=> use main/default context queue.
		  else if (safe_get_main_context)
			=> use main as before
			unlock ...
		  else if (random other)
			set src_thread to current value.

	** Unfortunately
		+ we can accidentally get the glib context
		  'by mistake' ... in a random thread.

	** What are we trying to achieve ?
		+ can we push this back ?
		+ who knows what thread we are really in ?
			+ same async API used for both
			  'call-back-in-this-thread'
			+ and 'call-back-in-main-loop'
		+ Not possible to distinguish in the ORB.
			+ Ergo - we have to make all async
			  calls return in the GMainContext
			+ our only hope ...
		+ of course all returns go to the waiting
		  XYZ thread ...

	** we want to 'take/grab/poke' the GMainContext lock
		+ no way to do that
		+ can't push into the mainloop -> may not be running.
		+ we can require that there is a running loop for that
		  case.
			+ different past ?
			+ have a glib mainloop running ?
				+ ask for the context
				+ if we can't get it push ...
				+ but don't allow re-enterancy.
			+ => foo ...
			+ make tests spin...

	** Did we break anything else ? **
	    ... re-enterancy ...
		+ This also fixes the ORBit2 foo ...
		+ What async invocation stuff do we need
		  for a11y ? ...

	** poa's: thread_push_T
	    + is this ok ?

** 2 problems
    + a) handle_request - have no idea who to hand
         it to / wake-up on 'NULL'
	    + which of the waiting threads is the 'main' one ...
    + as we acquire / release the context over a call
      - we can find out ?
    + b) Handle incoming foo [!?] - no idea what queue to put it on ...
	+ should we have a 'set this as main thread' ?
	    + whomever is waiting & has the lock ?
	    + have no 'main thread' thing; but switch ownership ?
	      + rotate & leave 'the main thread' as the owner
	      + have a lock on it (?)
      + a g_idle_foo - that sets us as the owner ?
      + 

	** "We get a 'handle_reqest'
	    + no idea to whom to hand it ...
	    + no way of knowing if we 'own' the glib mainloop
	      reliably ...
	** if g_get_foo ...
	** then ...

TODO:
    ** Audit 'handle_reply' pointer changes in diff:
    



** Other approaches:
    + just don't do any CORBA IPC in-proc to other objects
	++ OR - tag them all as 'thread-safe' though they are not...


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]