<html>
<head>
<style>
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
FONT-SIZE: 10pt;
FONT-FAMILY:Tahoma
}
</style>
</head>
<body class='hmmessage'>Tony, Yep, I got my true/false backwards at least once.<BR>
 <BR>
 > I have no  objection. <BR>
 <BR>
Thanks. Expect a few deleted lines "soon".<BR>
 <BR>
<DIV> > When does the GC currently create a thread?</DIV>
 <BR>
I'd have to double check. I thought it was in RTAllocator's module initialization. But maybe not.<BR>
No mystery here, just that I'm out of Modula-3 mode for a few hours.<BR>
It might be on-demand actually -- which would then have to be synchronized -- so doing it early might be preferable..er...well...actually..problem either way I now realize, depending..<BR>
 <BR>
There is this interesting useful but problematic aspect of .dlls on Windows.<BR>
.dlls have an "entry point", a "main" if you will. Usually called DllMain, but the name can be anything. It isn't exported, it's a field in the file format. The signature is<BR>
BOOLEAN DlMain(int reason, ADDRESS opaqueHandleToSelf, ADDRESS additionalBit);<BR>
 <BR>
The reasons are<BR>
  process attach, process detach, thread attach, thread detach <BR>
  the opaqueHandleToSelf can be used for example to load "resources" from yourself<BR>
  additionalBit has a null vs. non-null meaning<BR>
    when reason == process detach, the nullness indicates if the .dll is being unloaded because the process is going away, or it is being unloaded but the process is staying around -- if the process is going away, basically nothing should be done, if the process is not going away, cleanup any process-global resources <BR>
 <BR>
Process attach means the .dll was "just" loaded.<BR>
 <BR>
If you return false for failure from process attach, then the process will fail to launch or the LoadLibrary (dlopen) will fail, depending on if you are a static dependency of the .exe, or dynamically loaded via LoadLibrary (dlopen).<BR>
 <BR>
I believe the return values from all the other reasons are ignored.<BR>
 <BR>
There are many oddities here. Including the fact that threads can be created before the .dll loads and destroyed after it unloads, so the interface of thread attach/detach isn't what it seems -- you don't necessarily get the calls, you only get the calls for threads created/destroyed while you are already loaded (and perhaps one extra when you get loaded/unloaded?)<BR>
 <BR>
Folks who think they can do their per-thread cleanup in thread detach are sorely wrong.<BR>
What you have to do is keep all your thread-locals in a global list and free them in process detach.<BR>
Or just don't have any, that's the best policy.<BR>
 <BR>
Now, the important aspect here is that there is a lock around all DllMain calls, be they the process or thread ones.<BR>
 <BR>
This is "useful" because it means you can initialize your globals without worrying about synchronization.<BR>
Now, because of the lock, there isn't much you can do without risking deadlock.<BR>
But you would typically limit your activities to heap allocation, TlsAlloc (pthread_threadspecific_allocate_key or such), and critical section initialization. Win32 critical sections sadly require an initialization call, rather than just being initialized to all zeros. There's an API in Vista to allow static initialization.<BR>
(Cygwin's pthreads stuff also doesn't have zero initialization, but at least static).<BR>
 <BR>
On-demand initialization outside of DllMain must be synchronized, as threads can be created fairly arbitrarily early.<BR>
If you create a thread in DllMain, it essentially won't start until all the DllMains return.<BR>
It is possible though to have multiple threads running concurrently with "main".<BR>
 <BR>
And just because "you" don't create a thread in your app/.exe, doesn't mean some .dll you loaded didn't create some.<BR>
There's no such thing as a single-threaded process.<BR>
 <BR>
I suspect there is therefore a problem here in Modula-3. Or at least some double checking needed -- around the thread safety of various initialization.<BR>
 <BR>
A common pattern in Win32 is /ROUGHLY/:<BR>
 <BR>
T* g_pt; // global pointer to a T<BR>
 <BR>
T* GetTheT(void)<BR>
{<BR>
  if (g_pt != NULL)<BR>
    return g_pt;<BR>
  T* pt = new T();<BR>
  MemoryBarrier(); // ensure T's constructor finished before storing the global pointer<BR>
  if (InterlockedCompareExchangePointer(&g_pt, pt, NULL) != NULL)<BR>
   {<BR>
     // somebody else won the race<BR>
    delete pt;<BR>
   }<BR>
   return g_pt;<BR>
}<BR>
 <BR>
This way, initialization is done on-demand and thread safely.<BR>
This code assumes that race conditions will be rare vs. the expense of creating a T that is thrown away, and that creating, multiple T's in the event of a race, only to cleanup all but one right away, is ok.<BR>
 <BR>
If you must not ever create more than one T, then other code is needed.<BR>
Easiest is to initialize a critical section in DllMain and then just use that.<BR>
 <BR>
Or implement a little spin lock, assuming initialization of T is cheap.<BR>
 <BR>
