Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / internet / _sigchld.c
1 /*
2  * Copyright (c) 2010 Twisted Matrix Laboratories.
3  * See LICENSE for details.
4  */
5
6 #include <signal.h>
7 #include <errno.h>
8
9 #include "Python.h"
10
11 static int sigchld_pipe_fd = -1;
12
13 static void got_signal(int sig) {
14     int saved_errno = errno;
15     int ignored_result;
16
17     /* write() errors are unhandled.  If the buffer is full, we don't
18      * care.  What about other errors? */
19     ignored_result = write(sigchld_pipe_fd, "x", 1);
20
21     errno = saved_errno;
22 }
23
24 PyDoc_STRVAR(install_sigchld_handler_doc, "\
25 install_sigchld_handler(fd)\n\
26 \n\
27 Installs a SIGCHLD handler which will write a byte to the given fd\n\
28 whenever a SIGCHLD occurs. This is done in C code because the python\n\
29 signal handling system is not reliable, and additionally cannot\n\
30 specify SA_RESTART.\n\
31 \n\
32 Please ensure fd is in non-blocking mode.\n\
33 ");
34
35 static PyObject *
36 install_sigchld_handler(PyObject *self, PyObject *args) {
37     int fd, old_fd;
38     struct sigaction sa;
39
40     if (!PyArg_ParseTuple(args, "i:install_sigchld_handler", &fd)) {
41         return NULL;
42     }
43     old_fd = sigchld_pipe_fd;
44     sigchld_pipe_fd = fd;
45
46     if (fd == -1) {
47         sa.sa_handler = SIG_DFL;
48     } else {
49         sa.sa_handler = got_signal;
50         sa.sa_flags = SA_RESTART;
51         /* mask all signals so I don't worry about EINTR from the write. */
52         sigfillset(&sa.sa_mask);
53     }
54     if (sigaction(SIGCHLD, &sa, 0) != 0) {
55         sigchld_pipe_fd = old_fd;
56         return PyErr_SetFromErrno(PyExc_OSError);
57     }
58     return PyLong_FromLong(old_fd);
59 }
60
61 PyDoc_STRVAR(is_default_handler_doc, "\
62 Return 1 if the SIGCHLD handler is SIG_DFL, 0 otherwise.\n\
63 ");
64
65 static PyObject *
66 is_default_handler(PyObject *self, PyObject *args) {
67     /*
68      * This implementation is necessary since the install_sigchld_handler
69      * function above bypasses the Python signal handler installation API, so
70      * CPython doesn't notice that the handler has changed and signal.getsignal
71      * won't return an accurate result.
72      */
73     struct sigaction sa;
74
75     if (sigaction(SIGCHLD, NULL, &sa) != 0) {
76         return PyErr_SetFromErrno(PyExc_OSError);
77     }
78
79     return PyLong_FromLong(sa.sa_handler == SIG_DFL);
80 }
81
82 static PyMethodDef sigchld_methods[] = {
83     {"installHandler", install_sigchld_handler, METH_VARARGS,
84      install_sigchld_handler_doc},
85     {"isDefaultHandler", is_default_handler, METH_NOARGS,
86      is_default_handler_doc},
87     /* sentinel */
88     {NULL, NULL, 0, NULL}
89 };
90
91
92 static const char _sigchld_doc[] = "\n\
93 This module contains an API for receiving SIGCHLD via a file descriptor.\n\
94 ";
95
96 PyMODINIT_FUNC
97 init_sigchld(void) {
98     /* Create the module and add the functions */
99     Py_InitModule3(
100         "twisted.internet._sigchld", sigchld_methods, _sigchld_doc);
101 }