signal.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * <signal.h> wrapper functions.
  3. *
  4. * Authors:
  5. * Jonathan Pryor ([email protected])
  6. * Jonathan Pryor ([email protected])
  7. *
  8. * Copyright (C) 2004-2005 Jonathan Pryor
  9. * Copyright (C) 2008 Novell, Inc.
  10. */
  11. #include <signal.h>
  12. #include "map.h"
  13. #include "mph.h"
  14. #ifndef PLATFORM_WIN32
  15. #include <sys/time.h>
  16. #include <sys/types.h>
  17. #include <unistd.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <pthread.h>
  21. #include <mono/io-layer/atomic.h>
  22. #endif
  23. G_BEGIN_DECLS
  24. typedef void (*mph_sighandler_t)(int);
  25. typedef struct Mono_Unix_UnixSignal_SignalInfo signal_info;
  26. static int count_handlers (int signum);
  27. void*
  28. Mono_Posix_Stdlib_SIG_DFL (void)
  29. {
  30. return SIG_DFL;
  31. }
  32. void*
  33. Mono_Posix_Stdlib_SIG_ERR (void)
  34. {
  35. return SIG_ERR;
  36. }
  37. void*
  38. Mono_Posix_Stdlib_SIG_IGN (void)
  39. {
  40. return SIG_IGN;
  41. }
  42. void
  43. Mono_Posix_Stdlib_InvokeSignalHandler (int signum, void *handler)
  44. {
  45. mph_sighandler_t _h = (mph_sighandler_t) handler;
  46. _h (signum);
  47. }
  48. int Mono_Posix_SIGRTMIN (void)
  49. {
  50. #ifdef SIGRTMIN
  51. return SIGRTMIN;
  52. #else /* def SIGRTMIN */
  53. return -1;
  54. #endif /* ndef SIGRTMIN */
  55. }
  56. int Mono_Posix_SIGRTMAX (void)
  57. {
  58. #ifdef SIGRTMAX
  59. return SIGRTMAX;
  60. #else /* def SIGRTMAX */
  61. return -1;
  62. #endif /* ndef SIGRTMAX */
  63. }
  64. int Mono_Posix_FromRealTimeSignum (int offset, int *r)
  65. {
  66. if (NULL == r) {
  67. errno = EINVAL;
  68. return -1;
  69. }
  70. *r = 0;
  71. #if defined (SIGRTMIN) && defined (SIGRTMAX)
  72. if ((offset < 0) || (SIGRTMIN > SIGRTMAX - offset)) {
  73. errno = EINVAL;
  74. return -1;
  75. }
  76. *r = SIGRTMIN+offset;
  77. return 0;
  78. #else /* defined (SIGRTMIN) && defined (SIGRTMAX) */
  79. # ifdef ENOSYS
  80. errno = ENOSYS;
  81. # endif /* ENOSYS */
  82. return -1;
  83. #endif /* defined (SIGRTMIN) && defined (SIGRTMAX) */
  84. }
  85. #ifndef PLATFORM_WIN32
  86. #ifdef WAPI_ATOMIC_ASM
  87. #define mph_int_get(p) InterlockedExchangeAdd ((p), 0)
  88. #define mph_int_inc(p) InterlockedIncrement ((p))
  89. #define mph_int_set(p,o,n) InterlockedExchange ((p), (n))
  90. #elif GLIB_CHECK_VERSION(2,4,0)
  91. #define mph_int_get(p) g_atomic_int_get ((p))
  92. #define mph_int_inc(p) do {g_atomic_int_inc ((p));} while (0)
  93. #define mph_int_set(p,o,n) do { \
  94. while (!g_atomic_int_compare_and_exchange ((p), (o), (n))) {} \
  95. } while (0)
  96. #else
  97. #define mph_int_get(p) (*(p))
  98. #define mph_int_inc(p) do { (*(p))++; } while (0)
  99. #define mph_int_set(p,o,n) do { *(p) = n; } while (0)
  100. #endif
  101. int
  102. Mono_Posix_Syscall_psignal (int sig, const char* s)
  103. {
  104. errno = 0;
  105. psignal (sig, s);
  106. return errno == 0 ? 0 : -1;
  107. }
  108. #define NUM_SIGNALS 64
  109. static signal_info signals[NUM_SIGNALS];
  110. static void
  111. default_handler (int signum)
  112. {
  113. int i;
  114. for (i = 0; i < NUM_SIGNALS; ++i) {
  115. int fd;
  116. signal_info* h = &signals [i];
  117. if (mph_int_get (&h->signum) != signum)
  118. continue;
  119. mph_int_inc (&h->count);
  120. fd = mph_int_get (&h->write_fd);
  121. if (fd > 0) {
  122. char c = signum;
  123. write (fd, &c, 1);
  124. }
  125. }
  126. }
  127. static pthread_mutex_t signals_mutex = PTHREAD_MUTEX_INITIALIZER;
  128. void*
  129. Mono_Unix_UnixSignal_install (int sig)
  130. {
  131. int i, mr;
  132. signal_info* h = NULL;
  133. int have_handler = 0;
  134. void* handler = NULL;
  135. mr = pthread_mutex_lock (&signals_mutex);
  136. if (mr != 0) {
  137. errno = mr;
  138. return NULL;
  139. }
  140. #if defined (SIGRTMIN) && defined (SIGRTMAX)
  141. /*The runtime uses some rt signals for itself so it's important to not override them.*/
  142. if (sig >= SIGRTMIN && sig <= SIGRTMAX && count_handlers (sig) == 0) {
  143. struct sigaction sinfo;
  144. sigaction (sig, NULL, &sinfo);
  145. if (sinfo.sa_handler != SIG_DFL || (void*)sinfo.sa_sigaction != (void*)SIG_DFL) {
  146. pthread_mutex_unlock (&signals_mutex);
  147. errno = EADDRINUSE;
  148. return NULL;
  149. }
  150. }
  151. #endif /*defined (SIGRTMIN) && defined (SIGRTMAX)*/
  152. for (i = 0; i < NUM_SIGNALS; ++i) {
  153. if (h == NULL && signals [i].signum == 0) {
  154. h = &signals [i];
  155. h->handler = signal (sig, default_handler);
  156. if (h->handler == SIG_ERR) {
  157. h->handler = NULL;
  158. h = NULL;
  159. break;
  160. }
  161. else {
  162. h->have_handler = 1;
  163. }
  164. }
  165. if (!have_handler && signals [i].signum == sig &&
  166. signals [i].handler != default_handler) {
  167. have_handler = 1;
  168. handler = signals [i].handler;
  169. }
  170. if (h && have_handler)
  171. break;
  172. }
  173. if (h && have_handler) {
  174. h->have_handler = 1;
  175. h->handler = handler;
  176. }
  177. if (h) {
  178. mph_int_set (&h->count, h->count, 0);
  179. mph_int_set (&h->signum, h->signum, sig);
  180. }
  181. pthread_mutex_unlock (&signals_mutex);
  182. return h;
  183. }
  184. static int
  185. count_handlers (int signum)
  186. {
  187. int i;
  188. int count = 0;
  189. for (i = 0; i < NUM_SIGNALS; ++i) {
  190. if (signals [i].signum == signum)
  191. ++count;
  192. }
  193. return count;
  194. }
  195. int
  196. Mono_Unix_UnixSignal_uninstall (void* info)
  197. {
  198. signal_info* h;
  199. int mr, r = -1;
  200. mr = pthread_mutex_lock (&signals_mutex);
  201. if (mr != 0) {
  202. errno = mr;
  203. return -1;
  204. }
  205. h = info;
  206. if (h == NULL || h < signals || h > &signals [NUM_SIGNALS])
  207. errno = EINVAL;
  208. else {
  209. /* last UnixSignal -- we can unregister */
  210. if (h->have_handler && count_handlers (h->signum) == 1) {
  211. mph_sighandler_t p = signal (h->signum, h->handler);
  212. if (p != SIG_ERR)
  213. r = 0;
  214. h->handler = NULL;
  215. h->have_handler = 0;
  216. }
  217. h->signum = 0;
  218. }
  219. pthread_mutex_unlock (&signals_mutex);
  220. return r;
  221. }
  222. static int
  223. setup_pipes (signal_info** signals, int count, fd_set *read_fds, int *max_fd)
  224. {
  225. int i, r;
  226. for (i = 0; i < count; ++i) {
  227. signal_info* h;
  228. int filedes[2];
  229. if ((r = pipe (filedes)) != 0) {
  230. break;
  231. }
  232. h = signals [i];
  233. h->read_fd = filedes [0];
  234. h->write_fd = filedes [1];
  235. if (h->read_fd > *max_fd)
  236. *max_fd = h->read_fd;
  237. FD_SET (h->read_fd, read_fds);
  238. }
  239. return r;
  240. }
  241. static void
  242. teardown_pipes (signal_info** signals, int count)
  243. {
  244. int i;
  245. for (i = 0; i < count; ++i) {
  246. signal_info* h = signals [i];
  247. if (h->read_fd != 0)
  248. close (h->read_fd);
  249. if (h->write_fd != 0)
  250. close (h->write_fd);
  251. h->read_fd = 0;
  252. h->write_fd = 0;
  253. }
  254. }
  255. static int
  256. wait_for_any (signal_info** signals, int count, int max_fd, fd_set* read_fds, int timeout)
  257. {
  258. int r, idx;
  259. do {
  260. struct timeval tv;
  261. struct timeval *ptv = NULL;
  262. if (timeout != -1) {
  263. tv.tv_sec = timeout / 1000;
  264. tv.tv_usec = (timeout % 1000)*1000;
  265. ptv = &tv;
  266. }
  267. r = select (max_fd + 1, read_fds, NULL, NULL, ptv);
  268. } while (r == -1 && errno == EINTR);
  269. idx = -1;
  270. if (r == 0)
  271. idx = timeout;
  272. else if (r > 0) {
  273. int i;
  274. for (i = 0; i < count; ++i) {
  275. signal_info* h = signals [i];
  276. if (FD_ISSET (h->read_fd, read_fds)) {
  277. char c;
  278. read (h->read_fd, &c, 1); /* ignore any error */
  279. if (idx == -1)
  280. idx = i;
  281. }
  282. }
  283. }
  284. return idx;
  285. }
  286. /*
  287. * returns: -1 on error:
  288. * timeout on timeout
  289. * index into _signals array of signal that was generated on success
  290. */
  291. int
  292. Mono_Unix_UnixSignal_WaitAny (void** _signals, int count, int timeout /* milliseconds */)
  293. {
  294. fd_set read_fds;
  295. int mr, r;
  296. int max_fd = 0;
  297. signal_info** signals = (signal_info**) _signals;
  298. mr = pthread_mutex_lock (&signals_mutex);
  299. if (mr != 0) {
  300. errno = mr;
  301. return -1;
  302. }
  303. FD_ZERO (&read_fds);
  304. r = setup_pipes (signals, count, &read_fds, &max_fd);
  305. if (r == 0) {
  306. r = wait_for_any (signals, count, max_fd, &read_fds, timeout);
  307. }
  308. teardown_pipes (signals, count);
  309. pthread_mutex_unlock (&signals_mutex);
  310. return r;
  311. }
  312. #endif /* ndef PLATFORM_WIN32 */
  313. G_END_DECLS
  314. /*
  315. * vim: noexpandtab
  316. */