Dave Butenhof wrote:
[...]
> clearing/ignoring the existing values might "contribute
> to" an application memory leak -- but if the application
> fails to clean up abandoned TSD values it's got a memory
> leak ANYWAY
Not at all. Clean up "abandoned" TSD data can be done without
clearing the existing values in the TSD slots. You just need
"delete static_cast<type *>(tsd_get(key))". Clearing of value
in the TSD slot is only needed if you have defined a key with
a destructor... but you're not sure that thead won't terminate
resulting in another clean up as part of thread termination.
IOW, you'd "probably" define a key without destructor if you
can and want to take care of data clean up (if any is needed)
on your own.
In the case of keys without destructors, an application either
doesn't need any data clean up (see DCSI-TLS) or it has some
means to perform the clean up of "abandoned" keys (might even
have some means to "intercept" thread termination and perform
data cleanup without using TSD dtor... heck, Win32 zealots do
it all the time ;-) ). In this case, the current wording even
kinda encourages application programmers to NOT bother with
clearing the slots, I'd say.
In my example (I mean stuff not working under current True64),
I have defined a key without destructor and THAT program would
continue to be conforming even under the "proposed action" to
impose an extra UB. The situation would be different if I'd
wrote a similar program that would defined a key with "a dummy"
destructor. There would be NO "leaks" but such appl would cease
to be conforming. I really doubt that you can find some similar
appls(s) that would become broken under the "proposed action"
(a change in the normative section for _key_delete()), though.
[...]
> Look, if we're going to asynchronously clear TSD values (or
> "behave as if"), what's the point in restricting it to keys
> with no destructor?
Versioning is a bad thing. I don't like it. I'd prefer to pay
the price only when implementation chooses to reuse a key with
no destructor (zapping slots eagerly in pthread_key_delete()
aside for a moment). There shouldn't be that many such keys...
nor should we need to traverse many zillions of threads in a
"typical application". That's the entire point. "Economy". ;-)
> Any cost of versioning or traversal will be the same.
I don't think so.
> Furthermore, it means remembering the previous definition
> of the key (because the definition depends on whether THAT
> definition had a destructor); something that's otherwise
> not necessary.
Yeah, apart of doing the zapping (traversing and clearing)
eagerly -- you probably won't need to remember the definition,
then. OTOH, with NPTL-like versioning, you really need to
maintain version number, stop counting on its MAX... and slow
down "a bit" all get and set operations. Not good. (NPTL folks
might want to fix finally all {reported} msync bugs in "0.57+"
first, however ;-) ;-) )
regards,
alexander.
To: Alexander yyyyyyyyyyyyyyyyyyyy@xxxxx
cc: yyyyyyyyyyyyyy@xxxxxxxxxxxxx
Subject: Re: Rejected XSH ERN 101
Alexander Terekhov wrote:
>Dave Butenhof wrote:
>[...]
>
>
>>Perhaps you intended to suggest that the existing requirement on
>>pthread_key_create() of presenting NULL values to the subsequent
>>pthread_getspecific() in all threads be restricted only to keys
>>that at last incarnation (before pthread_key_delete) defined keys
>>with no destructor?
>>
>>
>Sort of. The intent is to 'force' applications to clear all slots
>for a key with a destructor (non-NULL dtor ptr) -- not doing so
>would trigger UB at pthread_key_delete() invocation... optional
>EBUSY checking aside for a moment.
>
My point was more that making it "undefined" doesn't actually help
anyone...
>>You didn't say anything remotely suggesting that.
>>
>>
>Yeah, apart from the text in the Action. ;-)
>
> "For a thread-specific data key with a NULL destructor
> pointer, the thread-specific data values associated with
> key need not be NULL at the time pthread_key_delete() is
> called; otherwise (for a thread-specific data key with a
> non-NULL destructor pointer), application must ensure that
> the thread-specific data values are NULL in all threads
> prior to key destruction."
>
Yes, but that's not what you claim you want to do. You're making
behavior undefined if the application fails to do something it probably
cannot in general accomplish, but you're NOT changing the text that
currently unconditionally requires that the value of a newly created key
(whether "fresh" or "recycled") shall be NULL in all threads. That's an
IMPLEMENTATION requirement, regardless of what the application does,
must do, or can do.
One can certainly INFER your desired change from your actual change, but
it's not stated and therefore would not be a formal requirement of the
standard.
For example, let's say we have an implementation that doesn't detect a
"dangling value" on deletion of a TSD key. One facility in the process
deletes a TSD key, leaving a non-NULL value somewhere. The "application"
is broken. Undefined behavior is invoked. In some vague sense, it's now
"OK" that a TSD key created later, reusing this key value, gives a
non-NULL value in one or more threads. The "application" has broken its
contract with the implementation. OK, fine. But that's a technicality. I
wasn't trying to say this doesn't accomplish anything; but what it
accomplishes is academic standardese of essentially no practical value
to most real-world applications.
If the EBUSY were a "shall fail", fine; this broken application facility
would be unable to delete the key, and it therefore couldn't be reused.
No problem. Except to accomplish that you need at least a count of
threads with non-NULL values, which must be synchronized... and you
might as well version the values and avoid the annoying error. Sure,
clearing/ignoring the existing values might "contribute to" an
application memory leak -- but if the application fails to clean up
abandoned TSD values it's got a memory leak ANYWAY, of the same
magnitude, whether the key is deleted or not. You've added aggravation
and complication that's of no value to anyone. And in any case, the
EBUSY is NOT going to be a "shall fail" so this line of reasoning is
irrelevant.
>[...]
>
>
>>I see no point in this.
>>
>>
>
>Well, the point is that while I agree with you that
>
>http://www.opengroup.org/austin/mailarchives/austin-group-l/msg04508.html
>(see "asynchronously zap the old value from all running threads")
>
> "if I were to encounter an actual need to guarantee a "fresh
> value" for existing threads after the re-creation of a key,
> I would prefer this obnoxious mess, that costs "a lot" only
> when a key is actually reused, (which should occur rarely),
> over something like a versioning protocol that adds a
> smaller cost to every pthread_getspecific and
> pthread_setspecific call even if no key is ever reused."
>
>I would prefer to AVOID "this obnoxious mess" for keys WITH
>destructors (non-NULL dtor ptrs). In the past, I was on your
>side completely -- I though that applications should always
>clear the slots prior to pthread_key_delete() invocation or
>simply shall NOT delete a key if they don't want to have a
>protocol that would ensure both tracking of key sharing and
>cleanup of TSD data by each 'suspect thread' when it decides
>that it 'won't use that key anymore':
>
>http://google.com/groups?selm=3C76897D.426BC98E%40web.de
>(Subject: Re: TSD key reusing issue)
>
>Later, I've run into 'example' that showed to me that Ulrich
>and Kaz were {partially} right and that, at least, for keys
>with NO destructors (NULL dtors), the "requirement on
>pthread_key_create() of presenting NULL values to the
>subsequent pthread_getspecific() in all threads" (even if
>key is reused and its slots were NOT cleared at the last
>incarnation) does make sense. That example is nothing but
>DCSI-TLS (in the scope of another "dynamic" shared object).
>
Look, if we're going to asynchronously clear TSD values (or "behave as
if"), what's the point in restricting it to keys with no destructor? Any
cost of versioning or traversal will be the same. Furthermore, it means
remembering the previous definition of the key (because the definition
depends on whether THAT definition had a destructor); something that's
otherwise not necessary.
>[...]
>
>
>>>Also, can someone point out an existing application that
>>>would be broken by what is being requested? Not a strong
>>>argument, I know, but I'm just curious.
>>>
>>>
>Imposing UB (EBUSY aside for a moment) might be a problem.
>
>>You'd have to depend on seeing particular stale values from
>>
>>
> ^ ^^^^^^^^^^
> | "non-NULL"
>NOT ---------------------+
>
Any non-NULL value is by definition "stale", because it persists from
the previous definition of the key.
>>a previous incarnation of a TSD key in an existing thread.
>>
>>
>http://google.com/groups?selm=3C7666D8.542EE194%40web.de
>
>quoted...
>
>I wrote a THIRD[1] program that did it, I believe.
>
>And, yes, I would have NO problems with a requirement to
>"manually" set TSD values to NULL in ALL threads prior to
>key destruction... BUT please spell this out *clearly*
>in the STANDARD[2] then!
>
The point of TSD is that any library can use it to maintain per-thread
values in any arbitrary thread that enters the code. Requiring that code
to track and manage all those threads would defeat the basic intent. You
could, practically speaking, delete a TSD key only if you could
guarantee that only threads you created (and could control) would ever
have instantiated values for that key.
Yes, we could say that, and there was a time that I would have agreed.
But I've changed my mind. That would substantially reduce the usefulness
and generality of an established standard function that currently has no
such formal restrictions. Instead, I've decided we ought to mean what
the standard says, and make this easy for the application.
>regards,
>alexander.
>
>[1] I think that it is FULLY conforming,
> please correct me if I am wrong:
>
Yes, it looks fine. And, as you point out, it currently fails on Tru64.
That's because I was holding to the original working group intent that
TSD impose no synchronization overhead, despite the accidental wording
of the standard requiring otherwise. As we've already established, I've
changed my mind, and "fixed" my code. (Although the fix hasn't yet
propagated to the support pools; and if our "reaffirmation" of the
existing text doesn't stand through discussion or balloting I could in
theory decide to back it out.)
--
/--------------------[ yyyyyyyyyyyyyy@xxxxxx ]--------------------\
| Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
|