Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-signal.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
79# ifndef AH_SIGNAL_H
80# define AH_SIGNAL_H
81
82# include <csignal>
83# include <cstring>
84# include <iostream>
85# include <stdexcept>
86# include <string>
87# include <initializer_list>
88# include <aleph.H>
89
95class SignalError : public std::runtime_error
96{
99
100public:
107 SignalError(const std::string & msg, int signo = -1, int err = 0)
108 : std::runtime_error(msg), signal_num_(signo), errno_code_(err) {}
109
111 [[nodiscard]] int signal_number() const noexcept { return signal_num_; }
112
114 [[nodiscard]] int error_code() const noexcept { return errno_code_; }
115};
116
133{
134 sigset_t set_;
135
136public:
138 SignalSet() noexcept { sigemptyset(&set_); }
139
141 SignalSet(std::initializer_list<int> signals) noexcept
142 {
143 sigemptyset(&set_);
144 for (int sig : signals)
145 sigaddset(&set_, sig);
146 }
147
149 [[nodiscard]] static SignalSet full() noexcept
150 {
151 SignalSet s;
152 sigfillset(&s.set_);
153 return s;
154 }
155
157 [[nodiscard]] static SignalSet empty() noexcept { return SignalSet(); }
158
161 SignalSet & add(int signo) noexcept
162 {
163 sigaddset(&set_, signo);
164 return *this;
165 }
166
169 SignalSet & remove(int signo) noexcept
170 {
171 sigdelset(&set_, signo);
172 return *this;
173 }
174
177 SignalSet & clear() noexcept
178 {
179 sigemptyset(&set_);
180 return *this;
181 }
182
185 SignalSet & fill() noexcept
186 {
187 sigfillset(&set_);
188 return *this;
189 }
190
192 [[nodiscard]] bool contains(int signo) const noexcept
193 {
194 return sigismember(&set_, signo) == 1;
195 }
196
198 [[nodiscard]] sigset_t * get() noexcept { return &set_; }
199
201 [[nodiscard]] const sigset_t * get() const noexcept { return &set_; }
202
204 operator sigset_t *() noexcept { return &set_; }
205
207 operator const sigset_t *() const noexcept { return &set_; }
208};
209
233{
234 sigset_t old_mask_;
235 bool active_ = true;
236
237public:
243 explicit SignalBlocker(const SignalSet & signals)
244 {
245 if (sigprocmask(SIG_BLOCK, signals.get(), &old_mask_) < 0)
246 throw SignalError("sigprocmask(SIG_BLOCK) failed", -1, errno);
247 }
248
254 SignalBlocker(std::initializer_list<int> signals)
255 : SignalBlocker(SignalSet(signals)) {}
256
262 explicit SignalBlocker(int signo)
263 : SignalBlocker(SignalSet({signo})) {}
264
267 {
268 if (active_)
269 sigprocmask(SIG_SETMASK, &old_mask_, nullptr);
270 }
271
273 void release() noexcept { active_ = false; }
274
276 [[nodiscard]] const sigset_t & previous_mask() const noexcept
277 {
278 return old_mask_;
279 }
280
281 // Non-copyable
282 SignalBlocker(const SignalBlocker &) = delete;
284
285 // Movable
286 SignalBlocker(SignalBlocker && other) noexcept
287 : old_mask_(other.old_mask_), active_(other.active_)
288 {
289 other.active_ = false;
290 }
291
293 {
294 if (this != &other)
295 {
296 if (active_)
297 sigprocmask(SIG_SETMASK, &old_mask_, nullptr);
298 old_mask_ = other.old_mask_;
299 active_ = other.active_;
300 other.active_ = false;
301 }
302 return *this;
303 }
304};
305
354{
355public:
357 using Handler = void (*)(int);
358
359private:
360 struct sigaction old_action_;
363 bool active_ = true;
364
365 // Internal constructor that doesn't abort on error
366 struct NoAbortTag {};
367
368 Signal(NoAbortTag, int signo, Handler func, bool restart_calls, int & error_out)
369 : signal_number_(signo), restart_calls_(restart_calls)
370 {
371 error_out = 0;
372 struct sigaction act;
373
374 act.sa_handler = func;
375 sigemptyset(&act.sa_mask);
376 act.sa_flags = 0;
377
378 if (signo == SIGALRM)
379 {
380#ifdef SA_INTERRUPT
381 act.sa_flags |= SA_INTERRUPT;
382#endif
383 }
384 else if (restart_calls_)
385 {
386#ifdef SA_RESTART
387 act.sa_flags |= SA_RESTART;
388#endif
389 }
390
391 if (sigaction(signo, &act, &old_action_) < 0)
392 {
393 error_out = errno;
394 active_ = false;
395 }
396 }
397
398public:
416 Signal(int signo, Handler func, bool restart_calls = true)
417 : signal_number_(signo), restart_calls_(restart_calls)
418 {
419 struct sigaction act;
420
421 act.sa_handler = func;
422 sigemptyset(&act.sa_mask);
423 act.sa_flags = 0;
424
425 if (signo == SIGALRM)
426 {
427#ifdef SA_INTERRUPT
428 act.sa_flags |= SA_INTERRUPT;
429#endif
430 }
431 else if (restart_calls_)
432 {
433#ifdef SA_RESTART
434 act.sa_flags |= SA_RESTART;
435#endif
436 }
437
438 if (sigaction(signo, &act, &old_action_) < 0)
439 {
440 std::cerr << "Cannot modify the action associated with the signal "
441 << signo << std::endl;
442 abort();
443 }
444 }
445
446
470 [[nodiscard]] static Signal create(int signo, Handler func,
471 bool restart_calls = true)
472 {
473 int error = 0;
474 Signal sig(NoAbortTag{}, signo, func, restart_calls, error);
475 if (error != 0)
476 throw SignalError("Cannot modify signal action for signal " +
477 std::to_string(signo) + ": " + std::strerror(error),
478 signo, error);
479 return sig;
480 }
481
503 [[nodiscard]] static Signal try_create(int signo, Handler func,
504 bool restart_calls, int & error_out)
505 {
506 return Signal(NoAbortTag{}, signo, func, restart_calls, error_out);
507 }
508
521 {
522 if (active_)
523 {
524 if (sigaction(signal_number_, &old_action_, nullptr) < 0)
525 {
526 std::cerr << "Cannot restore signal handler for signal "
527 << signal_number_ << std::endl;
528 abort();
529 }
530 }
531 }
532
550 void release() noexcept { active_ = false; }
551
553 [[nodiscard]] int signal_number() const noexcept { return signal_number_; }
554
556 [[nodiscard]] bool restarts_calls() const noexcept { return restart_calls_; }
557
559 [[nodiscard]] bool is_active() const noexcept { return active_; }
560
562 [[nodiscard]] Handler previous_handler() const noexcept
563 {
564 return old_action_.sa_handler;
565 }
566
568 [[nodiscard]] const struct sigaction & previous_action() const noexcept
569 {
570 return old_action_;
571 }
572
573 // Non-copyable (would cause double restoration)
574 Signal(const Signal &) = delete;
575 Signal & operator=(const Signal &) = delete;
576
583 Signal(Signal && other) noexcept
584 : old_action_(other.old_action_),
585 signal_number_(other.signal_number_),
586 restart_calls_(other.restart_calls_),
587 active_(other.active_)
588 {
589 other.active_ = false;
590 }
591
598 Signal & operator=(Signal && other) noexcept
599 {
600 if (this != &other)
601 {
602 // Restore our handler first if active (ignore errors in move)
603 if (active_)
604 sigaction(signal_number_, &old_action_, nullptr);
605
606 old_action_ = other.old_action_;
607 signal_number_ = other.signal_number_;
608 restart_calls_ = other.restart_calls_;
609 active_ = other.active_;
610 other.active_ = false;
611 }
612 return *this;
613 }
614};
615
635[[nodiscard]] inline int wait_for_signal(const SignalSet & signals)
636{
637 int sig = 0;
638 int result = sigwait(signals.get(), &sig);
639 if (result != 0)
640 throw SignalError("sigwait failed", -1, result);
641 return sig;
642}
643
652inline bool send_signal_to_self(int signo) noexcept
653{
654 return raise(signo) == 0;
655}
656
665[[nodiscard]] inline std::string signal_name(int signo)
666{
667 switch (signo)
668 {
669 case SIGHUP: return "SIGHUP";
670 case SIGINT: return "SIGINT";
671 case SIGQUIT: return "SIGQUIT";
672 case SIGILL: return "SIGILL";
673 case SIGABRT: return "SIGABRT";
674 case SIGFPE: return "SIGFPE";
675 case SIGKILL: return "SIGKILL";
676 case SIGSEGV: return "SIGSEGV";
677 case SIGPIPE: return "SIGPIPE";
678 case SIGALRM: return "SIGALRM";
679 case SIGTERM: return "SIGTERM";
680 case SIGUSR1: return "SIGUSR1";
681 case SIGUSR2: return "SIGUSR2";
682 case SIGCHLD: return "SIGCHLD";
683 case SIGCONT: return "SIGCONT";
684 case SIGSTOP: return "SIGSTOP";
685 case SIGTSTP: return "SIGTSTP";
686 case SIGTTIN: return "SIGTTIN";
687 case SIGTTOU: return "SIGTTOU";
688#ifdef SIGBUS
689 case SIGBUS: return "SIGBUS";
690#endif
691#ifdef SIGTRAP
692 case SIGTRAP: return "SIGTRAP";
693#endif
694#ifdef SIGURG
695 case SIGURG: return "SIGURG";
696#endif
697#ifdef SIGXCPU
698 case SIGXCPU: return "SIGXCPU";
699#endif
700#ifdef SIGXFSZ
701 case SIGXFSZ: return "SIGXFSZ";
702#endif
703#ifdef SIGVTALRM
704 case SIGVTALRM: return "SIGVTALRM";
705#endif
706#ifdef SIGPROF
707 case SIGPROF: return "SIGPROF";
708#endif
709#ifdef SIGWINCH
710 case SIGWINCH: return "SIGWINCH";
711#endif
712#ifdef SIGIO
713 case SIGIO: return "SIGIO";
714#endif
715#ifdef SIGSYS
716 case SIGSYS: return "SIGSYS";
717#endif
718 default: return "Signal " + std::to_string(signo);
719 }
720}
721
730[[nodiscard]] inline std::string signal_description(int signo)
731{
732 const char * desc = strsignal(signo);
733 if (desc)
734 return desc;
735 return signal_name(signo);
736}
737
738# endif // AH_SIGNAL_H
int wait_for_signal(const SignalSet &signals)
Utility to wait for a signal.
Definition ah-signal.H:635
bool send_signal_to_self(int signo) noexcept
Sends a signal to the current process.
Definition ah-signal.H:652
std::string signal_description(int signo)
Returns a human-readable description of a signal.
Definition ah-signal.H:730
std::string signal_name(int signo)
Returns the name of a signal.
Definition ah-signal.H:665
Core header for the Aleph-w library.
RAII wrapper for temporarily blocking signals.
Definition ah-signal.H:233
SignalBlocker(int signo)
Blocks a single signal.
Definition ah-signal.H:262
sigset_t old_mask_
Definition ah-signal.H:234
SignalBlocker(SignalBlocker &&other) noexcept
Definition ah-signal.H:286
SignalBlocker & operator=(const SignalBlocker &)=delete
void release() noexcept
Releases ownership - the mask won't be restored on destruction.
Definition ah-signal.H:273
SignalBlocker(std::initializer_list< int > signals)
Blocks the signals specified in the initializer list.
Definition ah-signal.H:254
const sigset_t & previous_mask() const noexcept
Returns the previous signal mask that will be restored.
Definition ah-signal.H:276
SignalBlocker(const SignalBlocker &)=delete
SignalBlocker & operator=(SignalBlocker &&other) noexcept
Definition ah-signal.H:292
SignalBlocker(const SignalSet &signals)
Blocks the signals in the given set.
Definition ah-signal.H:243
~SignalBlocker()
Restores the previous signal mask.
Definition ah-signal.H:266
Exception thrown when a signal operation fails.
Definition ah-signal.H:96
int signal_number() const noexcept
Returns the signal number involved in the error.
Definition ah-signal.H:111
SignalError(const std::string &msg, int signo=-1, int err=0)
Constructs a SignalError.
Definition ah-signal.H:107
int errno_code_
Definition ah-signal.H:98
int error_code() const noexcept
Returns the errno value at the time of failure.
Definition ah-signal.H:114
int signal_num_
Definition ah-signal.H:97
C++ wrapper for sigset_t with a fluent interface.
Definition ah-signal.H:133
SignalSet & clear() noexcept
Clears the set (removes all signals).
Definition ah-signal.H:177
static SignalSet full() noexcept
Creates a full signal set (all signals).
Definition ah-signal.H:149
sigset_t set_
Definition ah-signal.H:134
static SignalSet empty() noexcept
Creates an empty signal set.
Definition ah-signal.H:157
SignalSet() noexcept
Creates an empty signal set.
Definition ah-signal.H:138
sigset_t * get() noexcept
Returns a pointer to the underlying sigset_t.
Definition ah-signal.H:198
const sigset_t * get() const noexcept
Returns a const pointer to the underlying sigset_t.
Definition ah-signal.H:201
SignalSet(std::initializer_list< int > signals) noexcept
Creates a signal set from an initializer list.
Definition ah-signal.H:141
bool contains(int signo) const noexcept
Checks if a signal is in the set.
Definition ah-signal.H:192
SignalSet & fill() noexcept
Fills the set with all signals.
Definition ah-signal.H:185
SignalSet & add(int signo) noexcept
Adds a signal to the set.
Definition ah-signal.H:161
SignalSet & remove(int signo) noexcept
Removes a signal from the set.
Definition ah-signal.H:169
RAII wrapper for POSIX signal handler registration.
Definition ah-signal.H:354
struct sigaction old_action_
Definition ah-signal.H:360
Signal(NoAbortTag, int signo, Handler func, bool restart_calls, int &error_out)
Definition ah-signal.H:368
int signal_number_
Definition ah-signal.H:361
bool restart_calls_
Definition ah-signal.H:362
int signal_number() const noexcept
Returns the signal number being handled.
Definition ah-signal.H:553
bool restarts_calls() const noexcept
Returns whether SA_RESTART is enabled for this handler.
Definition ah-signal.H:556
Signal(Signal &&other) noexcept
Move constructor.
Definition ah-signal.H:583
Signal & operator=(Signal &&other) noexcept
Move assignment operator.
Definition ah-signal.H:598
bool active_
Definition ah-signal.H:363
Signal & operator=(const Signal &)=delete
void release() noexcept
Releases ownership of the signal handler.
Definition ah-signal.H:550
Signal(int signo, Handler func, bool restart_calls=true)
Installs a signal handler.
Definition ah-signal.H:416
Signal(const Signal &)=delete
const struct sigaction & previous_action() const noexcept
Returns the previous sigaction structure.
Definition ah-signal.H:568
static Signal try_create(int signo, Handler func, bool restart_calls, int &error_out)
Attempts to create a Signal object.
Definition ah-signal.H:503
bool is_active() const noexcept
Returns whether this object will restore the handler on destruction.
Definition ah-signal.H:559
void(*)(int) Handler
Type alias for signal handler function.
Definition ah-signal.H:357
~Signal()
Restores the previous signal handler.
Definition ah-signal.H:520
static Signal create(int signo, Handler func, bool restart_calls=true)
Creates a Signal object or throws on failure.
Definition ah-signal.H:470
Handler previous_handler() const noexcept
Returns the previous handler that will be restored.
Definition ah-signal.H:562
STL namespace.