Submitter: Jens Gustedt
Submission Date:
2012-10-08
Source:
Reference Document: N/A
Version: 1.0
Date: 2012-10-08
Subject: underspecification of thread functions with void return
Summary
There is are several thread functions in C11 that don't provide
return values:
call_once
,
cnd_destroy
,
mtx_destroy
,
tss_delete
, and
thrd_yield
.
These functions can never fail.
On the other hand it is easily imaginable that for given implementations there might be conditions that have these functions fail. In particular first four refer to objects or structures of some kind and have to suppose that these are valid.
Discussion
POSIX threads have return types for the corresponding calls that may return valuable information to the application. Wrappers around POSIX threads currently have to ignore that information and are not able to return it, nor are they allowed to output a runtime diagnostic or to abort the program.
Implementations of C11 threads that use POSIX threads underneath in
a shallow interface (e.g through inline
functions) may
face multiple warnings from compilers or code analysers about
ignored return values.
It is unlikely that an implementation will be able to implement these functions in ways that guarantees their successful invocation under all circumstances. The standard not being precise on the possible conditions for failure opens the door to a great variety of behavior of these calls in such a case. It is possible that that variety of strategies to cope with errors is unavoidable, but the standard should at least note the most common conditions and force implementation defined behavior in these cases.
Suggested Technical Corrigendum
There are basically two main strategies to overcome that
difficulty. The first is to change the interfaces and to allow them
to return an int
-error code. The second to specify for
each call under what circumstances the behavior becomes undefined.
Both solutions require an analysis of the conditions under which these functions may fail. Fortunately, POSIX also provides us with such an analysis so the text could be more or less copied from there.
(0) common corrigendum proposed for both alternatives
call_once
,
The behavior of call_once
is undefined if flag
has automatic storage duration or is not initialized by
ONCE_FLAG_INIT
.
cnd_destroy
,
A destroyed condition variable object can be reinitialized
using cnd_init
; the results of otherwise referencing
the object after it has been destroyed are undefined.
It shall be safe to destroy an initialized condition variable object
upon which no threads are currently blocked. Attempting to destroy a
condition variable object upon which other threads are currently
blocked results in failure of the call.
mtx_destroy
,
A destroyed mutex object can be reinitialized
using mtx_init
; the results of otherwise referencing
the object after it has been destroyed are undefined.
Attempting to destroy a locked mutex or one that is referenced by
another thread that is blocked in a call to cnd_wait
results in failure of the call.
tss_delete
,
Any attempt to use key
following the call to
tss_delete
results in failure of the call.
Then, the two alternatives would be to add either of the two following snipets to the sections for each of the functions:
(1) UB
A failing call results in undefined behavior.
(2) Changing the return type from void
to int
would not break existing code, since such calls
could have up to now only be placed
in void
-context. Some compilers might add warnings
after the corrigendum, though, for unused return values. For each of
the functions in question add something equivalent to
... change the return type to int ...
An implementation should specify if it is able to handle failures
and what error indications are returned in such a case by the
function. If a particular implementation isn't able to handle
failures the behavior becomes undefined.