diff mbox

[4/5,v2] Add manual documentation for threads.h

Message ID 1439299988-30771-2-git-send-email-j.m.torrespalma@gmail.com
State New
Headers show

Commit Message

Juan Manuel Torres Palma Aug. 11, 2015, 1:33 p.m. UTC
From: Juan Manuel Torres Palma <jmtorrespalma@gmail.com>

This patch updates the manual and adds a new chapter to the manual,
explaining types macros, constants and functions defined by ISO C11
threads.h standard.

2015-08-11  Juan Manuel Torres Palma  <jmtorrespalma@gmail.com>

	* manual/Makefile (chapters): Add isothreads.texi.
	* manual/isothreads.texi: New file. Add new chapter for ISO C11
	threads documentation.

---
 manual/Makefile        |   3 +-
 manual/isothreads.texi | 326 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 328 insertions(+), 1 deletion(-)
 create mode 100644 manual/isothreads.texi

Comments

Zack Weinberg Aug. 11, 2015, 6:06 p.m. UTC | #1
On 08/11/2015 09:33 AM, Juan Manuel Torres Palma wrote:
> This patch updates the manual and adds a new chapter to the manual,
> explaining types macros, constants and functions defined by ISO C11
> threads.h standard.

This has some substantive issues and some organizational problems.
Let me first outline a better organization, and then I'll run through
the whole thing pointing out the substantive issues as they pop up.

It's very important to minimize forward references in documentation.
That is, if someone starts reading at the beginning of a chapter, by
the time they get to 'foo' they should already have encountered all
the new concepts from that chapter that are necessary to understand
'foo'.  In this case, what that mostly means is the result codes need
to come first.  I also strongly recommend separating 'call_once' and
its associated constants and types to its own section -- right now
it's smeared over the mutex section and the thread-local storage
section, which is just weird.  So it should be something like this:

ISO C11 Threading
  Threading Result codes (current "C11 error types")
    thrd_success
    thrd_error
    thrd_timedout
    thrd_busy
    thrd_nomem

  Thread Creation and Control (current "Thread")
    thrd_t
    thrd_start_t
    thrd_current
    thrd_equal
    thrd_create
    thrd_exit
    thrd_join
    thrd_detach
    thrd_sleep
    thrd_yield

  Call Once (new)
    once_flag
    ONCE_FLAG_INIT
    call_once
    [an example]

  Thread-Local Storage
    thread_local
    tss_t
    tss_dtor_t
    TSS_DTOR_ITERATIONS
    tss_create
    tss_delete
    tss_get
    tss_set

  Mutexes
    mtx_t
    mtx_init
      mtx_plain  (* move the explanation of these constants inside
      mtx_timed     the @deftypefun for mtx_init *)
      mtx_recursive
    mtx_lock
    mtx_timedlock
    mtx_trylock
    mtx_unlock

  Condition Variables
    cnd_t
    cnd_init
    cnd_destroy
    cnd_wait
    cnd_timedwait
    cnd_signal
    cnd_broadcast

General editorial comments:

We do not appear to have any documentation of C11 atomics right now,
and that means you need to avoid *talking* about C11 atomics or
anything that you need to know C11 atomic terminology to understand.
All the "synchronizes-with" stuff -- just delete it.  (I would be
making a different recommendation if I were asking you to write a full
guide to threads, but since we don't even have complete reference
documentation on POSIX threads right now, that seems like too much
extra work to put on you.)

Make sure everything appears in the appropriate index.

Widespread substantive issues:

You need to explain what the return value means for *every single
function* even if you think it's obvious.  (Having moved the
result codes up front, "This function returns a threading result code"
will often, but not always, be sufficient -- e.g. that would not be
enough for mtx_trylock and mtx_timedlock.)

The @safety{} annotations appear to be wrong across the board.  Most
of these functions probably are indeed multithread-safe (or they'd be
useless!), but they probably *aren't* either async-signal or
async-cancel safe.  Please recheck every single one.

I'm cross-checking your work with C11 (N1570) and there are a bunch of
places where the standard doesn't specify the behavior as precisely as
I would like, which is really quite unfortunate; we should think about
the extent to which we want to pin down unspecified cases.

@deftp clauses for cnd_t, mtx_t, tss_t, tss_dtor_t, and once_flag are
missing.

Specific substantive issues:

