Qore Programming Language  1.12.0
QoreSignal.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreSignal.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2022 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 #ifdef HAVE_SIGNAL_HANDLING
33 #ifndef _QORE_QORESIGNAL_H
34 
35 #define _QORE_QORESIGNAL_H
36 
37 #include <qore/QoreThreadLock.h>
38 #include <qore/QoreCondition.h>
39 #include <qore/QoreCounter.h>
40 
41 #include <csignal>
42 #include <map>
43 #include <string>
44 
45 // maximum number of signals
46 #ifndef QORE_SIGNAL_MAX
47 #ifdef NSIG
48 #define QORE_SIGNAL_MAX (NSIG+1)
49 #elif defined _NSIG
50 #define QORE_SIGNAL_MAX _NSIG
51 #elif defined _NSIGS
52 #define QORE_SIGNAL_MAX _NSIGS
53 #elif defined __DARWIN_NSIG
54 #define QORE_SIGNAL_MAX (__DARWIN_NSIG+1)
55 #else
56 #error do not know maximum signal number on this platform
57 #endif
58 #endif
59 
60 // use SIGSYS for the status signal
61 #define QORE_STATUS_SIGNAL SIGSYS
62 
63 class CodePgm {
64 public:
66  QoreProgram* pgm;
67 
68  DLLLOCAL void setProgram(QoreProgram* n_pgm) {
69  assert(n_pgm);
70  pgm = n_pgm;
71  pgm->ref();
72  //printd(5, "CodePgm::setProgram() pgm: %p %d -> %d\n", pgm, pgm->reference_count() - 1, pgm->reference_count());
73  }
74 
75  DLLLOCAL CodePgm() : funcref(0), pgm(0) {
76  }
77 
78  DLLLOCAL CodePgm(ResolvedCallReferenceNode* f, QoreProgram* p) : funcref(f), pgm(p) {
79  }
80 
81  // must be called in the signal lock
82  DLLLOCAL void set(const ResolvedCallReferenceNode* n_funcref, QoreProgram* n_pgm) {
83  assert(!funcref);
84  assert(!pgm);
85 
86  funcref = n_funcref->refRefSelf();
87  setProgram(n_pgm);
88  }
89 
90  // must be called in the signal lock
91  DLLLOCAL CodePgm replace(const ResolvedCallReferenceNode* n_funcref, QoreProgram* n_pgm) {
92  assert(funcref);
93  assert(pgm);
94  assert(n_funcref);
95  CodePgm rv(funcref, pgm);
96 
97  funcref = n_funcref->refRefSelf();
98  setProgram(n_pgm);
99  return rv;
100  }
101 
102  // must be called in the signal lock
103  DLLLOCAL CodePgm take() {
104  assert(funcref);
105  CodePgm rv(funcref, pgm);
106  funcref = 0;
107  pgm = 0;
108  return rv;
109  }
110 
111  DLLLOCAL void del(ExceptionSink* xsink) {
112  if (funcref) {
113  funcref->deref(xsink);
114  assert(pgm);
115  //printd(5, "CodePgm::del() pgm: %p %d -> %d\n", pgm, pgm->reference_count() + 1, pgm->reference_count());
116  pgm->deref(xsink);
117  }
118  }
119 };
120 
121 class QoreSignalHandler : public CodePgm {
122 public:
123  enum sh_status_e { SH_OK = 0, SH_InProgress = 1, SH_Delete = 2 };
124  sh_status_e status;
125 
126  DLLLOCAL void init();
127  DLLLOCAL void runHandler(int sig, ExceptionSink* xsink);
128  DLLLOCAL bool isSet() const {
129  return (bool)funcref;
130  }
131  DLLLOCAL QoreProgram* getProgram() const {
132  return pgm;
133  }
134 };
135 
136 // map of signals to module names
137 typedef std::map<int, std::string> sig_map_t;
138 
139 class QoreSignalManager {
140  friend class QoreSignalManagerBusyHelper;
141 
142 private:
143  bool is_enabled; // signal handling enabled?
144  pthread_t ptid; // handler thread
145  int tid; // handler thread TID
146  QoreCounter tcount; // thread counter, for synchronization only
147  QoreCondition cond; // to ensure atomicity of set and remove calls
148  bool block;
149  int waiting;
150 
151  DLLLOCAL void reload();
152  DLLLOCAL void stop_signal_thread_unlocked();
153  DLLLOCAL int start_signal_thread(ExceptionSink* xsink);
154  DLLLOCAL void stop_signal_thread();
155  DLLLOCAL void setMask(sigset_t& mask);
156 
157 public:
158  enum sig_cmd_e { C_None = 0, C_Reload = 1, C_Exit = 2 };
159 
160  // set of signals we are managing
161  sigset_t mask;
162 
163  // set of signals we do not manage (empty at start)
164  sig_map_t fmap;
165 
166  int num_handlers;
167  bool thread_running;
168  QoreSignalHandler handlers[QORE_SIGNAL_MAX];
169  QoreThreadLock mutex;
170  sig_cmd_e cmd;
171 
172  DLLLOCAL QoreSignalManager();
173  DLLLOCAL void init(bool disable_signal_mask = false);
174  DLLLOCAL void del();
175  DLLLOCAL int setHandler(int sig, const ResolvedCallReferenceNode* fr, ExceptionSink* xsink);
176  DLLLOCAL int removeHandler(int sig, ExceptionSink* xsink);
177  DLLLOCAL const char* getSignalName(int sig);
178  DLLLOCAL void signal_handler_thread();
179  DLLLOCAL void lock_idle();
180  DLLLOCAL void release_idle();
181  DLLLOCAL void start_handler();
182  DLLLOCAL void end_handler();
183  DLLLOCAL void preFork();
184  DLLLOCAL void postFork(bool new_process, ExceptionSink* xsink);
185  DLLLOCAL int q_gettid() {
186  return tid;
187  }
188  DLLLOCAL void reset_default_signal_mask();
189  DLLLOCAL bool running() { return tid != -1; }
190  DLLLOCAL bool enabled() { return is_enabled; }
191 
192  // try to allow the signal to be managed externally (by a module)
193  // sig = signal number, name = name of module to manage signal
194  // returns 0 for OK, or an error string on error
195  DLLLOCAL QoreStringNode* reassignSignal(int sig, const char* name);
196  // 0 = OK, -1 = no signals allocated (all or nothing)
197  DLLLOCAL QoreStringNode* reassignSignals(const sig_vec_t& sig_vec, const char* name);
198  DLLLOCAL int releaseSignal(int sig, const char* name);
199  // 0 = OK, -1 = no signals release (all or nothing)
200  DLLLOCAL int releaseSignals(const sig_vec_t& sig_vec, const char* name);
201 };
202 
203 DLLLOCAL extern QoreSignalManager QSM;
204 
205 #endif // _QORE_QORESIGNAL_H
206 #endif // HAVE_SIGNAL_HANDLING
std::vector< int > sig_vec_t
signal vector
Definition: QoreLib.h:51
DLLLOCAL void ref() const
increments the reference count of the object
Definition: AbstractPrivateData.h:51
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false,...
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
a thread condition class implementing a wrapper for pthread_cond_t
Definition: QoreCondition.h:45
a simple thread-safe counter object; objects can block on it until the counter reaches zero
Definition: QoreCounter.h:40
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:127
virtual DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count of the object
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
base class for resolved call references
Definition: CallReferenceNode.h:109
DLLLOCAL ResolvedCallReferenceNode * refRefSelf() const
references itself and returns this
Definition: CallReferenceNode.h:138
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
DLLEXPORT int q_gettid() noexcept
returns the current TID number