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