> +@deftp {Data Type} {thrd_t}
> +Unique number that identifies a thread
> +unequivocally.
> +@end deftp

This should be described as an "opaque object", not a "number".

> +@deftp {Data Type} {thrd_start_t}
> +It is a function pointer that is passed to @code{thrd_create} when
> +creating a new thread. Should point to the first function that thread
> +will run.
> +@end deftp

This, you need to specify the exact definition of, (int (*)(void *)),
so people know how to write their thread-start procedures.

> +@deftypefun int thrd_equal (thrd_t @var{lhs}, thrd_t @var{rhs})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Checks whether @var{lhs} and @var{rhs} refer to the same thread.
> +@end deftypefun

This makes a nice example of how specific you need to be, everywhere,
about the return value:

"Returns a nonzero value if @var{lhs} and @var{rhs} refer to the same
thread, or zero if they don't."

> +@deftypefun int thrd_sleep (const struct timespec* @var{time_point},
struct timespec* @var{remaining})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Blocks the execution of the current thread for at least until
> +the TIME_UTC based time point pointed to by @var{time_point} has been
> +reached.

C11 says this function takes a *duration*, not an absolute time
point.  What did you actually implement?  Need to explicitly point out
that this is not the same as mtx_timedlock or cnd_timedwait.

TIME_UTC is not documented, say "wall-clock time" instead.

> +@deftypefun _Noreturn void thrd_exit (int @var{res})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Terminates execution of the calling thread and sets its result code
> +to @var{res}.
> +@end deftypefun

This needs to mention that returning from a thread-start procedure is
equivalent to calling thrd_exit, and that thrd_exit calls exit(0),
*regardless of the value of @var{res}*, if the calling thread is the
only thread in the process.

> +@deftypefun int thrd_detach (thrd_t @var{thr})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Detaches the thread identified by @var{thr} from the current
> +environment.
> +The resources held by the thread will be freed automatically once
> +the thread exits.
> +@end deftypefun

I know this is what the C standard says this does, but it's not
actually a helpful thing to say.  It would be better to say something
like "Informs the implementation that the program does not need any
sort of notification when @var{thr} exits."

> +@deftypefun int mtx_init (mtx_t* @var{mutex},int @var{type})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Creates a new mutex object with type @var{type}. The object pointed
> +to by @var{mutex} is set to an identifier of the newly created mutex.
> +@end deftypefun

As mentioned above, explain the various values @var{type} can take
*here*, not at the bottom of the section.

> +@deftypefun int mtx_timedlock (mtx_t *restrict @var{mutex}, const
struct timespec *restrict @var{time_point})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Blocks the current thread until the mutex pointed to by @var{mutex}
> +is locked or until the TIME_UTC based time point pointed to
> +by @var{time_point} has been reached.

Again, TIME_UTC is not documented, so just say "wall-clock time".
Point out specifically that this function differs from thr_sleep, in
that it takes an absolute time point rather than a duration.

> +@deftypefun int mtx_trylock (mtx_t *@var{mutex})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Tries to lock the mutex pointed to by @var{mutex} without blocking.
> +Returns immediately if the mutex is already locked.

"Returns thrd_success if it locked the mutex, or if this thread has
already locked the mutex.  (This does not count as a recursive lock.)
Returns thrd_busy if another thread holds the lock."

(Does the case where the lock is already held indeed not count as a
recursive lock?  That could be extremely bad.)

> +@deftypefun int mtx_unlock (mtx_t *@var{mutex})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Unlocks the mutex pointed to by @var{mutex}. The behavior is undefined
> +if the mutex is not locked by the calling thread. This function
> +synchronizes-with subsequent @code{mtx_lock}, @code{mtx_trylock},
> +or @code{mtx_timedlock} 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).
> +@end deftypefun

If you have recursively locked a mutex N times, do you need to unlock
it N times also?  (I see that C11 does not say.)

> +Mutexes are not the only synchronization mechanisms available. For some
> +more complex tasks, @theglibc{} also implements condition variables,
> +that allow the user to think in a higher level to solve possible
> +mutual exclusion issues.

This paragraph doesn't make any sense.

> +@deftypefun int cnd_timedwait (cnd_t* restrict @var{cond}, mtx_t*
restrict @var{mutex}, const struct timespec* restrict @var{time_point})
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +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}, or until the TIME_UTC based
> +time point pointed to by @var{time_point} has been reached. The mutex
> +is locked again before the function returns.
> +@end deftypefun

