home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Python 1.1 / Modules / signalmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-14  |  11.8 KB  |  466 lines  |  [TEXT/KAHL]

  1. /***********************************************************
  2. Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
  3. Amsterdam, The Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. /* Signal module -- many thanks to Lance Ellinghouse */
  26.  
  27. #include "Python.h"
  28. #include "intrcheck.h"
  29.  
  30. #include <signal.h>
  31. #include <errno.h>
  32.  
  33. #ifndef SIG_ERR
  34. #define SIG_ERR ((RETSIGTYPE (*)())-1)
  35. #endif
  36.  
  37. /*
  38.    NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS
  39.  
  40.    When threads are supported, we want the following semantics:
  41.  
  42.    - only the main thread can set a signal handler
  43.    - any thread can get a signal handler
  44.    - signals are only delivered to the main thread
  45.  
  46.    I.e. we don't support "synchronous signals" like SIGFPE (catching
  47.    this doesn't make much sense in Python anyway) nor do we support
  48.    signals as a means of inter-thread communication, since not all
  49.    thread implementations support that (at least our thread library
  50.    doesn't).
  51.  
  52.    We still have the problem that in some implementations signals
  53.    generated by the keyboard (e.g. SIGINT) are delivered to all
  54.    threads (e.g. SGI), while in others (e.g. Solaris) such signals are
  55.    delivered to one random thread (an intermediate possibility would
  56.    be to deliver it to the main thread -- POSIX???).  For now, we have
  57.    a working implementation that works in all three cases -- the
  58.    handler ignores signals if getpid() isn't the same as in the main
  59.    thread.  XXX This is a hack.
  60.  
  61. */
  62.  
  63. #ifdef WITH_THREAD
  64. #include "thread.h"
  65. static long main_thread;
  66. static pid_t main_pid;
  67. #endif
  68.  
  69. struct PySignal_SignalArrayStruct {
  70.     int    tripped;
  71.     PyObject *func;
  72. };
  73.  
  74. static struct PySignal_SignalArrayStruct PySignal_SignalHandlerArray[NSIG];
  75. static int PySignal_IsTripped = 0; /* Speed up sigcheck() when none tripped */
  76.  
  77. static PyObject *PySignal_SignalDefaultHandler;
  78. static PyObject *PySignal_SignalIgnoreHandler;
  79. static PyObject *PySignal_DefaultIntHandler;
  80.  
  81. static PyObject *
  82. PySignal_CDefaultIntHandler(self, arg)
  83.     PyObject *self;
  84.     PyObject *arg;
  85. {
  86.     PyErr_SetNone(PyExc_KeyboardInterrupt);
  87.     return (PyObject *)NULL;
  88. }
  89.  
  90. static RETSIGTYPE
  91. PySignal_Handler(sig_num)
  92.     int sig_num;
  93. {
  94. #ifdef WITH_THREAD
  95.     /* See NOTES section above */
  96.     if (getpid() == main_pid) {
  97. #endif
  98.         PySignal_IsTripped++;
  99.         PySignal_SignalHandlerArray[sig_num].tripped = 1;
  100. #ifdef WITH_THREAD
  101.     }
  102. #endif
  103. #ifdef SIGCHLD
  104.     if (sig_num == SIGCHLD) {
  105.         /* To avoid infinite recursion, this signal remains
  106.            reset until explicit re-instated.
  107.            Don't clear the 'func' field as it is our pointer
  108.            to the Python handler... */
  109.         return;
  110.     }
  111. #endif
  112.     (void *)signal(sig_num, &PySignal_Handler);
  113. }
  114.  
  115.  
  116. static PyObject *
  117. PySignal_Alarm(self, args)
  118.     PyObject *self; /* Not used */
  119.     PyObject *args;
  120. {
  121.     int t;
  122.     int rtn;
  123.     if (!PyArg_Parse(args, "i", &t))
  124.         return (PyObject *)NULL;
  125.     /* alarm() returns the number of seconds remaining */
  126.     return PyInt_FromLong(alarm(t));
  127. }
  128.  
  129. static object *
  130. PySignal_Pause(self, args)
  131.     PyObject *self; /* Not used */
  132.     PyObject *args;
  133. {
  134.     if (!PyArg_NoArgs(args))
  135.         return NULL;
  136.     BGN_SAVE
  137.     pause();
  138.     END_SAVE
  139.     Py_INCREF(Py_None);
  140.     return Py_None;
  141. }
  142.  
  143. static PyObject *
  144. PySignal_Signal(self, args)
  145.     PyObject *self; /* Not used */
  146.     PyObject *args;
  147. {
  148.     PyObject *obj;
  149.     int sig_num;
  150.     PyObject *old_handler;
  151.     RETSIGTYPE (*func)();
  152.     if (!PyArg_Parse(args, "(iO)", &sig_num, &obj))
  153.         return (PyObject *)NULL;
  154. #ifdef WITH_THREAD
  155.     if (get_thread_ident() != main_thread) {
  156.         PyErr_SetString(PyExc_ValueError, "signal only works in main thread");
  157.         return (PyObject *)NULL;
  158.     }
  159. #endif
  160.     if (sig_num < 1 || sig_num >= NSIG) {
  161.         PyErr_SetString(PyExc_ValueError, "signal number out of range");
  162.         return (PyObject *)NULL;
  163.     }
  164.     if (obj == PySignal_SignalIgnoreHandler)
  165.         func = SIG_IGN;
  166.     else if (obj == PySignal_SignalDefaultHandler)
  167.         func = SIG_DFL;
  168.     else if (!PyCFunction_Check(obj) &&
  169.          !PyFunction_Check(obj) &&
  170.          !PyMethod_Check(obj)) {
  171.         PyErr_SetString(PyExc_TypeError,
  172. "signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object");
  173.         return (PyObject *)NULL;
  174.     }
  175.     else
  176.         func = PySignal_Handler;
  177.     if (signal(sig_num, func) == SIG_ERR) {
  178.         PyErr_SetFromErrno(PyExc_RuntimeError);
  179.         return (PyObject *)NULL;
  180.     }
  181.     old_handler = PySignal_SignalHandlerArray[sig_num].func;
  182.     PySignal_SignalHandlerArray[sig_num].tripped = 0;
  183.     Py_INCREF(obj);
  184.     PySignal_SignalHandlerArray[sig_num].func = obj;
  185.     return old_handler;
  186. }
  187.  
  188. static PyObject *
  189. PySignal_GetSignal(self, args)
  190.     PyObject *self; /* Not used */
  191.     PyObject *args;
  192. {
  193.     int sig_num;
  194.     PyObject *old_handler;
  195.     if (!PyArg_Parse(args, "i", &sig_num))
  196.         return (PyObject *)NULL;
  197.     if (sig_num < 1 || sig_num >= NSIG) {
  198.         PyErr_SetString(PyExc_ValueError, "signal number out of range");
  199.         return (PyObject *)NULL;
  200.     }
  201.     old_handler = PySignal_SignalHandlerArray[sig_num].func;
  202.     Py_INCREF(old_handler);
  203.     return old_handler;
  204. }
  205.  
  206.  
  207. /* List of functions defined in the module */
  208.  
  209. static PyMethodDef PySignal_methods[] = {
  210.     {"alarm",    PySignal_Alarm},
  211.     {"signal",    PySignal_Signal},
  212.     {"getsignal",    PySignal_GetSignal},
  213.     {"pause",    PySignal_Pause},
  214.     {NULL,        NULL}        /* sentinel */
  215. };
  216.  
  217. void
  218. initsignal()
  219. {
  220.     PyObject *m, *d, *x;
  221.     PyObject *b_dict;
  222.     int i;
  223.  
  224. #ifdef WITH_THREAD
  225.     main_thread = get_thread_ident();
  226.     main_pid = getpid();
  227. #endif
  228.  
  229.     /* Create the module and add the functions */
  230.     m = Py_InitModule("signal", PySignal_methods);
  231.  
  232.     /* Add some symbolic constants to the module */
  233.     d = PyModule_GetDict(m);
  234.  
  235.     PySignal_SignalDefaultHandler = PyInt_FromLong((long)SIG_DFL);
  236.     PyDict_SetItemString(d, "SIG_DFL", PySignal_SignalDefaultHandler);
  237.     PySignal_SignalIgnoreHandler = PyInt_FromLong((long)SIG_IGN);
  238.     PyDict_SetItemString(d, "SIG_IGN", PySignal_SignalIgnoreHandler);
  239.     PyDict_SetItemString(d, "NSIG", PyInt_FromLong((long)NSIG));
  240.     PySignal_DefaultIntHandler = PyCFunction_New("default_int_handler",
  241.                              PySignal_CDefaultIntHandler,
  242.                              (PyObject *)NULL,
  243.                              0);
  244.     PyDict_SetItemString(d, "default_int_handler", PySignal_DefaultIntHandler);
  245.  
  246.     PySignal_SignalHandlerArray[0].tripped = 0;
  247.     for (i = 1; i < NSIG; i++) {
  248.         RETSIGTYPE (*t)();
  249.         t = signal(i, SIG_IGN);
  250.         signal(i, t);
  251.         PySignal_SignalHandlerArray[i].tripped = 0;
  252.         if (t == SIG_DFL)
  253.             PySignal_SignalHandlerArray[i].func = PySignal_SignalDefaultHandler;
  254.         else if (t == SIG_IGN)
  255.             PySignal_SignalHandlerArray[i].func = PySignal_SignalIgnoreHandler;
  256.         else
  257.             PySignal_SignalHandlerArray[i].func = Py_None; /* None of our business */
  258.         Py_INCREF(PySignal_SignalHandlerArray[i].func);
  259.     }
  260.     if (PySignal_SignalHandlerArray[SIGINT].func == PySignal_SignalDefaultHandler) {
  261.         /* Install default int handler */
  262.         Py_DECREF(PySignal_SignalHandlerArray[SIGINT].func);
  263.         PySignal_SignalHandlerArray[SIGINT].func = PySignal_DefaultIntHandler;
  264.         Py_INCREF(PySignal_DefaultIntHandler);
  265.         signal(SIGINT, &PySignal_Handler);
  266.     }
  267.  
  268. #ifdef SIGHUP
  269.     x = PyInt_FromLong(SIGHUP);
  270.     PyDict_SetItemString(d, "SIGHUP", x);
  271. #endif
  272. #ifdef SIGINT
  273.     x = PyInt_FromLong(SIGINT);
  274.     PyDict_SetItemString(d, "SIGINT", x);
  275. #endif
  276. #ifdef SIGQUIT
  277.     x = PyInt_FromLong(SIGQUIT);
  278.     PyDict_SetItemString(d, "SIGQUIT", x);
  279. #endif
  280. #ifdef SIGILL
  281.     x = PyInt_FromLong(SIGILL);
  282.     PyDict_SetItemString(d, "SIGILL", x);
  283. #endif
  284. #ifdef SIGTRAP
  285.     x = PyInt_FromLong(SIGTRAP);
  286.     PyDict_SetItemString(d, "SIGTRAP", x);
  287. #endif
  288. #ifdef SIGIOT
  289.     x = PyInt_FromLong(SIGIOT);
  290.     PyDict_SetItemString(d, "SIGIOT", x);
  291. #endif
  292. #ifdef SIGABRT
  293.     x = PyInt_FromLong(SIGABRT);
  294.     PyDict_SetItemString(d, "SIGABRT", x);
  295. #endif
  296. #ifdef SIGEMT
  297.     x = PyInt_FromLong(SIGEMT);
  298.     PyDict_SetItemString(d, "SIGEMT", x);
  299. #endif
  300. #ifdef SIGFPE
  301.     x = PyInt_FromLong(SIGFPE);
  302.     PyDict_SetItemString(d, "SIGFPE", x);
  303. #endif
  304. #ifdef SIGKILL
  305.     x = PyInt_FromLong(SIGKILL);
  306.     PyDict_SetItemString(d, "SIGKILL", x);
  307. #endif
  308. #ifdef SIGBUS
  309.     x = PyInt_FromLong(SIGBUS);
  310.     PyDict_SetItemString(d, "SIGBUS", x);
  311. #endif
  312. #ifdef SIGSEGV
  313.     x = PyInt_FromLong(SIGSEGV);
  314.     PyDict_SetItemString(d, "SIGSEGV", x);
  315. #endif
  316. #ifdef SIGSYS
  317.     x = PyInt_FromLong(SIGSYS);
  318.     PyDict_SetItemString(d, "SIGSYS", x);
  319. #endif
  320. #ifdef SIGPIPE
  321.     x = PyInt_FromLong(SIGPIPE);
  322.     PyDict_SetItemString(d, "SIGPIPE", x);
  323. #endif
  324. #ifdef SIGALRM
  325.     x = PyInt_FromLong(SIGALRM);
  326.     PyDict_SetItemString(d, "SIGALRM", x);
  327. #endif
  328. #ifdef SIGTERM
  329.     x = PyInt_FromLong(SIGTERM);
  330.     PyDict_SetItemString(d, "SIGTERM", x);
  331. #endif
  332. #ifdef SIGUSR1
  333.     x = PyInt_FromLong(SIGUSR1);
  334.     PyDict_SetItemString(d, "SIGUSR1", x);
  335. #endif
  336. #ifdef SIGUSR2
  337.     x = PyInt_FromLong(SIGUSR2);
  338.     PyDict_SetItemString(d, "SIGUSR2", x);
  339. #endif
  340. #ifdef SIGCLD
  341.     x = PyInt_FromLong(SIGCLD);
  342.     PyDict_SetItemString(d, "SIGCLD", x);
  343. #endif
  344. #ifdef SIGCHLD
  345.     x = PyInt_FromLong(SIGCHLD);
  346.     PyDict_SetItemString(d, "SIGCHLD", x);
  347. #endif
  348. #ifdef SIGPWR
  349.     x = PyInt_FromLong(SIGPWR);
  350.     PyDict_SetItemString(d, "SIGPWR", x);
  351. #endif
  352. #ifdef SIGIO
  353.     x = PyInt_FromLong(SIGIO);
  354.     PyDict_SetItemString(d, "SIGIO", x);
  355. #endif
  356. #ifdef SIGURG
  357.     x = PyInt_FromLong(SIGURG);
  358.     PyDict_SetItemString(d, "SIGURG", x);
  359. #endif
  360. #ifdef SIGWINCH
  361.     x = PyInt_FromLong(SIGWINCH);
  362.     PyDict_SetItemString(d, "SIGWINCH", x);
  363. #endif
  364. #ifdef SIGPOLL
  365.     x = PyInt_FromLong(SIGPOLL);
  366.     PyDict_SetItemString(d, "SIGPOLL", x);
  367. #endif
  368. #ifdef SIGSTOP
  369.     x = PyInt_FromLong(SIGSTOP);
  370.     PyDict_SetItemString(d, "SIGSTOP", x);
  371. #endif
  372. #ifdef SIGTSTP
  373.     x = PyInt_FromLong(SIGTSTP);
  374.     PyDict_SetItemString(d, "SIGTSTP", x);
  375. #endif
  376. #ifdef SIGCONT
  377.     x = PyInt_FromLong(SIGCONT);
  378.     PyDict_SetItemString(d, "SIGCONT", x);
  379. #endif
  380. #ifdef SIGTTIN
  381.     x = PyInt_FromLong(SIGTTIN);
  382.     PyDict_SetItemString(d, "SIGTTIN", x);
  383. #endif
  384. #ifdef SIGTTOU
  385.     x = PyInt_FromLong(SIGTTOU);
  386.     PyDict_SetItemString(d, "SIGTTOU", x);
  387. #endif
  388. #ifdef SIGVTALRM
  389.     x = PyInt_FromLong(SIGVTALRM);
  390.     PyDict_SetItemString(d, "SIGVTALRM", x);
  391. #endif
  392. #ifdef SIGPROF
  393.     x = PyInt_FromLong(SIGPROF);
  394.     PyDict_SetItemString(d, "SIGPROF", x);
  395. #endif
  396. #ifdef SIGCPU
  397.     x = PyInt_FromLong(SIGCPU);
  398.     PyDict_SetItemString(d, "SIGCPU", x);
  399. #endif
  400. #ifdef SIGFSZ
  401.     x = PyInt_FromLong(SIGFSZ);
  402.     PyDict_SetItemString(d, "SIGFSZ", x);
  403. #endif
  404.     /* Check for errors */
  405.     if (PyErr_Occurred())
  406.         Py_FatalError("can't initialize module signal");
  407. }
  408.  
  409. int
  410. sigcheck()
  411. {
  412.     int i;
  413.     PyObject *f;
  414.     if (!PySignal_IsTripped)
  415.         return 0;
  416. #ifdef WITH_THREAD
  417.     if (get_thread_ident() != main_thread)
  418.         return 0;
  419. #endif
  420.     f = getframe();
  421.     if (f == (PyObject *)NULL)
  422.         f = Py_None;
  423.     for (i = 1; i < NSIG; i++) {
  424.         if (PySignal_SignalHandlerArray[i].tripped) {
  425.             PyObject *arglist, *result;
  426.             PySignal_SignalHandlerArray[i].tripped = 0;
  427.             arglist = Py_BuildValue("(iO)", i, f);
  428.             if (arglist == (PyObject *)NULL)
  429.                 result = (PyObject *)NULL;
  430.             else {
  431.                 result = PyEval_CallObject(PySignal_SignalHandlerArray[i].func,arglist);
  432.                 Py_DECREF(arglist);
  433.             }
  434.             if (result == (PyObject *)NULL) {
  435.                 return 1;
  436.             } else {
  437.                 Py_DECREF(result);
  438.             }
  439.         }
  440.     }
  441.     PySignal_IsTripped = 0;
  442.     return 0;
  443. }
  444.  
  445. /* Replacement for intrcheck.c functionality */
  446.  
  447. void
  448. initintr()
  449. {
  450.     initsignal();
  451. }
  452.  
  453. int
  454. intrcheck()
  455. {
  456.     if (PySignal_SignalHandlerArray[SIGINT].tripped) {
  457. #ifdef WITH_THREAD
  458.         if (get_thread_ident() != main_thread)
  459.             return 0;
  460. #endif
  461.         PySignal_SignalHandlerArray[SIGINT].tripped = 0;
  462.         return 1;
  463.     }
  464.     return 0;
  465. }
  466.