Tcl Source Code

View Ticket
Login
Ticket UUID: 219355
Title: fix proposal for TR#5312 (part 2)
Type: Bug Version: obsolete: 8.4a1
Submitter: nobody Created on: 2000-10-26 05:11:16
Subsystem: 49. Threading Assigned To: davygrvy
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2002-10-02 13:34:03
Resolution: Fixed Closed By: davygrvy
    Closed on: 2002-10-02 06:34:03
Description:
OriginalBugID: 5829 Bug
Version: 8.4a1
SubmitDate: '2000-06-06'
LastModified: '2000-09-01'
Severity: LOW
Status: UnAssn
Submitter: techsupp
ChangedBy: davidg
RelatedBugIDs: 5793 5312
OS: Windows 2000
FixedDate: '2000-10-25'
ClosedDate: '2000-10-25'


Name:

David Gravereaux



CVS:

updated saturday



CustomShell:

my tclAsync.c patch



Comments:

This appears to be working with SetConsoleCtrlHandler and the

    CtrlHandler returning TRUE, so Win32 doesn't kill it.  I think

    I was being too aggressive with

    CloseHandle(GetStdHandle(STD_INPUT_HANDLE));

    as Tcl_Gets in Tcl_Main was properly dropping-out.  The

    tclWinNotify.c change is there just for the DLL as that's a

    possible senario with a threaded build.



ObservedBehavior:

Ctrl+C crashes tclsh84.exe rather then a clean exit.



Patch:

*** win/tclAppInit.c1999/12/02 02:03:371.6

--- win/tclAppInit.c2000/06/05 00:50:23

***************

*** 29,35 ****

--- 29,39 ----

  #endif /* TCL_TEST */

  

  static voidsetargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr));

+ static BOOL __stdcallsigHandler _ANSI_ARGS_((DWORD fdwCtrlType));

  

+ Tcl_AsyncHandlerexitToken;

+ Tcl_AsyncProcasyncExit;

+ 

  

  /*

   *----------------------------------------------------------------------

***************

*** 156,161 ****

--- 162,170 ----

              Procbodytest_SafeInit);

  #endif /* TCL_TEST */

  

+     SetConsoleCtrlHandler(sigHandler, TRUE);

+     exitToken = Tcl_AsyncCreate(asyncExit, (ClientData) interp);

+ 

      /*

       * Call the init procedures for included packages.  Each call should

       * look like this:

***************

*** 298,301 ****

--- 307,375 ----

  

      *argcPtr = argc;

      *argvPtr = argv;

+ }

+ 

+ /*

+  *----------------------------------------------------------------------

+  *

+  * asyncExit --

+  *

+  *The AsyncProc for the exitToken.

+  *

+  * Results:

+  *doesn't actually return.

+  *

+  * Side effects:

+  *tclsh cleanly exits.

+  *

+  *----------------------------------------------------------------------

+  */

+ 

+ int asyncExit (ClientData clientData, Tcl_Interp *interp, int code)

+ {

+     char *buffer = "exit -1";

+     Tcl_Eval((Tcl_Interp *) clientData, buffer);

+ 

+     /* NOTREACHED */

+     return code;

+ }

+ 

+ /*

+  *----------------------------------------------------------------------

+  *

+  * sigHandler --

+  *

+  *Signal handler for the Win32 OS.  Catches Ctrl+C, Ctrl+Break and

+  *other exits.  This is needed so tclsh can do it's real clean-up

+  *and not an unclean crash terminate.

+  *

+  * Results:

+  *TRUE.

+  *

+  * Side effects:

+  *effects the way the app exits from a signal.  This is an 

+  *operating system supplied thread and unsafe to call ANY

+  *Tcl commands except for Tcl_AsyncMark.

+  *

+  *----------------------------------------------------------------------

+  */

+ 

+ BOOL __stdcall sigHandler(DWORD fdwCtrlType)

+ {

+     /*

+      *  If Tcl is currently executing some bytecode or in the eventloop,

+      *  this will cause Tcl to enter asyncExit at the next command

+      *  boundry.

+      */

+     Tcl_AsyncMark(exitToken);

+ 

+     /*

+      *  This will cause Tcl_Gets in Tcl_Main() to drop-out with an <EOF>

+      *  should it be blocked on input and our Tcl_AsyncMark didn't grab

+      *  the attention of the interpreter.

+      */

+ /*    CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); */

+ 

+     /* indicate to the OS not to call the default terminator */

+     return TRUE;

  }



