From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS31976 209.132.180.0/23 X-Spam-Status: No, score=-3.6 required=3.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_PASS,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.1 Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 2AF941F597 for ; Sat, 21 Jul 2018 02:12:07 +0000 (UTC) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:to:cc:references:from:message-id:date :mime-version:in-reply-to:content-type :content-transfer-encoding; q=dns; s=default; b=TDjoUxMvOzgc0lgX sHV3X6SCM2/PjRmi6m9M56HtJL4Wi5Ieeg2ELECTi/AhyQYVund0qxPwWEZhaFPX HCvI5RGCs6sAGFym228k7KpnYZYcuHaTVfdiXo5Bwb8Ao/Jmk9YcfJ5OLVEAilwx WtYBN3XJp5KSNwAAUANxtLPGvS8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:to:cc:references:from:message-id:date :mime-version:in-reply-to:content-type :content-transfer-encoding; s=default; bh=IppQcXe1Xj8alabSydOusm qNyUQ=; b=ZB030vg8enzsBuU470MO+PQD+Xp+aUuVy1qUdYbKOxtm4Z4twIlcgT /QvABjgnUY9bu1KQq+jtykcfBn6rJnkQvaV5a03cl3nBwcZ026WI5JSSq8p/tBk4 GiFUZR2YtUSMBrbuhxoBUsBwayEMOHZcqPi02DLnRLyw6zh2NVJP0= Received: (qmail 2474 invoked by alias); 21 Jul 2018 02:12:03 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Received: (qmail 2281 invoked by uid 89); 21 Jul 2018 02:12:01 -0000 Authentication-Results: sourceware.org; auth=none X-HELO: mail-qt0-f177.google.com Subject: Re: [PATCH v8 0/8] Add support for ISO C threads.h To: Rical Jasan , Adhemerval Zanella Cc: libc-alpha@sourceware.org, Florian Weimer References: <1517591084-11347-1-git-send-email-adhemerval.zanella@linaro.org> <203a3def-74d0-fa66-9792-a587a089a359@linaro.org> <46c7b370-f98d-30a3-9aac-c5e2c5d5e1d0@linaro.org> <00cbaea3-d979-d766-58b1-a4b0822ca678@redhat.com> <614bd248-b727-d517-6cba-a7968dc888c1@2c3t.io> <2630c1fd-d1b5-7bca-d853-838bbc15ac07@linaro.org> <31423f60-2d82-64c2-ff10-d545b414346d@2c3t.io> From: Carlos O'Donell Openpgp: preference=signencrypt Message-ID: <031e5e99-2bef-7fc2-d87a-fb8386f3f6e8@redhat.com> Date: Fri, 20 Jul 2018 22:11:52 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 In-Reply-To: <31423f60-2d82-64c2-ff10-d545b414346d@2c3t.io> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit On 07/20/2018 08:26 PM, Rical Jasan wrote: > On 07/19/2018 12:58 PM, Adhemerval Zanella wrote: >> If you could send a patch based on my personal branch [1] and can merge >> it. > I've attached the refactored/rewritten version. It isn't a very long > section, so shouldn't take long to review (IANAE, so somebody should). > > Aside from the refactoring to make the Threads chapter generic, I > reviewed the grammar, converted all references to "ISO C11" to "ISO C", > added @standards to everything, made sure all the relevant functions > mentioned their return values, and added cross-references where I felt > they would be useful. I also reviewed the output in PDF, Info, and HTML > form. > > I didn't mean to take so long, but I had to build make due a minimum > version requirement before I could review the output, and it took a lot > longer than building a single package like that usually does... > > I didn't bother with the ChangeLog since I wasn't sure how you wanted to > handle that, and it changes all the time anyway. Great work here! Thank you for this help Rical! OK for 2.28 with the follwing changes: - Two spelling fixes. - Consider suggestion for removing "unequivocally" - Use "owning thread" - Consider suggestion to expand thread type |'ing. - Tighten up TLS language. - You "use" a keyword. - Broaden explanation of TSS_DTOR_ITERATIONS Reviewed-by: Carlos O'Donell > commit 52d5f975656c61903d6a2fbb47a9ea460dd8db28 > Author: Rical Jasan > Date: Fri Jul 20 17:04:02 2018 -0700 > > manual: Add documentation for ISO C Threads. > > The POSIX Threads chapter is renamed to Threads, making POSIX Threads > a section, and a new section is added on the topic of ISO C Threads. > > * manual/debug.texi: Update adjacent chapter name. > * manual/probes.texi: Likewise. > * manual/threads.texi (ISO C Threads): New section. > (POSIX Threads): Convert to a section. > > diff --git a/manual/debug.texi b/manual/debug.texi > index f4157e525e..712a42f75c 100644 > --- a/manual/debug.texi > +++ b/manual/debug.texi > @@ -1,5 +1,5 @@ > @node Debugging Support > -@c @node Debugging Support, POSIX Threads, Cryptographic Functions, Top > +@c @node Debugging Support, Threads, Cryptographic Functions, Top OK. > @c %MENU% Functions to help debugging applications > @chapter Debugging support > > diff --git a/manual/probes.texi b/manual/probes.texi > index fa6e38f785..ab2a3102bb 100644 > --- a/manual/probes.texi > +++ b/manual/probes.texi > @@ -1,5 +1,5 @@ > @node Internal Probes > -@c @node Internal Probes, Tunables, POSIX Threads, Top > +@c @node Internal Probes, Tunables, Threads, Top OK. > @c %MENU% Probes to monitor libc internal behavior > @chapter Internal probes > > diff --git a/manual/threads.texi b/manual/threads.texi > index 769d974d50..01217e1c85 100644 > --- a/manual/threads.texi > +++ b/manual/threads.texi > @@ -1,10 +1,538 @@ > +@node Threads > +@c @node Threads, Internal Probes, Debugging Support, Top > +@c %MENU% Functions, constants, and data types for working with threads OK. > +@chapter Threads > +@cindex threads > + > +This chapter describes functions used for managing threads. > +@Theglibc{} provides two threading implementations: ISO C threads and > +POSIX threads. OK. > + > +@menu > +* ISO C Threads:: Threads based on the ISO C specification. > +* POSIX Threads:: Threads based on the POSIX specification. OK. Yay! > +@end menu > + > + > +@node ISO C Threads > +@section ISO C Threads > +@cindex ISO C threads > +@cindex C threads > +@pindex threads.h > + > +This section describes the @glibcadj{} ISO C threads implementation. > +To have a deeper understanding of this API, it is strongly recomended s/recomended/recommended/g > +to read ISO/IEC 9899:2011, section 7.26, in which ISO C threads were > +originally specified. All types and function prototypes are declared > +in the header file @file{threads.h}. > + > +@menu > +* ISO C Threads Return Values:: Symbolic constants that represent a > + function's return value. > +* ISO C Thread Management:: Support for basic threading. > +* Call Once:: Single-call functions and macros. > +* ISO C Mutexes:: A low-level mechanism for mutual exclusion. > +* ISO C Condition Variables:: High-level objects for thread synchronization. > +* ISO C Thread-local Storage:: Functions to support thread-local storage. > +@end menu OK. > + > + > +@node ISO C Threads Return Values > +@subsection Return Values > + > +The ISO C thread specification provides the following enumeration > +constants for return values from functions in the API: > + > +@vtable @code > +@item thrd_timedout > +@standards{C11, threads.h} > +A specified time was reached without acquiring the requested resource, > +usually a mutex or condition variable. > + > +@item thrd_success > +@standards{C11, threads.h} > +The requested operation succeeded. > + > +@item thrd_busy > +@standards{C11, threads.h} > +The requested operation failed because a requested resource is already > +in use. > + > +@item thrd_error > +@standards{C11, threads.h} > +The requested operation failed. > + > +@item thrd_nomem > +@standards{C11, threads.h} > +The requested operation failed because it was unable to allocate > +enough memory. > +@end vtable OK. > + > + > +@node ISO C Thread Management > +@subsection Creation and Control > +@cindex thread creation > +@cindex thread control > +@cindex thread management > + > +@Theglibc{} implements a set of functions that allow the user to easily > +create and use threads. Additional functionality is provided to control > +the behavior of threads. > + > +The following data types are defined for managing threads: > + > +@deftp {Data Type} thrd_t > +@standards{C11, threads.h} > +A unique object that identifies a thread unequivocally. Suggest: A unique object that identifies one thread. Do more with less. > +@end deftp > + > +@deftp {Data Type} thrd_start_t > +@standards{C11, threads.h} > +This data type is an @code{int (*) (void *)} typedef that is passed to > +@code{thrd_create} when creating a new thread. It should point to the > +first function that thread will run. > +@end deftp > + > +The following functions are used for working with threads: > + > +@deftypefun int thrd_create (thrd_t *@var{thr}, thrd_start_t @var{func}, void *@var{arg}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_create} creates a new thread that will execute the function > +@var{func}. The object pointed to by @var{arg} will be used as the > +argument to @var{func}. If successful, @var{thr} is set to the new > +thread identifier. OK. > + > +This function may return @code{thrd_success}, @code{thrd_nomem}, or > +@code{thrd_error}. OK. > +@end deftypefun > + > +@deftypefun thrd_t thrd_current (void) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +This function returns the identifier of the calling thread. > +@end deftypefun > + > +@deftypefun int thrd_equal (thrd_t @var{lhs}, thrd_t @var{rhs}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_equal} checks whether @var{lhs} and @var{rhs} refer to the > +same thread. If @var{lhs} and @var{rhs} are different threads, this > +function returns @math{0}; otherwise, the return value is non-zero. > +@end deftypefun OK. > + > +@deftypefun int thrd_sleep (const struct timespec *@var{time_point}, struct timespec *@var{remaining}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_sleep} blocks the execution of the current thread for at > +least until the elapsed time pointed to by @var{time_point} has been > +reached. This function does not take an absolute time, but a duration > +that the thread is required to be blocked. @xref{Time Basics}, and > +@ref{Elapsed Time}. > + OK. > +The thread may wake early if a signal that is not ignored is received. > +In such a case, if @code{remaining} is not NULL, the remaining time > +duration is stored in the object pointed to by > +@var{remaining}. OK. > + > +@code{thrd_sleep} returns @math{0} if it blocked for at least the > +amount of time in @code{time_point}, @math{-1} if it was interrupted > +by a signal, or a negative number on failure. > +@end deftypefun OK. > + > +@deftypefun void thrd_yield (void) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_yield} provides a hint to the implementation to reschedule > +the execution of the current thread, allowing other threads to run. > +@end deftypefun OK. > + > +@deftypefun {_Noreturn void} thrd_exit (int @var{res}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_exit} terminates execution of the calling thread and sets > +its result code to @var{res}. > + > +If this function is called from a single-threaded process, the call is > +equivalent to calling @code{exit} with @code{EXIT_SUCCESS} > +(@pxref{Normal Termination}). Also note that returning from a > +function that started a thread is equivalent to calling > +@code{thrd_exit}. This is the text you worried about. On the one hand the standard says "last thread," but what does that mean? It implies a total ordering of exiting threads, when that might not be true, but both texts appear to assume it. Therefore it's fine for a first kick at the can to describe what is happening. In essence you had a multi-threaded program, and the threads start exiting, and eventually you are left with just one thread whose thrd_exit is equivalent to exit. It's a fine cognitive model, but assumes the implementation imposes that total exit ordering in order for there to be a "last" thread, rather than all threads exiting simultaneously and all of them being the "last" thread. This looks good to me. > +@end deftypefun > + > +@deftypefun int thrd_detach (thrd_t @var{thr}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_detach} detaches the thread identified by @code{thr} from > +the current control thread. The resources held by the detached thread > +will be freed automatically once the thread exits. The parent thread > +will never be notified by any @var{thr} signal. > + > +Calling @code{thrd_detach} on a thread that was previously detached or > +joined by another thread results in undefined behavior. > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun int thrd_join (thrd_t @var{thr}, int *@var{res}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{thrd_join} blocks the current thread until the thread identified > +by @code{thr} finishes execution. If @code{res} is not NULL, the > +result code of the thread is put into the location pointed to by > +@var{res}. The termination of the thread @dfn{synchronizes-with} the > +completion of this function, meaning both threads have arrived at a > +common point in their execution. > + > +Calling @code{thrd_join} on a thread that was previously detached or > +joined by another thread results in undefined behavior. > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > + > +@node Call Once > +@subsection Call Once > +@cindex call once > +@cindex single-call functions > + > +In order to guarantee single access to a function, @theglibc{} > +implements a @dfn{call once function} to ensure a function is only > +called once in the presence of multiple, potentially calling threads. > + > +@deftp {Data Type} once_flag > +@standards{C11, threads.h} > +A complete object type capable of holding a flag used by @code{call_once}. > +@end deftp > + > +@defvr Macro ONCE_FLAG_INIT > +@standards{C11, threads.h} > +This value is used to initialize an object of type @code{once_flag}. > +@end defvr > + > +@deftypefun void call_once (once_flag *@var{flag}, void (*@var{func}) (void)) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{call_once} calls function @var{func} exactly once, even if > +invoked from several threads. The completion of the function > +@var{func} synchronizes-with all previous or subsequent calls to > +@code{call_once} with the same @code{flag} variable. > +@end deftypefun OK. > + > + > +@node ISO C Mutexes > +@subsection Mutexes > +@cindex mutex > +@cindex mutual exclusion > + > +To have better control of resources and how threads access them, > +@theglibc{} implements a @dfn{mutex} object, which can help avoid race > +conditions and other concurrency issues. The term ``mutex'' refers to OK. > +mutual exclusion. > + OK. > +The fundamental data type for a mutex is the @code{mtx_t}: > + > +@deftp {Data Type} mtx_t > +@standards{C11, threads.h} > +The @code{mtx_t} data type uniquely identifies a mutex object. > +@end deftp > + > +The ISO C standard defines several types of mutexes. They are > +represented by the following symbolic constants: > + > +@vtable @code > +@item mtx_plain > +@standards{C11, threads.h} > +A mutex that does not support timeout, or test and return. > + > +@item mtx_recursive > +@standards{C11, threads.h} > +A mutex that supports recursive locking, which means that the owner > +thread can lock it more than once without causing deadlock. Traditional technical language is "owning thread" s/owner thread/owning thread/g > + > +@item mtx_timed > +@standards{C11, threads.h} > +A mutex that supports timeout. > +@end vtable > + > +The following functions are used for working with mutexes: > + > +@deftypefun int mtx_init (mtx_t *@var{mutex}, int @var{type}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{mtx_init} creates a new mutex object with type @var{type}. The > +object pointed to by @var{mutex} is set to the identifier of the newly > +created mutex. > + > +The @code{type} argument may be either @code{mtx_plain} or > +@code{mtx_timed}, optionally combined with @code{mtx_recursive}. This should be expanded to ensure clarity. Suggest: ~~~ The @code{type} argument may be either @code{mtx_plain}, @code{mtx_timed}, @code{mtx_plain | mtx_recursive}, or @code{mtx_timed | mtx_recursive}. ~~~ > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun int mtx_lock (mtx_t *@var{mutex}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} > +@code{mtx_lock} blocks the current thread until the mutex pointed to > +by @var{mutex} is locked. The behavior is undefined if the current > +thread has already locked the mutex and the mutex is not recursive. > + > +Prior calls to @code{mtx_unlock} on the same mutex synchronize-with > +this operation (if this operation succeeds), and all lock/unlock > +operations on any given mutex form a single total order (similar to > +the modification order of an atomic). > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun int mtx_timedlock (mtx_t *restrict @var{mutex}, const struct timespec *restrict @var{time_point}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} > +@code{mtx_timedlock} blocks the current thread until the mutex pointed > +to by @var{mutex} is locked or until the calendar time pointed to by > +@var{time_point} has been reached. Since this function takes an > +absolute time, if a duration is required, the calendar time must be > +calculated manually. @xref{Time Basics}, and @ref{Calendar Time}. OK. > + > +If the current thread has already locked the mutex and the mutex is > +not recursive, or if the mutex does not support timeout, the behavior > +of this function is undefined. > + > +Prior calls to @code{mtx_unlock} on the same mutex synchronize-with > +this operation (if this operation succeeds), and all lock/unlock > +operations on any given mutex form a single total order (similar to > +the modification order of an atomic). > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun OK. > + > +@deftypefun int mtx_trylock (mtx_t *@var{mutex}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} > +@code{mtx_trylock} tries to lock the mutex pointed to by @var{mutex} > +without blocking. It returns immediately if the mutex is already > +locked. > + > +Prior calls to @code{mtx_unlock} on the same mutex synchronize-with > +this operation (if this operation succeeds), and all lock/unlock > +operations on any given mutex form a single total order (similar to > +the modification order of an atomic). > + > +This function returns @code{thrd_success} if the lock was obtained, > +@code{thrd_busy} if the mutex is already locked, and @code{thrd_error} > +on failure. > +@end deftypefun > + > +@deftypefun int mtx_unlock (mtx_t *@var{mutex}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{mtx_unlock} unlocks the mutex pointed to by @var{mutex}. The > +behavior is undefined if the mutex is not locked by the calling > +thread. OK. What about unlocking a lock you already unlocked? > + > +This function synchronizes-with subsequent @code{mtx_lock}, > +@code{mtx_trylock}, and @code{mtx_timedlock} calls on the same mutex. > +All lock/unlock operations on any given mutex form a single total > +order (similar to the modification order of an atomic). > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun void mtx_destroy (mtx_t *@var{mutex}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{mtx_destroy} destroys the mutex pointed to by @var{mutex}. If > +there are any threads waiting on the mutex, the behavior is > +undefined. OK. > +@end deftypefun > + > + > +@node ISO C Condition Variables > +@subsection Condition Variables > +@cindex condvar > +@cindex condition variables > + > +Mutexes are not the only synchronization mechanisms available. For > +some more complex tasks, @theglibc{} also implements @dfn{condition > +variables}, which allow the programmer to think at a higher level when > +solving complex synchronization problems. They are used to > +synchronize threads waiting on a certain condition to happen. OK. > + > +The fundamental data type for condition variables is the @code{cnd_t}: > + > +@deftp {Data Type} cnd_t > +@standards{C11, threads.h} > +The @code{cnd_t} uniquely identifies a condition variable object. > +@end deftp > + > +The following functions are used for working with condition variables: > + > +@deftypefun int cnd_init (cnd_t *@var{cond}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{cnd_init} initializes a new condition variable, identified by > +@var{cond}. > + > +This function may return @code{thrd_success}, @code{thrd_nomem}, or > +@code{thrd_error}. > +@end deftypefun > + > +@deftypefun int cnd_signal (cnd_t *@var{cond}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{cnd_signal} unblocks one thread that is currently waiting on the > +condition variable pointed to by @var{cond}. If a thread is > +successfully unblocked, this function returns @code{thrd_success}. If > +no threads are blocked, this function does nothing and returns > +@code{thrd_success}. Otherwise, this function returns > +@code{thrd_error}. > +@end deftypefun OK. > + > +@deftypefun int cnd_broadcast (cnd_t *@var{cond}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{cnd_broadcast} unblocks all the threads that are currently > +waiting on the condition variable pointed to by @var{cond}. This > +function returns @code{thrd_success} on success. If no threads are > +blocked, this function does nothing and returns > +@code{thrd_success}. Otherwise, this function returns > +@code{thrd_error}. > +@end deftypefun OK. > + > +@deftypefun int cnd_wait (cnd_t *@var{cond}, mtx_t *@var{mutex}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} > +@code{cnd_wait} atomically unlocks the mutex pointed to by @var{mutex} > +and blocks on the condition variable pointed to by @var{cond} until > +the thread is signalled by @code{cnd_signal} or @code{cnd_broadcast}. s/signalled/signaled/g > +The mutex is locked again before the function returns. > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun int cnd_timedwait (cnd_t *restrict @var{cond}, mtx_t *restrict @var{mutex}, const struct timespec *restrict @var{time_point}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} > +@code{cnd_timedwait} atomically unlocks the mutex pointed to by > +@var{mutex} and blocks on the condition variable pointed to by > +@var{cond} until the thread is signalled by @code{cnd_signal} or s/signalled/signaled/g > +@code{cnd_broadcast}, or until the calendar time pointed to by > +@var{time_point} has been reached. The mutex is locked again before > +the function returns. > + > +As for @code{mtx_timedlock}, since this function takes an absolute > +time, if a duration is required, the calendar time must be calculated > +manually. @xref{Time Basics}, and @ref{Calendar Time}. > + OK. > +This function may return @code{thrd_success}, @code{thrd_nomem}, or > +@code{thrd_error}. > +@end deftypefun > + > +@deftypefun void cnd_destroy (cnd_t *@var{cond}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{cnd_destroy} destroys the condition variable pointed to by > +@var{cond}. If there are threads waiting on @var{cond}, the behavior > +is undefined. > +@end deftypefun OK. > + > + > +@node ISO C Thread-local Storage > +@subsection Thread-local Storage > +@cindex thread-local storage > + > +@Theglibc{} implements functions to provide @dfn{thread-local > +storage}, which means each thread can have their own variables that > +are not visible by other threads. I would tighten this up a bit like this, since it's less about visibility and more about storage: ~~~ @Theglibc{} implements functions to provide @dfn{thread-local storage}. Variables can be defined to have unique storage per-thread, lifetimes that match the thread lifetime, and destructors that cleanup the unique per-thread storage. ~~~ > + > +Several data types and macros exist for working with thread-local > +storage: > + > +@deftp {Data Type} tss_t > +@standards{C11, threads.h} > +The @code{tss_t} data type identifies a thread-specific storage > +object. Even if shared, every thread will have its own instance of > +the variable, with different values. > +@end deftp OK. > + > +@deftp {Data Type} tss_dtor_t > +@standards{C11, threads.h} > +The @code{tss_dtor_t} is a function pointer of type @code{void (*) > +(void *)}, to be used as a thread-specific storage destructor. The > +function will be called when the current thread calls @code{thrd_exit} > +(but never when calling @code{tss_delete} or @code{exit}). > +@end deftp OK. > + > +@defvr Macro thread_local > +@standards{C11, threads.h} > +@code{thread_local} is used to mark a variable with thread storage > +duration, which means it is created when the thread starts and cleaned > +up when the thread ends. OK. > + > +@emph{Note:} For C++, C++11 or later is required to get the s/get/use/g You "use" a keyword. > +@code{thread_local} keyword. > +@end defvr > + > +@defvr Macro TSS_DTOR_ITERATIONS > +@standards{C11, threads.h} > +@code{TSS_DTOR_ITERATIONS} is an integer constant expression > +representing the maximum number of times that destructors will be > +called when a thread terminates. Suggest a broader explanation: @code{TSS_DTOR_ITERATIONS} is an integer constant expression representing the maximum number of iterations over all thread-local destructors at the time of thread termination. This value provides a bounded limit to the destruction of thread-local storage e.g. consider a destructor that creates more thread-local storage. > +@end defvr > + > +The following functions are used to manage thread-local storage: > + > +@deftypefun int tss_create (tss_t *@var{tss_key}, tss_dtor_t @var{destructor}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{tss_create} creates a new thread-specific storage key and stores > +it in the object pointed to by @var{tss_key}. Although the same key > +value may be used by different threads, the values bound to the key by > +@code{tss_set} are maintained on a per-thread basis and persist for > +the life of the calling thread. > + > +If @code{destructor} is not NULL, a destructor function will be set, > +and called when the thread finishes its execution by calling > +@code{thrd_exit}. > + > +This function returns @code{thrd_success} if @code{tss_key} is > +successfully set to a unique value for the thread; otherwise, > +@code{thrd_error} is returned and the value of @code{tss_key} is > +undefined. > +@end deftypefun OK. > + > +@deftypefun int tss_set (tss_t @var{tss_key}, void *@var{val}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{tss_set} sets the value of the thread-specific storage > +identified by @var{tss_key} for the current thread to @var{val}. > +Different threads may set different values to the same key. OK. > + > +This function returns either @code{thrd_success} or @code{thrd_error}. > +@end deftypefun > + > +@deftypefun {void *} tss_get (tss_t @var{tss_key}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{tss_get} returns the value identified by @var{tss_key} held in > +thread-specific storage for the current thread. Different threads may > +get different values identified by the same key. On failure, > +@code{tss_get} returns zero. > +@end deftypefun OK. > + > +@deftypefun void tss_delete (tss_t @var{tss_key}) > +@standards{C11, threads.h} > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} > +@code{tss_delete} destroys the thread-specific storage identified by > +@var{tss_key}. > +@end deftypefun OK. > + > + > @node POSIX Threads > -@c @node POSIX Threads, Internal Probes, Cryptographic Functions, Top > -@chapter POSIX Threads > -@c %MENU% POSIX Threads > +@section POSIX Threads OK. > @cindex pthreads > > -This chapter describes the @glibcadj{} POSIX Threads implementation. > +This section describes the @glibcadj{} POSIX Threads implementation. > > @menu > * Thread-specific Data:: Support for creating and > @@ -14,7 +542,7 @@ This chapter describes the @glibcadj{} POSIX Threads implementation. > @end menu > > @node Thread-specific Data > -@section Thread-specific Data > +@subsection Thread-specific Data > > The @glibcadj{} implements functions to allow users to create and manage > data specific to a thread. Such data may be destroyed at thread exit, > @@ -71,7 +599,7 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. > > > @node Non-POSIX Extensions > -@section Non-POSIX Extensions > +@subsection Non-POSIX Extensions > > In addition to implementing the POSIX API for threads, @theglibc{} provides > additional functions and interfaces to provide functionality not specified in > @@ -83,7 +611,7 @@ the standard. > @end menu > > @node Default Thread Attributes > -@subsection Setting Process-wide defaults for thread attributes > +@subsubsection Setting Process-wide defaults for thread attributes > OK. > @Theglibc{} provides non-standard API functions to set and get the default > attributes used in the creation of threads in a process. -- Cheers, Carlos.