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);
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 in <stdlib.h>).
Change the Description of the set_constraint_handler_s function in §K.126.96.36.199, paragraph 2, as follows:
The set_constraint_handler_s function sets the runtime-constraint handler to be handler. 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
withset_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.188.8.131.52, paragraph 4, as follows:
has adefault constraint handler thatis used if no calls tothe set_constraint_handler_s function have been made.
Add a new section titled The thrd_set_constraint_handler_s function, immediately following §K.184.108.40.206, 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);
Change Footnote 407 in §K.220.127.116.11, paragraph 2 as follows:
If the runtime-constraint handler is set to the ignore_handler_s function, any library function 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.