In Vista there is a "once" synchronization object for handling this.<BR>
It is very disappointing that this wasn't introduced 10+ years ago.<BR>
As well as statically initializable locks and reader/writer locks.<BR>
 <BR>
I keep tending to think that Modula-3 module intializers have this same lock, at least on Windows.<BR>
But that is definitely NOT necessariiy true, at least in the face of static linking, and probably even with dynamic linking, since Modula-3 implements this stuff itself.<BR>
 <BR>
I'll have to review the code. Maybe it is just fine already.<BR>
 <BR>
If it isn't, well, there are a few easy solutions.<BR>
As well, this could be a problem on all platforms.<BR>
So it might make sense for the runtime to recognize when it is calling module initializers and endeavor to "not start" any threads while they are running.<BR>
 <BR>
Corrallary, on Win32, and in this scheme, that if you create  a thread in DllMain/thread initializer and then wait for it to make progress, you deadlock.<BR>
 <BR>
Gotta run,<BR>
 - Jay<BR><BR>
<BLOCKQUOTE>
<HR id=EC_stopSpelling>
CC: m3devel@elegosoft.com<BR>From: hosking@cs.purdue.edu<BR>To: jayk123@hotmail.com<BR>Subject: Re: [M3devel] eliminate Target.Global_handler_stack?<BR>Date: Mon, 12 May 2008 19:43:35 -0400<BR><BR><BR>
<DIV>
<DIV>On May 12, 2008, at 7:35 PM, Jay wrote:</DIV><BR class=EC_Apple-interchange-newline>
<BLOCKQUOTE><SPAN class=EC_Apple-style-span style="WORD-SPACING: 0px; FONT: 12px Helvetica; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate">
<DIV class=EC_hmmessage style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">Target.Global_handler_stack is FALSE for targets that ever use kernel threads.<BR>Target.Global_handler_stack is TRUE for targets that never use kernel threads.<BR>Targets that can go either way set it to FALSE.<BR> <BR><BR>When Global_handler_stack is TRUE, inline code is generated to,<BR>  I guess, manipulate a per-thread linked list of stack frames.<BR><BR> <BR>When Global_handler_stack is FALSE, function calls are generated<BR>  to do same.<BR><BR> <BR>That is, Global_handler_stack is TRUE is a little more efficient.<BR><BR> <BR>Given that Global_handler_stack is TRUE for all "recent", "active", "interesting"<BR>  targets, with the presumably temporary exception of PPC_LINUX, how about<BR>  we remove Global_handler_stack as a variable and just act as if it is always FALSE?</DIV></SPAN></BLOCKQUOTE>
<DIV><BR></DIV>Don't you mean "false" for all current targets (i.e., using threads)?</DIV>
<DIV><BR>
<BLOCKQUOTE><SPAN class=EC_Apple-style-span style="WORD-SPACING: 0px; FONT: 12px Helvetica; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate">
<DIV class=EC_hmmessage style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">(I have some suspicion that this linked list is absent on targets<SPAN class=EC_Apple-converted-space> </SPAN><BR>with a stack walker, so it'd make no difference on them. I'll check later..<BR>NT386 ought use fs:0 but it doesn't.)</DIV></SPAN></BLOCKQUOTE>
<DIV><BR></DIV>
<DIV>Indeed, the list is absent on such targets.</DIV><BR>
<BLOCKQUOTE><SPAN class=EC_Apple-style-span style="WORD-SPACING: 0px; FONT: 12px Helvetica; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate">
<DIV class=EC_hmmessage style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">I figure target-specificity should be minimized.<BR>Make it easier to bring up new targets -- not that the code isn't pretty<BR>  well commented and easy to understand, so it's really no easier without this.</DIV></SPAN></BLOCKQUOTE>
<DIV><BR></DIV>I have no  objection. 
<DIV><BR></DIV>
<BLOCKQUOTE><SPAN class=EC_Apple-style-span style="WORD-SPACING: 0px; FONT: 12px Helvetica; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate">
<DIV class=EC_hmmessage style="FONT-SIZE: 10pt; FONT-FAMILY: Tahoma">The counterpoints would be:<BR>  Even if it is target-specific, it does work and isn't complicated, so leave it alone.<BR>  If those old targets are alive, and lack pthreads, it is<SPAN class=EC_Apple-converted-space> </SPAN><EM>slightly<SPAN class=EC_Apple-converted-space> </SPAN></EM>faster this way.<BR>  If people want current/new targets to have a "faster" single threaded mode, this<SPAN class=EC_Apple-converted-space> </SPAN><BR>   could be part of that. Note though that single threaded apps can't/don't exist,<BR>   unless maybe if you never heap allocate, since the heap allocator/garbage collector<BR>   creates a thread at initialization (shouldn't it wait for a heap allocation? Maybe.<BR>   If there really is a chance it won't occur or won't occur for a while).</DIV></SPAN></BLOCKQUOTE>
<DIV><BR></DIV>
<DIV>When does the GC currently create a thread?</DIV></DIV></BLOCKQUOTE></body>
</html>