Same deal with TIME_UTC and being clear that this function, unlike
thrd_sleep, *does* take an absolute time.

> +@deftypevr Macro {} TSS_DTOR_ITERATIONS
> +Integer constant expression representing the maximum number of
> +times that destructors will be called when a thread terminates.
> +@end deftypevr

This also doesn't make any sense.  I see that this text was copied
verbatim from C11, but that isn't an excuse :)

Ideally there would be something in here about when you should use
thread_local versus tss_*.

> +@deftypefun int tss_create (tss_t* @var{tss_key}, tss_dtor_t
@var{destructor})

When would the destructor be called?

> +The ISO C11 specification also provides new error types that belong
> +specifically to @code{threads.h}. @Theglibc{} has also implemented
> +this feature and every function in this API always returns one of the
> +following error codes:

Does that mean none of them ever set errno?

> +@item thrd_error
> +Value returned by a function to indicate that the requested operation
> +failed.

Gosh, that's vague.

zw
Torvald Riegel Aug. 18, 2015, 4:18 p.m. UTC | #2
Disclaimer:  I haven't had time to look through the actual
documentation, but want to comment nonetheless early so that we agree on
the general direction.

On Tue, 2015-08-11 at 14:06 -0400, Zack Weinberg wrote:
> It's very important to minimize forward references in documentation.
> That is, if someone starts reading at the beginning of a chapter, by
> the time they get to 'foo' they should already have encountered all
> the new concepts from that chapter that are necessary to understand
> 'foo'.

Agreed that this makes it easier, but understanding a concept does not
mean that one knows about all possible instances of it.  Specifically,
it's perfectly fine to introduce the concept of a Threading Result Code
without actually enumerating all the specific codes.  Putting the
enumeration further down in the manual can even be easier because the
codes aren't central to the understanding, I'd claim -- users would be
interested in the functions first, and then care about error conditions.

> General editorial comments:
> 
> We do not appear to have any documentation of C11 atomics right now,
> and that means you need to avoid *talking* about C11 atomics or
> anything that you need to know C11 atomic terminology to understand.
> All the "synchronizes-with" stuff -- just delete it.

I disagree.  First, synchronizes-with is not tied C11 atomics, but to
the C11 memory model.  The semantics of atomics are described based on
the memory model.

If we try to document the semantics of the thread functions at all, we
need to assume the reader is familiar with the memory model.  Otherwise,
we just shouldn't document any of the synchronization semantics (at
which point we can just omit the docs completely I'd say).


More generally, I'm also wondering why we even try to document semantics
that are (supposed to be) documented perfectly by C11.  I agree that the
C11 specs aren't as precise as we'd want them to be, but then we need to
make it clear that whatever we're documenting is just illustrative and
not the authorative spec (which is C11), or covers
implementation-defined behavior, or covers our interpretation of C11.

> I'm cross-checking your work with C11 (N1570) and there are a bunch of
> places where the standard doesn't specify the behavior as precisely as
> I would like, which is really quite unfortunate; we should think about
> the extent to which we want to pin down unspecified cases.

If we do so, we should also look at C++14.  It specifies the
synchronization stuff more thoroughly, and arguably C++ and C should be
aligned where possible.

> > +@deftypefun int mtx_trylock (mtx_t *@var{mutex})
> > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> > +Tries to lock the mutex pointed to by @var{mutex} without blocking.
> > +Returns immediately if the mutex is already locked.
> 
> "Returns thrd_success if it locked the mutex, or if this thread has
> already locked the mutex.  (This does not count as a recursive lock.)
> Returns thrd_busy if another thread holds the lock."
> 
> (Does the case where the lock is already held indeed not count as a
> recursive lock?  That could be extremely bad.)

I believe calling mtx_trylock on a nonrecursive mutex is undefined
behavior.  It's not specifically called out in C (but is in C++), but
mtx_lock makes that requirement.

> > +@deftypefun int mtx_unlock (mtx_t *@var{mutex})
> > +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> > +Unlocks the mutex pointed to by @var{mutex}. The behavior is undefined
> > +if the mutex is not locked by the calling thread. This function
> > +synchronizes-with subsequent @code{mtx_lock}, @code{mtx_trylock},
> > +or @code{mtx_timedlock} 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).

