Doc. No.: WG21/P0270R1
Date: 2016-07-10
Author: Hans-J. Boehm
Email: hboehm@google.com
Audience: Primarily LWG

P0270R1: Removing C dependencies from signal handler wording

This topic was briefly addressed in P0063R0, but the authors subsequently decided to address it separately. This version reflects P0270R0 discussion in Jacksonville, and of draft revisions in Oulu.

The current C++ working draft restricts signal handlers to functions in the intersection of C and C++. We believe this is dubious for at least three reasons:

We propose to remedy this by replacing the notion of a "POF", "plain old function" with a "signal-safe function" defined entirely in C++ terms. The definition we use largely excludes use of the library, thus avoiding any need to reimplement that in a signal-safe manner. This makes the definition rather restrictive. But we believe it remains at least theoretically possible for the user to write very sophisticated signal handlers through the use of atomics.

We expect that, although these changes are clearly substantive, there is no real practical impact. Existing implementations and user code should continue to work unchanged (or remain as broken as they always were.)

We do not exclude lambda expressions from signal handlers, on the assumption that the lambda expression itself should not require memory allocation. We do not say anything about non-function-local statics, since it should not be possible to trigger construction or destruction from within a signal handler.

As far as I can tell, the mem... and str... functions are not guaranteed to be async-signal-safe in Posix (or C), so it seems presumptive of us to declare them signal-safe here. I thus decided against it.

We somewhat separably propose to make the behavior of non-signal-safe functions in signal handlers undefined, instead of implementation-defined. We are not aware of any implementations that actually attempt to define this.

The restriction on static initialization warrants discussion. We currently allow even the call of a POF that doesn't access any globals to trigger static initialization (3.6.2p4 [basic.start.init]). It's not clear how to make that work if a thread already part way through the initialization receives the signal. This appears to me to be a preexisting problem that this exposes, rather than a problem introduced by this change.

It may make sense to eventually relax these restrictions invoked through an explicit synchronous raise() call. It's unclear that this is important enough to bother.

These changes are arguably not essential for the adoption of the P0063. But we believe they are highly desirable and should follow P0063 in fairly short order.

Proposed wording changes:

Thanks to help from the editors, these are roughly relative to the C++17 CD. Note that the underlying text changed substantially in Oulu, in ways that are orthogonal to our goals here.

Update 18.10.5 [csignal.syn] as follows. Insert a new paragraph before paragraph 3:

A plain lock-free atomic operation is an invocation of a function f from Clause 29, such that:

Modify the former paragraph 3 as follows.

The common subset of the C and C ++ languages consists of all declarations, definitions, and expressions that may appear in a well formed C++ program and also in a conforming C program. A POF (“plain old function”) is a function that uses only features from this common subset, and that does not directly or indirectly use any function that is not a POF, signal-safe if it does not, either directly or indirectly:

The behavior is undefined ofif any function other than a POFsignal-safe function with C language linkage (7.5) is used as a signal handler in a C++ program is implementation-defined.

Append a new paragraph.

The function signal() is signal-safe.

The following functions need to be callable from handlers. We expect that a few other functions should also eventually be declared signal-safe, but these are among the more blatant cases. abort() and quick_exit() are treated as safe by C.

Add a new paragraph at the beginning of section 18.3.2.4 [numeric.limits.members]:

Each member function defined in this Clause is signal-safe (18.10.5 [csignal.syn]).

Add a sentence at the end of the remarks for _Exit() in 18.5p3 [support.start.term]:

The function _Exit() is signal-safe (18.10.5 [csignal.syn]).

Add a sentence at the end of the remarks for abort() in 18.5p5 [support.start.term]:

The function abort() is signal-safe (18.10.5 [csignal.syn]).

Add at new element to the end of 18.5p13 (quick_exit()) [support.start.term]:

Remarks: The function quick_exit() is signal-safe (18.10.5 [csignal.syn]). [Note: It might still be unsafe to call quick_exit() from a handler, because the functions registered with at_quick_exit() might not be signal-safe. – end note]

Modify 18.9p1 [support.initlist] as follows:

The header <initializer_list> defines a class template and several support functions related to list-initialization (see 8.5.4). All functions specified in this Clause are signal-safe (18.10.5 [csignal.syn]).

Add a new paragraph between paragraphs 9 and 10 of section 20.2.1 [operators]:

All four of the above comparison operators are signal-safe (18.10.5 [csignal.syn]) when the expression in the Returns: element would be signal-safe.

Modify 20.2.4p1 [forward] as follows:

The library provides templated helper functions to simplify applying move semantics to an lvalue and to simplify the implementation of forwarding functions. All functions specified in this Clause are signal-safe (18.10.5 [csignal.syn]).

20.14 [meta] provides a few actual functions that return constant values. These are also clearly signal-safe. Add a new paragraph at the end of section 20.14 [meta], before 20.14.1:

All functions specified in this Clause are signal-safe (18.10.5 [csignal.syn]).

Acknowledgment

Clark Nelson provided many useful suggestions, but not necessarily agreement. This version reflects contributions by many other members of CWG and LWG, including Thomas Koeppe and JF Bastien, who helped shepherd it through CWG and LWG and provided additional feedback. This version was rebased on the current C++ working draft after CWG and LWG review.