In a message dated 4/6/2001 12:04:09 AM Eastern Daylight Time,
[EMAIL PROTECTED] writes:


> > I believe, on my 4th attempt, I may have correctly implemented Zoran's
> > patches to the 3.3.1 code to avoid the crash.
> > <snip>
> > Hopefully all is well now.  This stuff has to work now - Tcl 7.6 has been
> > ripped out of 4.0 altogether!
>
> Well, first tests are encouraging. Seems we have a proper behaviour
> now. I'll make little more testing these days but the impression is that
> all should be ok. I've tested the 3.3.2 (nsd_v3_r3_p0 tag) but assume
> that 4.+ should be ok as well.
>
> Thanks for your time and effort, Jim !



Well, actually Zoran, we should all thank you for tracking down the problem!

BTW:  The thread-data block model of the Tcl C API is very different from the
AOLserver and Pthread thread local storage C API's.  I'd encourage anyone
using thread local storage to stick to the pthread/aolserver model if
possible.  It was specifically designed, via the iterative nature of it's
cleanup callbacks, to handle the case of interfaces accidently
re-initializing other interfaces during cleanup.

For example, consider two extension, the Foo and Bar API's, which both use
thread local storage initialized at startup like this:

  Ns_TlsAlloc(&barTls, DeleteBar);
  Ns_TlsAlloc(&fooTls, DeleteFoo);


One could call GetBar to get a private, per-thread Bar thing and GetFoo to
get a private, per-thread Foo thing.  Perhaps GetBar looks like this:

void Bar *
GetBar(void)
{
  Bar *bPtr = Ns_TlsGet(&barTls);
  if (bPtr == NULL) {
    bPtr = NewBar();
    Ns_TlsSet(&barTls, bPtr);
  }
  return bPtr;
}


Now, what if DeleteFoo looks like this:

void
DeleteFoo(void *arg)
{
  Foo *fPtr = arg;
  Bar *bPtr = GetBar();

  ... do something with bPtr ...
  FreeFoo(fPtr);
}


Note that DeleteFoo calls GetBar and you know that DeleteFoo will be called
at thread exit time.  How can you guarantee DeleteFoo will be called before
DeleteBar, especially if you didn't write Bar, you're just using it.  The
answer is you can't which is why the pthread and aolserver model run across
all the cleanup callbacks in order and then, if necessary, call them all
again until everything is clear out.  In otherwords, the order of cleanup
could be:

DeleteFoo
DeleteBar

or it could be:

DeleteBar
DeleteFoo (re-initializes Bar as a side effect)
...
DeleteBar (a second time)


By default the code will give up after a few trys in which case there's
probably a memory leak or something happing.  In practice this never happens.

Note the model of Tcl is different, relying on the exit handlers which could
call some other code which had already been destroyed.  I find the
pthread/aolserver model more useful and all the code in the aolserver core
and the modules we write at AOL are designed around that behavior, i.e., each
interface is safe to initialize/cleanup multiple times if necessary.  Most
pthread's books have a good explaination of this and you can find the code at
work in thread/tls.c.

Hope this clears up any confusion.

-Jim

Reply via email to