The sc relation for sequential consistency is a better similarity.  But
we really should just point to C11 here instead of inventing our own
wording.

> > +@end deftypefun
> 
> If you have recursively locked a mutex N times, do you need to unlock
> it N times also?  (I see that C11 does not say.)

Yes, you have to.  If C11 should say that, this should be treated as a
C11 defect.

> > +Mutexes are not the only synchronization mechanisms available. For some
> > +more complex tasks, @theglibc{} also implements condition variables,
> > +that allow the user to think in a higher level to solve possible
> > +mutual exclusion issues.
> 
> This paragraph doesn't make any sense.

Agreed, it's incorrect.  condvars are not a mutual exclusion mechanism.

> > +@deftypevr Macro {} TSS_DTOR_ITERATIONS
> > +Integer constant expression representing the maximum number of
> > +times that destructors will be called when a thread terminates.
> > +@end deftypevr
> 
> This also doesn't make any sense.  I see that this text was copied
> verbatim from C11, but that isn't an excuse :)

Well, copying C11 is better than inventing our own semantics that might
diverge from C11.  Thus, the way forward is to clarify this upstream
first, and then specify what upstream does -- and upstream is ISO C in
this case.

> Ideally there would be something in here about when you should use
> thread_local versus tss_*.
> 
> > +@deftypefun int tss_create (tss_t* @var{tss_key}, tss_dtor_t
> @var{destructor})
> 
> When would the destructor be called?
> 
> > +The ISO C11 specification also provides new error types that belong
> > +specifically to @code{threads.h}. @Theglibc{} has also implemented
> > +this feature and every function in this API always returns one of the
> > +following error codes:
> 
> Does that mean none of them ever set errno?
> 
> > +@item thrd_error
> > +Value returned by a function to indicate that the requested operation
> > +failed.
> 
> Gosh, that's vague.

But that may be the right description, given that it's a catch-all code.
diff mbox

Patch

diff --git a/manual/Makefile b/manual/Makefile
index 5382208..04c9154 100644
--- a/manual/Makefile
+++ b/manual/Makefile
@@ -38,7 +38,8 @@  chapters = $(addsuffix .texi, \
 		       message search pattern io stdio llio filesys	\
 		       pipe socket terminal syslog math arith time	\
 		       resource setjmp signal startup process ipc job	\
-		       nss users sysinfo conf crypt debug threads probes)
+		       nss users sysinfo conf crypt debug threads probes \
+		       isothreads)
 add-chapters = $(wildcard $(foreach d, $(add-ons), ../$d/$d.texi))
 appendices = lang.texi header.texi install.texi maint.texi platform.texi \
 	     contrib.texi
