npy_interrupt.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /* Signal handling:
  2. This header file defines macros that allow your code to handle
  3. interrupts received during processing. Interrupts that
  4. could reasonably be handled:
  5. SIGINT, SIGABRT, SIGALRM, SIGSEGV
  6. ****Warning***************
  7. Do not allow code that creates temporary memory or increases reference
  8. counts of Python objects to be interrupted unless you handle it
  9. differently.
  10. **************************
  11. The mechanism for handling interrupts is conceptually simple:
  12. - replace the signal handler with our own home-grown version
  13. and store the old one.
  14. - run the code to be interrupted -- if an interrupt occurs
  15. the handler should basically just cause a return to the
  16. calling function for finish work.
  17. - restore the old signal handler
  18. Of course, every code that allows interrupts must account for
  19. returning via the interrupt and handle clean-up correctly. But,
  20. even still, the simple paradigm is complicated by at least three
  21. factors.
  22. 1) platform portability (i.e. Microsoft says not to use longjmp
  23. to return from signal handling. They have a __try and __except
  24. extension to C instead but what about mingw?).
  25. 2) how to handle threads: apparently whether signals are delivered to
  26. every thread of the process or the "invoking" thread is platform
  27. dependent. --- we don't handle threads for now.
  28. 3) do we need to worry about re-entrance. For now, assume the
  29. code will not call-back into itself.
  30. Ideas:
  31. 1) Start by implementing an approach that works on platforms that
  32. can use setjmp and longjmp functionality and does nothing
  33. on other platforms.
  34. 2) Ignore threads --- i.e. do not mix interrupt handling and threads
  35. 3) Add a default signal_handler function to the C-API but have the rest
  36. use macros.
  37. Simple Interface:
  38. In your C-extension: around a block of code you want to be interruptable
  39. with a SIGINT
  40. NPY_SIGINT_ON
  41. [code]
  42. NPY_SIGINT_OFF
  43. In order for this to work correctly, the
  44. [code] block must not allocate any memory or alter the reference count of any
  45. Python objects. In other words [code] must be interruptible so that continuation
  46. after NPY_SIGINT_OFF will only be "missing some computations"
  47. Interrupt handling does not work well with threads.
  48. */
  49. /* Add signal handling macros
  50. Make the global variable and signal handler part of the C-API
  51. */
  52. #ifndef NPY_INTERRUPT_H
  53. #define NPY_INTERRUPT_H
  54. #ifndef NPY_NO_SIGNAL
  55. #include <setjmp.h>
  56. #include <signal.h>
  57. #ifndef sigsetjmp
  58. #define NPY_SIGSETJMP(arg1, arg2) setjmp(arg1)
  59. #define NPY_SIGLONGJMP(arg1, arg2) longjmp(arg1, arg2)
  60. #define NPY_SIGJMP_BUF jmp_buf
  61. #else
  62. #define NPY_SIGSETJMP(arg1, arg2) sigsetjmp(arg1, arg2)
  63. #define NPY_SIGLONGJMP(arg1, arg2) siglongjmp(arg1, arg2)
  64. #define NPY_SIGJMP_BUF sigjmp_buf
  65. #endif
  66. # define NPY_SIGINT_ON { \
  67. PyOS_sighandler_t _npy_sig_save; \
  68. _npy_sig_save = PyOS_setsig(SIGINT, _PyArray_SigintHandler); \
  69. if (NPY_SIGSETJMP(*((NPY_SIGJMP_BUF *)_PyArray_GetSigintBuf()), \
  70. 1) == 0) { \
  71. # define NPY_SIGINT_OFF } \
  72. PyOS_setsig(SIGINT, _npy_sig_save); \
  73. }
  74. #else /* NPY_NO_SIGNAL */
  75. #define NPY_SIGINT_ON
  76. #define NPY_SIGINT_OFF
  77. #endif /* HAVE_SIGSETJMP */
  78. #endif /* NPY_INTERRUPT_H */