gitweb rectification
[adesklets.git] / scripting / python / posix_signal.c
blob620248f63acefe68ae78f9027f64d1df04c133c4
1 /*--- posix_signal.c -----------------------------------------------------------
2 This is nothing but a forward port from older python code by Lance Ellinghaus,
3 Guido van Rossum & al., reformatted and put back together by Sylvain Fourmanoit <syfou@users.sourceforge.net>
4 for recent (2.2.0 final and newer) python implementations.
6 The ability to temporarily delay signals delivery is a very usefull feature -
7 not all C functions are reentrant (in fact, only a few need to be 'safe'
8 according to the POSIX 1003.1-2003 list), so being able to create critical
9 code sections is a must. Although I am convinced Python's developpers
10 had good reasons, I do not know myself why 'sigprocmask' and associated
11 functions support was dropped from the signal module on systems which
12 implemented them... Since I needed them in my blissful ignorance,
13 here they are, alive and kicking. :-)
15 ------------------------------------------------------------------------------*/
16 #include <Python.h>
18 #include <signal.h>
20 #include "config.h"
22 #ifdef HAVE_SIGPROCMASK
23 static int
24 _posix_signal_list_to_sigset(PyObject* seq, sigset_t* set, char* mesg)
26 int i, len, val;
28 seq = PySequence_Fast(seq, mesg);
29 if (!seq)
30 return -1;
32 len = PySequence_Fast_GET_SIZE(seq);
34 sigemptyset(set);
36 for (i = 0; i < len; i++) {
37 val = PyInt_AsLong(PySequence_Fast_GET_ITEM(seq, i));
38 if (val == -1 && PyErr_Occurred()) {
39 Py_DECREF(seq);
40 return -1;
42 if (sigaddset(set, val) < 0) {
43 Py_DECREF(seq);
44 PyErr_SetFromErrno(PyExc_ValueError);
45 return -1;
49 Py_DECREF(seq);
50 return 0;
53 static PyObject*
54 _posix_signal_sigset_to_list(sigset_t* set)
56 PyObject* ret;
57 PyObject* ob;
58 int i;
60 ret = PyList_New(0);
61 if (!ret)
62 return NULL;
64 for (i = 1; i < NSIG; i++) {
65 if (sigismember(set, i)) {
66 ob = PyInt_FromLong(i);
67 if (!ob) {
68 Py_DECREF(ret);
69 return NULL;
71 PyList_Append(ret, ob);
72 Py_DECREF(ob);
76 return ret;
79 static PyObject*
80 posix_signal_sigprocmask(PyObject* self, PyObject* args)
82 int how;
83 sigset_t newset, oldset;
84 PyObject* seq;
86 if (!PyArg_ParseTuple(args, "iO", &how, &seq))
87 return NULL;
89 if (_posix_signal_list_to_sigset(seq, &newset,
90 "sigprocmask requires a sequence") < 0)
91 return NULL;
93 if (sigprocmask(how, &newset, &oldset) < 0) {
94 return PyErr_SetFromErrno(PyExc_ValueError);
97 if (PyErr_CheckSignals())
98 return NULL;
100 return _posix_signal_sigset_to_list(&oldset);
103 PyDoc_STRVAR(sigprocmask_doc,
104 "sigprocmask(how, sigset) -> sigset\n\
106 Change the list of currently blocked signals. The parameter how should be\n\
107 one of SIG_BLOCK, SIG_UNBLOCK or SIG_SETMASK and sigset should be a\n\
108 sequence of signal numbers. The behaviour of the call depends on the value\n\
109 of how:\n\
111 SIG_BLOCK\n\
112 The set of blocked signals is the union of the current set and the\n\
113 sigset argument.\n\
114 SIG_UNBLOCK\n\
115 The signals in sigset are removed from the current set of blocked\n\
116 signals. It is legal to attempt to unblock a signal which is not\n\
117 blocked.\n\
118 SIG_SETMASK\n\
119 The set of blocked signals is set to the argument set.\n\
121 A list contating the numbers of the previously blocked signals is returned.");
123 static PyObject*
124 posix_signal_sigpending(PyObject* self)
126 sigset_t set;
128 if (sigpending(&set) < 0) {
129 return PyErr_SetFromErrno(PyExc_ValueError);
132 return _posix_signal_sigset_to_list(&set);
135 PyDoc_STRVAR(sigpending_doc,
136 "sigpending() -> sigset\n\
138 Return the set of pending signals, i.e. a list containing the numbers of\n\
139 those signals that have been raised while blocked.");
141 static PyObject*
142 posix_signal_sigsuspend(PyObject* self, PyObject* arg)
144 sigset_t set;
146 if (_posix_signal_list_to_sigset(arg, &set,
147 "sigsuspend requires a sequence") < 0)
148 return NULL;
150 Py_BEGIN_ALLOW_THREADS
151 sigsuspend(&set);
152 Py_END_ALLOW_THREADS
154 if (PyErr_CheckSignals())
155 return NULL;
157 Py_INCREF(Py_None);
158 return Py_None;
161 PyDoc_STRVAR(sigsuspend_doc,
162 "sigsuspend(sigset) -> None\n\
164 Temporarily replace the signal mask with sigset (which should be a sequence\n\
165 of signal numbers) and suspend the process until a signal is received.");
167 #endif
169 #ifdef HAVE_SIGPROCMASK
170 PyDoc_STRVAR(module_doc,
171 "This module supersets the core signal module to enable POSIX signal functions\n\
172 on platforms supporting them. Core `signal' module functions and constants\n\
173 are imported verbatim in posix_signal namespace.\n\
175 Functions:\n\
177 sigprocmask() -- Change the list of currently blocked signals\n\
178 sigpending() -- Allow the examination of pending signals\n\
179 sigsuspend() -- Temporarily replace the signal mask and then suspend\n\
180 the process until a signal is received\n\
182 Constants:\n\
184 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK -- See sigprocmask help below\n\
186 --- signal module documentation ----\n\
189 #else
190 PyDoc_STRVAR(module_doc,
191 "This module supersets the core signal module to enable POSIX signal functions\n\
192 on platforms supporting them. Core `signal' module functions and constants\n\
193 are imported verbatim in posix_signal namespace.\n\
195 WARNING: support for reliable POSIX signals was not detected on your system,\n\
196 and therefore not compiled in. In that state of affair, this module is only \n\
197 a placeholder for your core signal module.\n\
199 --- signal module documentation ----\n\
200 \n" );
201 #endif
203 /* List of functions defined in the module */
204 static PyMethodDef posix_signal_methods[] = {
205 #ifdef HAVE_SIGPROCMASK
206 {"sigprocmask", posix_signal_sigprocmask, METH_VARARGS, sigprocmask_doc},
207 {"sigpending", (PyCFunction)posix_signal_sigpending, METH_VARARGS, sigpending_doc},
208 {"sigsuspend", posix_signal_sigsuspend, METH_VARARGS, sigsuspend_doc},
209 #endif
210 { NULL, NULL, 0, NULL }
213 PyMODINIT_FUNC
214 initposix_signal(void)
216 const char * KEYS [] = { "__doc__", "__name__" , NULL};
217 int i, pos=0;
218 char * key_str, * doc_str , * new_str;
219 PyObject * m, * mDoc, *d,
220 * pName, * pModule, * pDict,
221 * key, * value, *x;
223 m = Py_InitModule3("posix_signal", posix_signal_methods, module_doc);
224 d = PyModule_GetDict(m);
226 x = PyInt_FromLong(SIG_BLOCK);
227 PyDict_SetItemString(d, "SIG_BLOCK", x);
228 Py_XDECREF(x);
229 x = PyInt_FromLong(SIG_UNBLOCK);
230 PyDict_SetItemString(d, "SIG_UNBLOCK", x);
231 Py_XDECREF(x);
232 x = PyInt_FromLong(SIG_SETMASK);
233 PyDict_SetItemString(d, "SIG_SETMASK", x);
234 Py_XDECREF(x);
236 /* The chunk of code below roughly perfoms python equivalent of:
237 'from signal import *' inside what would be a pure python posix_signal
238 module ... */
239 pName=PyString_FromString("signal");
240 if ((pModule=PyImport_Import((pName=PyString_FromString("signal"))))) {
241 pDict=PyModule_GetDict(pModule);
242 while (PyDict_Next(pDict, &pos, &key, &value))
243 /* Import all values from keys that are strings */
244 if (PyString_Check(key)) {
245 key_str=PyString_AsString(key);
246 for(i=0;KEYS[i];++i)
247 if (strncmp(key_str,KEYS[i],strlen(KEYS[i]))==0)
248 break;
249 if (!KEYS[i])
250 /* This needs python 2.2 and up */
251 PyModule_AddObject(m,key_str,value);
252 else {
253 if (i==0) {
254 /* Append signal module documentation */
255 if ((mDoc=PyDict_GetItemString(d,KEYS[0]))) {
256 doc_str=PyString_AsString(mDoc);
257 key_str=PyString_AsString(value);
258 if ((new_str=
259 malloc(sizeof(char)*(strlen(doc_str)+strlen(key_str))+1))) {
260 strcpy(new_str,doc_str);
261 strcat(new_str,key_str);
262 if(PyDict_SetItemString(d,KEYS[0],
263 (mDoc=PyString_FromString(new_str)))<0) {
264 Py_DECREF(mDoc);
266 free(new_str);
273 Py_DECREF(pName);