*** win/tclWinNotify.c1999/07/02 22:08:281.5

--- win/tclWinNotify.c2000/06/05 00:50:37

***************

*** 150,155 ****

--- 150,163 ----

  {

      ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;

  

+     /*

+      *  Should the operating system call DllMain with

+      *  DLL_PROCESS_DETACH from any alternate thread path, such

+      *  as Task Manager terminating the process, tsdPtr will

+      *  be NULL and invalid.

+      */

+     if (tsdPtr == NULL) return;

+ 

      DeleteCriticalSection(&tsdPtr->crit);

      CloseHandle(tsdPtr->event);



PatchFiles:

win/tclAppInit.c

    win/tclWinNotify.c
User Comments: davygrvy added on 2002-10-02 13:34:03:
Logged In: YES 
user_id=7549

To me, I look at this as a pure bug fix.  As wish gets going 
down notices because the system closes the UI windows, 
tclsh gets no notices.

A Ctrl+C brings down tclsh improperly from an unknown 
native thread, but with this patch the main thread is used 
which to me, seems like the proper solution then living with 
checks in TclFinalizeNotifier that aviod cleanup due to 
missing thread-specific data.

dgp added on 2002-09-30 21:01:12:
Logged In: YES 
user_id=80530


Haven't followed this one closely; just curious about the
recent commit.  Are we sure it's OK to go in between
an 8.4.0 release and an 8.4.1 release?  Or should it wait
for a real "alpha" development branch to open on the HEAD?

I've got nothing against the patch technically -- haven't
examined it.  Just want to be careful about large-ish,
potentially interface-changing changes during point releases.

davygrvy added on 2002-09-30 07:11:11:
Logged In: YES 
user_id=7549

Fix committed to HEAD for -r1.9

davygrvy added on 2002-09-29 07:50:26:

File Deleted - 31994: 



File Added - 31995: patch.txt

davygrvy added on 2002-09-29 07:47:48:

File Added - 31994: patch.txt

Logged In: YES 
user_id=7549

Adding updated patch file.

davygrvy added on 2002-06-18 08:52:24:
Logged In: YES 
user_id=7549

Jeff,

How do you feel about this?:

>The scary part is that the simplicity of tclAppInit.c will get 
>destroyed and start taking on windows specifics.  It'll be a 
>first to #include <windows.h>.
>
>If it does, a real shell with colors and mouse support 
>accessing the console API couldn't be far off as the door
>would be open...

Just wondering.  The possibility for nice interactive tclsh 
behavior on Win9x would be a plus: up-arrow for history and 
in-place editing.  Just NT does this by default.

davygrvy added on 2002-05-28 13:37:57:
Logged In: YES 
user_id=7549

Yes, half this problem still occurs in 8.4a4.  Just build for 
threads, start tclsh, then exit by way of the 'X' upper right 
button.  It doesn't go "boom" anymore because the 
tclWinNotify.c change is there, but no exit handlers get run.  
At least, it doesn't look this way...  I could be wrong.  
The "exit request" should get "posted" in some manner to the 
main thread.

dkf added on 2002-04-08 16:12:03:
Logged In: YES 
user_id=79902

ISTR doing something to do with threads that Tcl didn't
control doing things with shutting down Tcl fairly recently
(I didn't *understand* it, but nonetheless...)  Does the
problem still occur in 8.4a4 (I think it made the cut)?

davygrvy added on 2002-04-07 11:46:24:
Logged In: YES 
user_id=7549

>  Instead, my problem could be fixed cleanly *along* with
>bug 5312
>    by changing Tcl_Finalize to correctly finalize Tcl even
>    if called on a virgin, never-called-Tcl-before thread.

I like that solution the best.  How would the code look?  
Should we track all threads where a notifier is 
initialized?  Should a Tcl_Finalize() also hard close all 
running threads, too?

dgp added on 2002-04-07 07:09:59:
Logged In: YES 
user_id=80530

>From "Egon Pasztor" <[email protected]>


 Hi, I'm using Tcl 8.3.1 on a Windows 2000 Dual-Pentium III PC;
     exploring with Microsoft Visual C++ 6.0.

 This is regarding bug TR#5312 as listed on the scriptics
tcl bug 
database
    -- "Application Error" when closing tclsh83.exe
        (tcl8.3.1 with threads) Tcl Core"

     >> From www.scriptics.com, bug database, TR#5312:
     >
> ObservedBehavior: Tclsh83.exe throws an "Application Error"
     > when terminated with "Close" from the window's menu.
     > It does that ONLY with activated thread support.


 I ran into .. sortof a more severe version of this bug,
     and ended up tracking it here.   I notice additional
     information has been posted:


     >> From www.scriptics.com, bug database, TR#5312:
     >
> It throws the exception on line 151 of tclWinNotify.c in
     > Tcl_FinalizeNotifier().  It looks like the notifier
     > data coming in to the function is invalid.


 Invalid indeed -- on my computer, zero, uninitialized:
 I think the problem is that TclFinalizeNotifier (tclNotify.c)
   is being called from a thread in which TclInitNotifier
was never 
called.

     > This needs a more thorough investigation.

  .... read on ...  :)



 
===================================================================
  ====================         1         
===========================
 
===================================================================


 I see that Tcl_FinalizeNotifier (tclWinNotify.c)
    is actually called by TclFinalizeNotifier (tclNotify.c),
    which contains the lines


     >> ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
     >> ....
     >> Tcl_FinalizeNotifier(tsdPtr->clientData);


 This macro, "TCL_TSD_INIT",
    gets a pointer to thread-local-storage if some has been
allocated,
    or allocates some new if none has.

 So ** if TclFinalizeNotifier were called
       from a thread that had no thread-local-storage
constructed **

   then TCL_TSD_INIT would allocate fresh space, filled with
zeros;
      and pass it into Tcl_FinalizeNotifier, causing the crash.


                     -- -- -- -- -- -- -- --

 This is what I think is happening --
 I tried to trace the antics of the various threads
   started and stopped while executing the steps needed
   to reproduce the crash
                            -- (ie, starting tclsh83,
                                then selecting "CLOSE" from
                                the console's pull-down menu) --

   the "CLOSE" signal seems to cause Tcl_Finalize
(tclEvent.c) to be 
called
     (from DllMain (tclWin32Dll.c)) from within a new,
virgin thread --
     one which has never yet called any Tcl function at all.


 Tcl_Finalize calls Tcl_FinalizeThread (tclEvent.c),
    which calls TclFinalizeNotifier.



 
===================================================================
  ====================         2         
===========================
 
===================================================================



  That is, *Suppose* that Tcl_Finalize were called on such a
virgin 
thread:

    A:  I see that one of the first lines in Tcl_Finalize
(tclEvent.c) 
is

          >> tsdPtr = TCL_TSD_INIT(&dataKey);

        if this were a "virgin" thread, this line would *create*
          new thread-local storage, associated with the
"dataKey"
          in that file (tclEvent.c).



    B:  The next block of code is protected by an "if" statement

          >> if (subsystemsInitialized != 0) {

        presumably to keep Tcl_Finalize from doing anything
if no Tcl
        functions have ever run.  But I'm supposing that we
are at the
        end of a successful Tcl program; Tcl functions
*have* been 
called,
        and all subsystems initialized; just nothing from
*this* thread.

        So control proceeds into the main body of
Tcl_Finalize ...



    C:  ... down to the call to Tcl_FinalizeThread, about
halfway
        through the body of Tcl_Finalize.

        Tcl_FinalizeThread (tclEvent.c) begins with

          >> ThreadSpecificData *tsdPtr =
          >> (ThreadSpecificData
*)TclThreadDataKeyGet(&dataKey);
          >>
>> if (tsdPtr != NULL) { ....

        which gets a pointer to thread-local-storage in a
manner that
          doesn't create the storage if it's not already
present --
          and checks it for NULL.

        However, thread-local-storage for this thread *was*
created
          in Tcl_Finalize (see point A, above) -- and with
the same
          dataKey, since control is still in (tclEvent.c).

        So control proceeds past the if-statement's guard
into the
          main body of Tcl_FinalizeThread ...


    D:  Most of what follows in Tcl_FinalizeThread is in a
loop that
          will be skipped if "tsdPtr->firstExitPtr" is 0.

        Since the thread-local-storage was just allocated,
          it is likely to be 0,
          so control will make it down to
          the call to "TclFinalizeNotifier".


    E:  Which brings us back to the scenario posited above --
        TclFinalizeNotifier (tclNotify.c)
        begins with

          >> ThreadSpecificData *tsdPtr =
TCL_TSD_INIT(&dataKey);

        which allocates another new block of
thread-local-storage
          (since this is a different "dataKey", in
tclNotify.c now)
        and proceeds to call Tcl_FinalizeNotifier
        with its uninitialized contents, causing the crash.

 )



 
===================================================================
  ====================         3         
===========================
 
===================================================================


  So it looks like Tcl_Finalize would crash if called from a
virgin 
thread.
  I think this is what actually happens:


  According to the Microsoft documentation, a DLL's DllMain
function
    is called off and on for one of four reasons,
      "DLL_PROCESS_ATTACH",   "DLL_PROCESS_DETACH"
      "DLL_THREAD_ATTACH", & "DLL_THREAD_DETACH"

  So I put calls to my own "printf-like" external
message-logging 
function
    inside "DllMain" (tclWin32Dll.c) to watch the threads
startup
    and shutdown.


          >> From www.scriptics.com, bug database, TR#5312:
          >
> So it looks like the OS might be terminating
          > running threads for us in reverse order.


  Well.. not "reverse order", exactly.
  It seems that when the user selects "CLOSE" from the
console's menu,
    Windows actually spawns a *brand new thread* from which
to call
    "ExitProcess"  -- calling DllMain (DLL_PROCESS_DETACH))
                          -- calling Tcl_Finalize
                          -- all from within this virgin thread.


                     -- -- -- -- -- -- -- --

  That is, a dump of all the calls to DllMain during a run
of tclsh83
  looks like this:

   <1>: DllMain (DLL_PROCESS_ATTACH) is called on thread A
         (The main thread starting up; "main" (tclAppInit.c)
is called 
next
          .. this calls Tcl_Main, which inits lots of things
.. and 
soon:

   <2>: DllMain (DLL_THREAD_ATTACH) is called on thread B
         (Evidently running "ConsoleReaderThread" in
tclWinConsole.c;
          a thread "managing" STDIN in some way; spawned by
          CreateThread called in TclWinOpenConsoleChannel 
(tclWinConsole.c))

   <3>: DllMain (DLL_THREAD_ATTACH) is called on thread C
         (Same thing, this time "ConsoleWriterThread",
managing STDOUT)
         ... now the console appears on screen and cursor's
blinking ...
         ... and after the first command is interpreted, we
get one 
more:

   <4>: DllMain (DLL_THREAD_ATTACH) is called on thread D
         ... to represent STDERR.

         *Now* .. Take your mouse to the console menu and
select CLOSE 
...
                  and we get ...

   <5>: DllMain (DLL_THREAD_ATTACH) is called on thread E
         ..  ?? ?? ?? Evidently started by Windows ?? ?? ?? ..
         followed by

   <6>: DllMain (DLL_PROCESS_DETACH) is called on thread E
         -- which calls Tcl_Finalize on thread E,
            causing the crash as traced above, since thread E
            has no Tcl initializations.


                     -- -- -- -- -- -- -- --

  If instead, after Event 4, instead of selecting CLOSE you
    simply type "exit", and execute it,
    it gets interpreted (in thread A of course)
    calling Tcl_Exit,
       calling Tcl_Finalize (in thread A, the Tcl thread)
       and everything is fine.

    Tcl_Exit next calls TclpExit, which is #defined to the
       native OS "exit" (tclWinPort.h) --
         (all this still on thread A)
       -- which finally kills the process.

  So in this case, instead of Events 5 and 6,
    there is simply

    <5>: DllMain (DLL_PROCESS_DETACH) is called on thread A

    .. (which, of course, calls Tcl_Finalize a second time
        (still on thread A) .. but Tcl_Finalize checks for
this.)


 
===================================================================


  When I first saw this, I was initially surprised that
there weren't
    any "DLL_THREAD_DETACH"'es.  Oddly, I'd thought that
they would
    come in predictable pairs.   Nope.

  I found confirmation of this in Microsoft Docs on "DllMain"

   >>
http://msdn.microsoft.com/library/psdk/winbase/dll_8asu.htm

which contains the text:


      > When a DLL is unloaded from a process as a result of
      > ... termination of the process ...
      > the system does not call the DLL's entry-point function
      > with the DLL_THREAD_DETACH value for the individual
threads
      > of the process. The DLL is only sent a
DLL_PROCESS_DETACH
      > notification.


 
===================================================================


  I was less successful in finding official explanatation of
this
    random extra "thread E" started when the user selects
"CLOSE"
    in the console's menu.

  The best documentation I could find was noting that the
Microsoft
    Docs for Win32's "SetConsoleCtrlHandler" -- the API for
setting
    a CLOSE or Control-C handler --

    >>
http://msdn.microsoft.com/library/psdk/winbase/conchar_599u.htm

-- continually refer to these things -- Control-C,
Control-BREAK,
     perhaps CLOSE too -- as "signals", reminiscent of Unix
signals,
     and the Microsoft Doc for "signals" --

    >>
http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_crt_signa
l.htm

  -- contains the .. umm.. ominous warning:

      > When a CTRL+C interrupt occurs, Win32 operating systems
      > generate a new thread to specifically handle that
interrupt.
      > This can cause a single-thread application such as UNIX,
      > to become multithreaded, resulting in unexpected
behavior.


  (This makes me wonder about bug TR#4132 as well --
("Control-BREAK"
   causing a hang in tclsh) -- deadlock from unexpected
multithreading?)


  But the reality of this "thread E" created just to handle
the CLOSE
  is confirmed:  If you actually register a "CLOSE handler"
function,
  using "SetConsoleCtrlHandler" -- it is called on "thread E".




 
===================================================================
  ====================         4         
===========================
 
===================================================================


  On the scriptics page, it is suggested:


          >> From www.scriptics.com, bug database, TR#5312:
          >
> I'll assume right now that tclAppInit.c (the app,
          > not the dll) might need a control-c handler
provided by
          > Win32's SetConsoleCtrlHandler() for a controlled
shut-down

  and of course, the problem *can* be overcome this way.

  The simplest thing I can think of is
    .. "well, if Tcl_Finalize is going to get called on
thread E,
        let's make sure Tcl is initialized on it."

  By adding the function:


    >> BOOL WINAPI HandlerRoutine (DWORD dwCtrlType)
    >> {
    >> Tcl_DeleteInterp(Tcl_CreateInterp());
    >> return FALSE;
    >> }

  to (tclAppInit.c), along with a call to

    >> SetConsoleCtrlHandler(HandlerRoutine, TRUE);

  inside "main", the problem goes away,
  and you can CLOSE tclsh83 with ease.


                        BUT


  (and this brings us to the point of my long email)

  I'd like to suggest a deeper solution --
  one that would also fix * my * problem.


 
===================================================================
 
===================================================================


  Because the "fundamental" problem seems to be that
    it looks like Tcl_Finalize wasn't designed to be called
    from a non-tcl thread;
      And I ran into this bug from a completely different angle.


  * Me *, I'm writing a C++ program,
      with a Tcl/Tk interpreter embedded in it.


  Mine is a multithreaded Win32 application, not console at all,
     but most of the time it works invisibly, (no windows at
all)
     and only with native Win32 calls.

     Only some of the time (ie, not every time the program runs)
       do I need to pop up a GUI --- for which I init and
use Tk.

  So basically:

    Most of the time:

        My program starts (Thread A)
         .. runs for a while ..
            and then exits and (Thread A) dies.

    However, sometimes:

        My program starts (Thread A)
         .. runs for a while ..
         .. something happens requiring a GUI

              .. so I spawn (Thread B),
                 which runs code cut-and-pasted from (tkMain.c)
                 to start a tk-based GUI
              .. which runs for a while ..
              .. and then is stopped,
                 interpreter deleted, thread finalized,
                 (Thread B) dies.

         .. and then some time later,
            my program exits and (Thread A) dies.


  But every time my program uses Tk, when my program
subsequently
     exits, I get the same Tcl_FinalizeNotifier crash --
     the cause being the same thing:

        When thread A exits,
           Tcl/Tk DllMain's are called with DLL_PROCESS_DETACH
             which calls Tcl_Finalize ---- from thread A

         But my main thread -- thread A -- is not a tcl thread,
             and so none of its "Notifiers" have been
initialized.




        ###############################################
        ##  Hey, has this bug been reported before?  ##
        ###############################################

  I've seen oodles of examples of embedding Tk
         into a single-threaded C++ application,
      and many examples of embedding Tk into many threads
      of a multi-threaded C++ application, always invariably
      including the main thread.

  But had anyone tried to embed Tk into *only subordinate
threads*
      of a C++ application, and seen this problem?

        ###############################################
        ###############################################



  Of course, there are tons of workarounds --
      it's easy to initialize Tcl on the main thread;
      a simple Tcl_DeleteInterp(Tcl_CreateInterp()) does it,
      and then the implicit Tcl_Finalize caused by DLL unloading
      would work.   But this.. feels hacky -- having to
initialize
                    stuff just so the finalizer doesn't crash.

  Or I could abandon automatic DLL loading
      and switch to explicity loading and unloading the Tcl
      library in thread B -- this would prevent Tcl_Finalize
      from being called on thread A at all -- but this is a
pain.

  Instead, my problem could be fixed cleanly *along* with
bug 5312
    by changing Tcl_Finalize to correctly finalize Tcl even
    if called on a virgin, never-called-Tcl-before thread.




 
===================================================================
  ====================         5         
===========================
 
===================================================================


  Naively, this doesn't seem hard --

     1:  Tcl_Finalize (tclEvent.c)
         starts with the line

           >> tsdPtr = TCL_TSD_INIT(&dataKey);

         which runs the risk of inadvertently *creating*
         thread-local-storage if none exists.  Replacing this
         with

          >> tsdPtr = (ThreadSpecificData 
*)TclThreadDataKeyGet(&dataKey);

         doesn't, and prevents Tcl_FinalizeThread (called lower
         in Tcl_Finalize) from doing anything, since
Tcl_FinalizeThread
         uses identical code to *check* if
thread-local-storage exists,
         and does nothing if it hasn't.


    2:   When Tcl_Finalize is called on a virgin thread,
           "tsdPtr" will now be zero, which wasn't possible
before.

         This requires one more change -- lower in Tcl_Finalize
           is the code

          >> if (tsdPtr->tclLibraryPath != NULL) {
          >> Tcl_DecrRefCount(tsdPtr->tclLibraryPath);
          >> tsdPtr->tclLibraryPath = NULL;
          >> }

         which dereferences "tsdPtr" without checking it.
         Adding an additional

          >> if (tsdPtr)

         in front of this, protects against the "tsdPtr==0"
case.


  As far as I can tell, that's enough.   ??
  .. and my C++ program
     (linked with the Tcl/Tk Dlls) no longer crashes on exit;

  .. and tclsh83, (also linked with this Dll)
     can be CLOSE'd fine.

                     -- -- -- -- -- -- -- --

  I hesitate to go further .. because I must admit I don't
understand
    all the stuff in Tcl_Finalize ..

     those calls to TclFinalizeCompExecEnv()
                and TclFinalizeSynchronization(),
                just to name two .. are a mystery to me
                and I've grown too tired to track them,

     so I can't tell if there's any other reason that I'm not
     currently understanding -- why Tcl_Finalize should need
     to be called on a tcl thread.

  But I've made the above changes in my own copy, and it
seems better...


 
===================================================================
 
===================================================================

davygrvy added on 2002-01-28 12:25:23:
Logged In: YES 
user_id=7549

I guess so.  The scary part is that the simplicity of 
tclAppInit.c will get destroyed and start taking on windows 
specifics.  It'll be a first to #include <windows.h>.

If it does, a real shell with colors and mouse support 
accessing the console API couldn't be far off...

Sorry for the delay with a reply.

hobbs added on 2002-01-17 01:27:16:
Logged In: YES 
user_id=72656

is this still valid with the latest 8.4 cvs?

davygrvy added on 2001-09-14 11:20:15:
Logged In: YES 
user_id=7549

no time to do this.

davygrvy added on 2001-05-18 06:23:41:

File Added - 6398: noBoom.c

davygrvy added on 2001-05-18 06:22:48:

File Added - 6397: noBoom.msg

Logged In: YES 
user_id=7549

here's another follow-up describing a users difficulty with 
this issue and editted code to show that this method works.

davygrvy added on 2001-04-26 07:42:15:
Logged In: YES 
user_id=7549

Same as https://sourceforge.net/tracker/index.php?
func=detail&aid=219245&group_id=10894&atid=110894

davygrvy added on 2001-03-07 18:00:00:
Logged In: YES 
user_id=7549

This bug only happens with a threaded build of tclsh

Attachments: