w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
RtclSignalAction.cpp
Go to the documentation of this file.
1// $Id: RtclSignalAction.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2013-2018 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2018-12-18 1089 1.0.5 use c++ style casts
8// 2018-11-30 1075 1.0.4 use list-init
9// 2014-11-08 602 1.0.3 cast int first to ptrdiff_t, than to ClientData
10// 2014-08-22 584 1.0.2 use nullptr
11// 2014-08-02 577 1.0.1 add include unistd.h (write+pipe dcl)
12// 2013-05-17 521 1.0 Initial version
13// ---------------------------------------------------------------------------
14
19#include <errno.h>
20#include <signal.h>
21#include <unistd.h>
22
23#include <iostream>
24
26
27#include "RtclSignalAction.hpp"
28
29using namespace std;
30
36// all method definitions in namespace Retro
37namespace Retro {
38
39RtclSignalAction* RtclSignalAction::fpObj = nullptr;
40
41//------------------------------------------+-----------------------------------
43bool RtclSignalAction::Init(Tcl_Interp* interp, RerrMsg& emsg)
44{
45 if (fpObj) {
46 emsg.Init("RtclSignalAction::Init", "already initialized");
47 return false;
48 }
49
50 try {
51 fpObj = new RtclSignalAction(interp);
52 } catch (exception& e) {
53 emsg.Init("RtclSignalAction::Init", string("exception: ")+e.what());
54 return false;
55 }
56
57 Tcl_CreateExitHandler(reinterpret_cast<Tcl_ExitProc*>(ThunkTclExitProc),
58 reinterpret_cast<ClientData>(fpObj));
59
60 return true;
61}
62
63//------------------------------------------+-----------------------------------
65
67{
68 return fpObj;
69}
70
71
72//------------------------------------------+-----------------------------------
74
75bool RtclSignalAction::SetAction(int signum, Tcl_Obj* pobj, RerrMsg& emsg)
76{
77 if (!ValidSignal(signum, emsg)) return false;
78 if (fActionSet[signum] && !ClearAction(signum, emsg)) return false;
79
80 struct sigaction sigact = {};
81 sigact.sa_handler = SignalHandler;
82
83 if (::sigaction(signum, &sigact, &fOldAction[signum]) != 0) {
84 emsg.InitErrno("RtclSignalAction::SetAction",
85 "sigaction() failed: ", errno);
86 return false;
87 }
88
89 fpScript[signum] = pobj;
90 fActionSet[signum] = true;
91 return true;
92}
93
94//------------------------------------------+-----------------------------------
96
97bool RtclSignalAction::GetAction(int signum, Tcl_Obj*& pobj, RerrMsg& emsg)
98{
99 if (!ValidSignal(signum, emsg)) return false;
100 if (!fActionSet[signum]) {
101 emsg.Init("RtclSignalAction::GetAction", "no action for signal");
102 return false;
103 }
104
105 pobj = fpScript[signum];
106 return true;
107}
108
109//------------------------------------------+-----------------------------------
111
113{
114 if (!ValidSignal(signum, emsg)) return false;
115 if (!fActionSet[signum]) {
116 emsg.Init("RtclSignalAction::ClearAction", "no action for signal");
117 return false;
118 }
119
120 if (::sigaction(signum, &fOldAction[signum], nullptr) != 0) {
121 emsg.InitErrno("RtclSignalAction::ClearAction",
122 "sigaction() failed: ", errno);
123 return false;
124 }
125 fpScript[signum] = nullptr;
126 fActionSet[signum] = false;
127 return true;
128}
129
130//------------------------------------------+-----------------------------------
132
134{
135 if (signum > 0 && signum < 32) {
136 switch (signum) {
137 case SIGHUP:
138 case SIGINT:
139 case SIGTERM:
140 case SIGUSR1:
141 case SIGUSR2:
142 return true;
143 default:
144 break;
145 }
146 }
147 emsg.Init("RtclSignalAction::ValidSignal", "unsupported signal");
148 return false;
149}
150
151//------------------------------------------+-----------------------------------
153
155{
156 char signum;
157 Tcl_Read(fShuttleChn, reinterpret_cast<char*>(&signum), sizeof(signum));
158 // FIXME_code: handle return code
159
160 Tcl_SetVar2Ex(fpInterp, "Rutil_signum", nullptr,
161 Tcl_NewIntObj(int(signum)), 0);
162 // FIXME_code: handle return code
163
164 if (!!fpScript[int(signum)]) {
165 Tcl_EvalObjEx(fpInterp, fpScript[int(signum)], TCL_EVAL_GLOBAL);
166 // FIXME_code: handle return code
167 }
168
169 return;
170}
171
172//------------------------------------------+-----------------------------------
174
176{
177 if (fpObj && fpObj->fFdPipeWrite>0) {
178 char signum_c = signum;
179 int irc = ::write(fpObj->fFdPipeWrite, &signum_c, sizeof(signum_c));
180 if (irc < 0)
181 cerr << "RtclSignalAction::SignalHandler-E: write() failed, errno="
182 << errno << endl;
183 } else {
184 cerr << "RtclSignalAction::SignalHandler-E: spurious call" << endl;
185 }
186 return;
187}
188
189//------------------------------------------+-----------------------------------
191
192void RtclSignalAction::ThunkTclChannelHandler(ClientData /*cdata*/, int mask)
193{
194 if (fpObj) fpObj->TclChannelHandler(mask);
195 return;
196}
197
198//------------------------------------------+-----------------------------------
200
201void RtclSignalAction::ThunkTclExitProc(ClientData /*cdata*/)
202{
203 delete fpObj;
204 fpObj = nullptr;
205 return;
206}
207
208//------------------------------------------+-----------------------------------
210
212 : fpInterp(interp),
213 fFdPipeRead(-1),
214 fFdPipeWrite(-1),
215 fShuttleChn(),
216 fActionSet{},
217 fpScript{},
218 fOldAction{}
219{
220 int pipefd[2];
221 if (::pipe(pipefd) < 0)
222 throw Rexception("RtclSignalAction::<ctor>", "pipe() failed: ", errno);
223
224 fFdPipeRead = pipefd[0];
225 fFdPipeWrite = pipefd[1];
226
227 // cast first to ptrdiff_t to promote to proper int size
228 fShuttleChn = Tcl_MakeFileChannel(reinterpret_cast<ClientData>(fFdPipeRead),
229 TCL_READABLE);
230
231 Tcl_SetChannelOption(nullptr, fShuttleChn, "-buffersize", "64");
232 Tcl_SetChannelOption(nullptr, fShuttleChn, "-encoding", "binary");
233 Tcl_SetChannelOption(nullptr, fShuttleChn, "-translation", "binary");
234
235 Tcl_CreateChannelHandler(fShuttleChn, TCL_READABLE,
236 reinterpret_cast<Tcl_FileProc*>(ThunkTclChannelHandler),
237 reinterpret_cast<ClientData>(this));
238}
239
240//------------------------------------------+-----------------------------------
242
244{
245 for (size_t i=0; i<32; i++) {
246 RerrMsg emsg;
247 if (fActionSet[i]) ClearAction(i, emsg);
248 }
249}
250
251
252} // end namespace Retro
FIXME_docs.
Definition: RerrMsg.hpp:25
void Init(const std::string &meth, const std::string &text)
FIXME_docs.
Definition: RerrMsg.cpp:74
void InitErrno(const std::string &meth, const std::string &text, int errnum)
FIXME_docs.
Definition: RerrMsg.cpp:84
FIXME_docs.
Definition: Rexception.hpp:29
static void ThunkTclChannelHandler(ClientData cdata, int mask)
FIXME_docs.
bool SetAction(int signum, Tcl_Obj *pobj, RerrMsg &emsg)
FIXME_docs.
void TclChannelHandler(int mask)
FIXME_docs.
struct sigaction fOldAction[32]
original sigaction
static RtclSignalAction * fpObj
pointer to singleton
static bool Init(Tcl_Interp *interp, RerrMsg &emsg)
FIXME_docs.
static RtclSignalAction * Obj()
FIXME_docs.
RtclSignalAction(Tcl_Interp *interp)
constructor
bool fActionSet[32]
true if SetAction() done
int fFdPipeWrite
attn pipe write fd
bool ClearAction(int signum, RerrMsg &emsg)
FIXME_docs.
static void ThunkTclExitProc(ClientData cdata)
FIXME_docs.
Tcl_Channel fShuttleChn
Tcl channel.
bool GetAction(int signum, Tcl_Obj *&pobj, RerrMsg &emsg)
FIXME_docs.
bool ValidSignal(int signum, RerrMsg &emsg)
FIXME_docs.
Tcl_Interp * fpInterp
Tcl interpreter used.
int fFdPipeRead
attn pipe read fd
RtclOPtr fpScript[32]
action scripts
static void SignalHandler(int signum)
FIXME_docs.
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47