File: posix_signal.c

package info (click to toggle)
adesklets 0.6.1-4
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 2,044 kB
  • ctags: 1,325
  • sloc: ansic: 5,939; sh: 3,983; python: 2,344; perl: 333; makefile: 211; yacc: 80; lex: 42
file content (274 lines) | stat: -rw-r--r-- 7,580 bytes parent folder | download | duplicates (3)
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);
}