The problem:
    + mono is mind mangled & doesn't expose a sane GC API
    + ie. it wants to know about your entire C stack & wander over it
	+ it should push/pop start/stop tags as we invoke in/out
	+ it should manage C handles with a controlled lifecycle
	  mechanism: ref/unref layered on top of the GC
	    => no need to worry about walking the C stack.
    + however - this is horribly broken somehow.

We really need something like GC_start_routine()
   the start_info would be used to invoke our fn. and cleanup would
   be automatic.

* RedHerring 1: what is:
    GC_push_all_stack(self, <base ptr>)
    called from GCThreadFunctions mono_gc_thread_vtable
	-> mono_gc_push_all_stacks
	    + for the debugger [ libgc/include/libgc-mono-debugger.h ]

    
* The pthread_support.c code seems to be not much called:
	GC_segment_is_thread_stack - only from some dlopen code
	    GC_register_map_entries() [ filtering out code regions ? ]

	    * seems to call GC_add_roots *

	    /* Add a root segment.  Wizards only. */
	    GC_API void GC_add_roots GC_PROTO((char * low_address,
	    				       char * high_address_plus_1));
	   /* Remove a root segment.  Wizards only. */
	   GC_API void GC_remove_roots GC_PROTO((char * low_address, 
				                char * high_address_plus_1));


* Adding a thread has to set the GC_suspend_handler / GC_restart_handler
    + cf. pthread_stop_world, pthread_stop_init (?)

    + GC_stop_world uses the stop_world method from the vtable ...
	    GCThreadFunctions *gc_thread_vtable = &pthread_thread_vtable;

    => We need thread data to ensure we have stopped all the threads properly.
	    => we need to setup / install our signal handler properly in
	       each thread.

    + The high stack pointer is grokked from the 
      GC_approx_sp function - from the signal handler - just
      returns cur ptr. - signal handler executing on stack of
      signal recieving thread. [ fun ]

* GC_push_all_stacks [ pthread_stop_world.c ]
    + calls 'push_all_stack' for each thread.
	    + called from os_dep.c (GC_default_push_other_roots)
		    [ GC_push_other_roots ]

* Hacking libgc:

<lupus> yes, I suggest just duplicating the needed code for now
<michael_> lupus: is this a minimal-changes regimen ? or a wild-crazy-re-factoring-festival ?
<lupus> michael_: no crazy refactoring:-)
<michael_> lupus: and what does one do about a non-internal libgcj ? - or is that not a case worth worrying about ?
<lupus> michael_: we'll use the proper ifdef in the mono runtime
<michael_> sure - but it's ok to break horribly if we're not using an internal libgcj ? ;-)
<lupus> but a not internal gc is just for our testing, it's not a supported feature for people to use
<michael_> ie. no foreign-thread / OO.o impl. ?
<michael_> oh - great :-)

** How does Mono get a callback from the pthread foo ?
    + 

We need to add the functionality we need to mono_thread_attach


2005-04-12 log:

<michael_> lupus: so - are you utterly opposed to adding this to mono_runtime_invoke ?
<lupus> michael_: why should I be opposed?
<michael_> lupus: there is a small cost, particularly if you don't have a thread-variable,
<michael_> lupus: of course - then we could bin the mono_thread_attach or whatever;
<lupus> michael_: unmanaged->managed is not an important transition and a simple check is cheap
<lupus> of course there is no need to drop mono_thread_attach
<michael_> lupus: ok'y dokey,
<michael_> lupus: so - I'll re-work the patch to move this code into mono_runtime_invoke ?
<lupus> michael_: if your current patch works for you, I can write the equivalent code for the next mono release
<lupus> we're not going to remove the thread info at the end of _invoke
<lupus> something like the setspecific hack you had may be enough
<michael_> lupus: the problem is - we could get invoked again from lower down the stack in the same thread trivially.
<michael_> lupus: so - it's really no safer;
<michael_> lupus: and removing the thread information from the gc post invoke - [ if we added it ourself ] is cheap anyhow.
<lupus> that is not cheap, it requires locking both in the runtime and the GC
<lupus> I don't see what removing the info each time buys us
<michael_> lupus: consider A() -> B() -> C() -> runtime_invoke -> adds stack base --><--
--> eno (~atsushi@east94-p4.eaccess.hi-ho.ne.jp) has joined #mono
<lupus> the code I have in mind will check the stack start registered: if it doesn't contain the current stack address, we change it
<michael_> lupus: subsequently A() -> runtime_invoke -> stack base is now --><--
<michael_> lupus: sounds fine,
<lupus> it will also register an aligned address
<michael_> lupus: sounds fine,
<lupus> at a page size so hopefully we get a good enough approximation of the thread start
<michael_> lupus: sounds like you've got it under control anyhow
<michael_> clearly manipulating the local thread stack/state should require precisely no locking in an ideal world ;-)
<michael_> but ...
<michael_> [ when we write a better GC - we'll make it perfectly precise - right ? ;-]
<lupus> michael_: since you need to register the thread with the GC it's not possible to avoid a lock, since it's global state
<lupus> and we won't have a perfectly precise GC
<michael_> lupus: AFAICS the GC only asks for that when a signal is fired,
<lupus> the unamanged stack will still be conservatively scanned for a while
<lupus> michael_: the GC needs the stack boundaries when doing collection
<michael_> lupus: I appreciate that ;-)
<michael_> lupus: anyhow - thanks for taking that on.
<michael_> lupus: when is the next release ? :-)
<lupus> michael_: likely in a month or so
