home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / p / python / pytexdoc / ext / source / !Python / Modules / c / signalmodu < prev    next >
Encoding:
Text File  |  1996-11-06  |  12.4 KB  |  507 lines

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