ISO/IEC SC22/WG14 document N1866 — Thread safety of set_constraint_handler_s discusses a design defect of the Annex K function set_constraint_handler_s that prevents the function from being used in multiple threads in the same program. The committee acknowledged the defect at the St. Louis meeting in October 2014 and requested that the submitter of the defect report propose a solution. This paper is a response to this request.
The design of the proposed changes was driven by the following goals:
Reduce the risk that calls to the set_constraint_handler_s from multiple threads in the same program will have unexpected effects in existing programs. Currently, such calls will replace the runtime-constraint handler in a thread that may be relying on it.
Minimize breaking changes to existing correct programs by preserving the effects of the set_constraint_handler_s function as much as possible. In particular, the intent is to continue to be possible for any thread in a program to call set_constraint_handler_s and a set a new process-wide handler for all threads, either running or yet to be created, so long as those threads have not yet come to rely on the current handler. However, once a thread comes to rely on the handler in effect by virtue of calling any of the Annex K functions, including set_constraint_handler_s itself, it would be unsafe to allow another thread to replace it.
Thus, the proposed changes require implementations of Annex K to at the same time "propagate" the handler set by one thread to others that haven't made of use the Annex, and avoid propagating the handler to those that have.
Specify a new function with intutive semantics to allow individual threads to set their own runtime-constraint handler without affecting other existing threads in the program. Two sets of semantics were considered for threads that make use of this new function and create child threads of their own:
Note: POSIX specifies that a child thread inherits the signal mask of its parent thread.
The following corrigendum proposes changes that make it possible for one thread in a program to replace the runtime-constraint handler registered for it by another thread without affecting the other thread's behavior.
Add to the end of §B.21 General utilities <stdlib.h>, a declaration of a function thrd_set_constraint_handler_s as indicated below.
constraint_handler_t set_constraint_handler_s(constraint_handler_t handler); constraint_handler_t thrd_set_constraint_handler_s(constraint_handler_t handler);
Rartionale: The thrd_ prefix was chosen because it's used by the C11 threads library. The <stdlib.h> header has been chosen because declaring the function in <threads.h> would not be sufficient since the function needs to be provided even by implementations that do not support the header but support other kinds of threads interfaces (such as POSIX Threads or OpenMP). Implementations that don't support threads of any kind are expected to define the function with the same semantics as set_constraint_handler_s since they are indistinguishable in such environments.
Change §K.3.1.4 Runtime-constraint violations, paragraph 2, as follows:
If a runtime-constraint is violated, the implementation shall call the currently registered runtime-constraint handler (see set_constraint_handler_s and thrd_set_constraint_handler_s in <stdlib.h>).
Change the Description of the set_constraint_handler_s function in §K.3.6.1.1, paragraph 2, as follows:
The set_constraint_handler_s function sets the runtime-constraint handler to be handler for the calling thread and any threads yet to be created by it, for every other existing thread in the program that has not yet made a call to any function defined in Annex K or has been created by a thread that has made such a call, and for all threads that are yet to be created by such threads. The runtime-constraint handler is the function to be called when a library function invoked by the same thread detects a runtime-constraint violation. Only the most recent handler registered
withby a call to set_constraint_handler_s or thrd_set_constraint_handler_s is called when a runtime-constraint violation occurs.
Rationale: The intent is for child threads of the thread that has either registered a runtime-constraint handler by calling set_constraint_handler_s, or that has "inherited" such a handler from its parent thread by calling one of the other Annex K functions, to inherit the parent thread's handler. In cases where letting the child inherit the parent's handler isn't desirable the parent thread can temporarily replace its handler with the one the child thread should inherit instead by calling thrd_set_constraint_handler_s and save its result, create the child thread, and restore the original handler by calling thrd_set_constraint_handler_s with the saved result as an argument.
Change §K.3.6.1.1, paragraph 4, as follows:
The implementation-definedhas adefault runtime-constraint handlerthatis used ifno calls toit has not been replaced by a call to the set_constraint_handler_s or thrd_set_constraint_handler_s functionhave been made.
Add a new section titled The thrd_set_constraint_handler_s function, immediately following §K.3.6.1.1, with the following text:
K.3.6.1.? The thrd_set_constraint_handler_s function
Synopsis
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdlib.h> constraint_handler_t thrd_set_constraint_handler_s(constraint_handler_t handler);Description
The thrd_set_constraint_handler_s function behaves the same way as the set_constraint_handler_s function except that it sets the runtime-constraint handler to handler only for the calling thread and for any threads that are yet to be created by the calling thread. The function has no effect on other threads in the program.Footnote) The remaining effects of the two functions are identical, as are their return values.
Footnote) The function is required to be provided even by implementations that define the __STDC_NO_THREADS__ macro to 1.
Change Footnote 407 in §K.3.6.2.1, paragraph 2 as follows:
If the runtime-constraint handler for a thread is set to the ignore_handler_s function, any library function call in which a runtime-constraint violation occurs will return to its caller.
Rationale: The intent is to avoid any misunderstanding that ignore_handler_s is somehow special and that registering it causes a process-wide change to all runtime-constraint handlers across all threads.