| 277 | static sigset_t sigwait_mask; |
| 278 | |
| 279 | static void* |
| 280 | sigwait_thread_function (void* d) |
| 281 | { |
| 282 | int sig; |
| 283 | if (int e = sigwait (&sigwait_mask, &sig)) |
| 284 | { |
| 285 | cerr << "error: unable to wait for signals: " |
| 286 | << system_error (e, generic_category ()) // Sanitize. |
| 287 | << endl; |
| 288 | |
| 289 | terminate (false /* trace */); |
| 290 | } |
| 291 | |
| 292 | if (sig == SIGUSR1) // Request to shutdown. |
| 293 | return nullptr; |
| 294 | |
| 295 | // Block all the threads that attempt to issue any diagnostics. |
| 296 | // |
| 297 | // Note that the primary goal here is to suppress diagnostics about |
| 298 | // abnormally terminated child processes, which could have been terminated |
| 299 | // due to a signal sent to the whole process group (see |
| 300 | // butl::process::wait() implementation for details on the issue we try to |
| 301 | // resolve). The blocked threads will stay as such until the process is |
| 302 | // terminated. |
| 303 | // |
| 304 | // Also note that there is still a possibility that after sigwait() returns, |
| 305 | // making the signal non-pending, and before the diagnostics mutex is |
| 306 | // locked, some threads may print the diagnostics we try to avoid. If it |
| 307 | // ever becomes a problem, we can consider using the Linux and FreeBSD |
| 308 | // specific signalfd() in combination with select() and read(), which seems |
| 309 | // to provide an ability to make the transition from the pending signal to |
| 310 | // the locked diagnostics mutex atomic. |
| 311 | // |
| 312 | diag_stream_lock dl; |
| 313 | |
| 314 | // Instruct the scheduler to pre-shutdown (stop executing new tasks, etc). |
| 315 | // |
| 316 | build2::scheduler& s (*static_cast<build2::scheduler*> (d)); |
| 317 | s.shutdown (false /* wait */); |
| 318 | |
| 319 | // Unblock the signal, so that it can be raised. |
| 320 | // |
| 321 | sigset_t um; |
| 322 | sigemptyset (&um); |
| 323 | sigaddset (&um, sig); |
| 324 | |
| 325 | if (int e = pthread_sigmask (SIG_UNBLOCK, &um, nullptr /* oldset */)) |
| 326 | { |
| 327 | cerr << "error: unable to unblock signal " << sig << ": " |
| 328 | << system_error (e, generic_category ()) // Sanitize. |
| 329 | << endl; |
| 330 | |
| 331 | terminate (false /* trace */); |
| 332 | } |
| 333 | |
| 334 | // Call the signal handler. |
| 335 | // |
| 336 | build2_b_cleanup_handler (sig); |
nothing calls this directly
no test coverage detected