On 10/4/06, Stephen Deasey <[EMAIL PROTECTED]> wrote:
On 10/4/06, Zoran Vasiljevic <[EMAIL PROTECTED]> wrote:
>
> On 04.10.2006, at 18:44, Stephen Deasey wrote:
>
> >>
> >> OK. I can accept that. Still, you put this into frequently
> >> called procedure and there you go (literals are freed AFAIK,
> >> when procedure scope is exited): again you have global locking.
> >
> >
> > I'm not sure what you're saying here. What is freed, and when?
> >
>
> The literal object "themutex" is gone after procedure exits
> AFAIK. This MIGHT need to be double-checked though as I'm
> not 100% sure if the literals get garbage collected at that
> point OR at interp teardown.


If that were true then my scheme would be useless. But I don't think
it is. I added a log line to GetArgs in nsd/tclthread.c:

        if (Ns_TclGetOpaqueFromObj(objv[2], type, &addr) != TCL_OK
            && Ns_TclGetAddrFromObj(interp, objv[2], type, &addr) != TCL_OK) {

            Ns_Log(Warning, "tclthread.c:GetArgs: objv[2] not an
address object. Looking up in hash table...");

            Tcl_ResetResult(interp);
            Ns_MasterLock();
            ...


i.e. if the 'name' of the thread primitive given to the command does
not already contain a pointer to the underlying object, and it can not
be converted to one by deserialising a pointer address, then take the
global lock and look the name up in the hash table. Log this case.


    % proc lockunlock args {ns_mutex lock m; ns_mutex unlock m}
    % lockunlock
        [04/Oct/2006:18:39:25][8985.3086293920][-thread-1208673376-] Warning:
        tclthread.c:GetArgs: objv[2] not an address object. Looking up
in hash table...
    % lockunlock
    % lockunlock

The first time the proc is run it is compiled and the name is indeed
looked up in the hash of mutex names. And that is of course 'slow'
because there's a lock around the hash table.

But that is the *only* time this happens. On the second and third
attempt, no locking or look up!

What's interesting from the above is that there is only a single log
line, but there are two literal "m" objects.  Apparently Tcl is doing
some optimising behind the scenes...



Hmm.. what's most interesting about the above is, if Tcl notices two
literal "m" objects in the above code and coalesces them into one,
where does it put them?  If it puts them in a global cache, not a
proc-local one, then we have problems:


   % proc lockunlock args {ns_mutex lock x; ns_mutex unlock x}
   % proc broadcast args {ns_cond broadcast x}
   % broadcast
       [04/Oct/2006:19:15:41][9066.3086289824][-thread-1208677472-] Warning:
       tclthread.c:GetArgs: objv[2] not an address object. Looking up
in hash table...
   % broadcast
   % lockunlock
       [04/Oct/2006:19:15:52][9066.3086289824][-thread-1208677472-] Warning:
       tclthread.c:GetArgs: objv[2] not an address object. Looking up
in hash table...
   % lockunlock
   % broadcast
       [04/Oct/2006:19:15:59][9066.3086289824][-thread-1208677472-] Warning:
       tclthread.c:GetArgs: objv[2] not an address object. Looking up
in hash table...


Er, there's the object shimmering...

So to work efficiently the name you give to the mutex must be unique.
As is the case with naming procs etc. It will still work correctly
with a non-unique name, but it will incur a locking overhead should
your name clash with some other literal, and should that other literal
be used in a way which would cause shimering. Damn.

So maybe we can force unique names by requiring mutexes to be
explicitly created, as mentioned before. i.e.:

   init.tcl:
   ns_mutex create foo_lock

   foo.tcl
   proc foo_do args {
       ns_mutex lock foo_lock
       ...
   }


Or not.  I don't know...

Reply via email to