diff --git a/manual/isothreads.texi b/manual/isothreads.texi
new file mode 100644
index 0000000..8a602a2
--- /dev/null
+++ b/manual/isothreads.texi
@@ -0,0 +1,326 @@ 
+@node ISO Threads, , , Top
+@chapter ISO C11 threads
+
+This chapter describes @theglibc{} ISO C11 threads implementation.
+All types and function prototypes are declared in 
+@file{threads.h} header.
+@pindex threads.h
+
+@menu
+* Thread:: Support for basic threading
+* Mutex:: Low level mechanism for mutual exclusion
+* Condition variable:: Objects required for threads synchronization 
+* Thread-local storage:: Functions to support thread-local storage
+* C11 error types:: Symbolic constants that represent functions return value
+@end menu
+
+@node Thread, Mutex, , ISO Threads
+@section Thread
+
+@Theglibc{} implements a set of functions that allows the user
+to easily create and use threads. Many extra functionalities are
+provided to control the behaviour of threads. The following functions 
+and types are defined:
+
+@deftp {Data Type} {thrd_t}
+Unique number that identifies a thread
+unequivocally.
+@end deftp
+
+@deftp {Data Type} {thrd_start_t}
+It is a function pointer that is passed to @code{thrd_create} when
+creating a new thread. Should point to the first function that thread
+will run.
+@end deftp
+
+@deftypefun int thrd_create (thrd_t *@var{thr}, thrd_start_t @var{func}, void *@var{arg})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Create a new thread executing the function @var{func}. The object
+pointed by @var{arg} will be taken as @var{func} arguments. If successful,
+@var{thr} is so to the new thread identifier.
+@end deftypefun
+
+
+@deftypefun int thrd_equal (thrd_t @var{lhs}, thrd_t @var{rhs})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Checks whether @var{lhs} and @var{rhs} refer to the same thread.
+@end deftypefun
+
+
+@deftypefun thrd_t thrd_current (void)
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Returns the identifier of the calling thread.
+@end deftypefun
+
+@deftypefun int thrd_sleep (const struct timespec* @var{time_point}, struct timespec* @var{remaining})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Blocks the execution of the current thread for at least until
+the TIME_UTC based time point pointed to by @var{time_point} has been
+reached.
+
+The sleep may resume earlier if a signal that is not ignored is
+received. In such case, if remaining is not NULL, the remaining
+time duration is stored into the object pointed to by @var{remaining}
+@end deftypefun
+
+@deftypefun void thrd_yield (void)
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Provides a hint to the implementation to reschedule the execution
+of threads, allowing other threads to run.
+@end deftypefun
+
+@deftypefun _Noreturn void thrd_exit (int @var{res})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Terminates execution of the calling thread and sets its result code
+to @var{res}.
+@end deftypefun
+
+@deftypefun int thrd_detach (thrd_t @var{thr})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Detaches the thread identified by @var{thr} from the current
+environment.
+The resources held by the thread will be freed automatically once
+the thread exits.
+@end deftypefun
+
+@deftypefun int thrd_join (thrd_t @var{thr}, int *@var{res})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Blocks the current thread until the thread identified by @var{thr}
+finishes execution. If @var{res} is not a null pointer, the result
+code of the thread is put to the location pointed to by @var{res}.
+The termination of the thread synchronizes-with the
+completion of this function.
+The behavior is undefined if the thread was previously detached
+or joined by another thread.
+@end deftypefun
+
+
+@node Mutex, Condition variable, Thread, ISO Threads
+@section Mutex
+
+To have a better control of resources and how threads access them,
+@theglibc{} also implements a mutex object, that allows to
+avoid race conditions and some other concurrency issues.
+
+@deftypefun int mtx_init (mtx_t* @var{mutex},int @var{type})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Creates a new mutex object with type @var{type}. The object pointed 
+to by @var{mutex} is set to an identifier of the newly created mutex.
+@end deftypefun
+
+@deftypefun int mtx_lock (mtx_t* @var{mutex})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+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, and all lock/unlock operations on any given mutex
+form a single total order (similar to the modification order of
+an atomic).
+@end deftypefun
+
+@deftypefun int mtx_timedlock (mtx_t *restrict @var{mutex}, const struct timespec *restrict @var{time_point})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Blocks the current thread until the mutex pointed to by @var{mutex}
+is locked or until the TIME_UTC based time point pointed to
+by @var{time_point} has been reached.
+The behavior is undefined if the current thread has already
+locked the mutex and the mutex is not recursive.
+The behavior is undefined if the mutex does not support timeout.
+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).
+@end deftypefun
+
+@deftypefun int mtx_trylock (mtx_t *@var{mutex})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Tries to lock the mutex pointed to by @var{mutex} without blocking.
+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).
+@end deftypefun
+
+@deftypefun int mtx_unlock (mtx_t *@var{mutex})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Unlocks the mutex pointed to by @var{mutex}. The behavior is undefined 
+if the mutex is not locked by the calling thread. This function 
+synchronizes-with subsequent @code{mtx_lock}, @code{mtx_trylock},
+or @code{mtx_timedlock} 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).
+@end deftypefun
+
+@deftypefun void mtx_destroy (mtx_t *@var{mutex})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Destroys the mutex pointed to by @var{mutex}.
+If there are threads waiting on mutex, the behavior is undefined.
+@end deftypefun
+
+@deftypefun void call_once (once_flag* @var{flag}, void (*@var{func})(void))
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+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 @var{flag} variable.
+@end deftypefun
+
+The ISO C11 standard also defines several types of mutex that are
+also supported. They are represented with symbolic constants
+(enumeration type values) and are the following:
+
+@vtable @code
+
+@item mtx_plain
+Mutex type that does not support timeout or test and return.
+
+@item mtx_recursive
+Mutex type that supports recursive locking, what means that owner
+thread can lock it twice or more without causing deadlock.
+
+@item mtx_timed
+Mutex type that supports timeout.
+
+@end vtable
+
+@node Condition variable, Thread-local storage, Mutex, ISO Threads
+@section Condition Variable
+
+Mutexes are not the only synchronization mechanisms available. For some
+more complex tasks, @theglibc{} also implements condition variables,
+that allow the user to think in a higher level to solve possible
+mutual exclusion issues.
+
+@deftypefun int cnd_init (cnd_t* @var{cond})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Initializes new condition variable. The object pointed to by
+@var{cond} will be set to value that identifies the condition variable.
+@end deftypefun
+
+@deftypefun int cnd_signal (cnd_t *@var{cond})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Unblocks one thread that currently waits on condition variable
+pointed to by @var{cond}. If no threads are blocked, does nothing and
+returns @code{thrd_success}.
+@end deftypefun
+
+@deftypefun int cnd_broadcast (cnd_t *@var{cond})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Unblocks all threads that currently wait on condition variable
+pointed to by @var{cond}. If no threads are blocked, does nothing
+and returns @code{thrd_success}.
+@end deftypefun
+
+@deftypefun int cnd_wait (cnd_t* @var{cond}, mtx_t* @var{mutex})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+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}. The 
+mutex is locked again before the function returns.
+@end deftypefun
+
+@deftypefun int cnd_timedwait (cnd_t* restrict @var{cond}, mtx_t* restrict @var{mutex}, const struct timespec* restrict @var{time_point})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+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}, or until the TIME_UTC based
+time point pointed to by @var{time_point} has been reached. The mutex
+is locked again before the function returns.
+@end deftypefun
+
+@deftypefun void cnd_destroy (cnd_t* @var{cond})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Destroys the condition variable pointed to by @var{cond}.
+If there are threads waiting on @var{cond}, the behavior is undefined.
+@end deftypefun
+
+@node Thread-local storage, C11 error types, Condition variable, ISO Threads
+@section Thread-local Storage
+
+@Theglibc{} also implements different functions that adds
+funtionality for thread-local storage. That means that each thread can
+have their own variables and are not visible by other threads. The 
+functions and types provided are:
+
+@deftypevr Macro {} thread_local
+Used to mark a variable with thread storage duration, that means created
+when the thread starts, and cleaned up when the thread ends.
+@end deftypevr
+
+@deftypevr Macro {} ONCE_FLAG_INIT
+Value established to initialize an object of type @code{once_call}.
+@end deftypevr
+
+@deftypevr Macro {} TSS_DTOR_ITERATIONS
+Integer constant expression representing the maximum number of
+times that destructors will be called when a thread terminates.
+@end deftypevr
+
+@deftypefun int tss_create (tss_t* @var{tss_key}, tss_dtor_t @var{destructor})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Creates 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.
+@end deftypefun
+
+@deftypefun void *tss_get (tss_t @var{tss_key})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Returns the value held in thread-specific storage for the current
+thread identified by @var{tss_key}. Different threads 
+may get different values identified by the same key.
+@end deftypefun
+
+@deftypefun int tss_set (tss_t @var{tss_id}, void *@var{val})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Sets the value of the thread-specific storage identified by
+@var{tss_id} for the current thread to @var{val}. Different threads
+may set different values to the same key.
+The destructor, if available, is not invoked.
+@end deftypefun
+
+@deftypefun void tss_delete (tss_t @var{tss_id})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Destroys the thread-specific storage identified by @var{tss_id}.
+The destructor, if one was registered by @code{tss_create}, is not
+called
+@end deftypefun
+
+@node C11 error types, , Thread-local storage, ISO Threads
+@section Error Types
+
+The ISO C11 specification also provides new error types that belong
+specifically to @code{threads.h}. @Theglibc{} has also implemented
+this feature and every function in this API always returns one of the
+following error codes:
+
+
+@vtable @code
+
+@item thrd_timedout
+Value returned by a function to indicate that a specified time was
+reached without acquiring the requested resource, usually a mutex
+or condition variable.
+
+@item thrd_sucess
+Value returned by a function to indicate that the requested operation
+succeded.
+
+@item thrd_busy
+Value returned by a function to indicate that the requested operation
+failed because a resource requested is already in use.
+
+@item thrd_error
+Value returned by a function to indicate that the requested operation
+failed.
+
+@item thrd_nomem
+Value returned by a function to indicate that the requested operation
+failed because it was unable to allocate enough memory.
+
+@end vtable