// This handler is registered once for each UnixSignal object. A pipe is maintained // for each one; Wait users read at one end of this pipe, and default_handler sends // a write on the pipe for each signal received while the Wait is ongoing. // // Notice a fairly unlikely race condition exists here: Because we synchronize with // pipe teardown, but not install/uninstall (in other words, we are only trying to // protect against writing on a closed pipe) it is technically possible a full // uninstall and then an install could complete after signum is checked but before // the remaining instructions execute. In this unlikely case count could be // incremented or a byte written on the wrong signal handler. static void default_handler (int signum) { int i; for (i = 0; i < NUM_SIGNALS; ++i) { int fd; signal_info* h = &signals [i]; if (mph_int_get (&h->signum) != signum) continue; mph_int_inc (&h->count); if (!acquire_pipelock_handler (&h->pipelock)) continue; // Teardown is occurring on this object, no one to send to. fd = mph_int_get (&h->write_fd); if (fd > 0) { // If any listener exists to write to int j,pipecounter; char c = signum; // (Value is meaningless) pipecounter = mph_int_get (&h->pipecnt); // Write one byte per pipe listener for (j = 0; j < pipecounter; ++j) { int r; do { r = write (fd, &c, 1); } while (keep_trying (r)); } } release_pipelock_handler (&h->pipelock); } }
// Given pipes set up, wait for a byte to arrive on one of them static int wait_for_any (signal_info** signals, int count, int *currfd, struct pollfd* fd_structs, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down) { int r, idx; // Poll until one of this signal_info's pipes is ready to read. // Once a second, stop to check if the VM is shutting down. do { struct timeval tv; struct timeval *ptv = NULL; if (timeout != -1) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000)*1000; ptv = &tv; } r = poll (fd_structs, count, timeout); } while (keep_trying (r) && !shutting_down ()); idx = -1; if (r == 0) idx = timeout; else if (r > 0) { // The pipe[s] are ready to read. int i; for (i = 0; i < count; ++i) { signal_info* h = signals [i]; if (fd_structs[i].revents & POLLIN) { int r; char c; do { r = read (mph_int_get (&h->read_fd), &c, 1); } while (keep_trying (r) && !shutting_down ()); if (idx == -1) idx = i; } } } return idx; }
static int wait_for_any (signal_info** signals, int count, int *currfd, struct pollfd* fd_structs, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down) { int r, idx; do { struct timeval tv; struct timeval *ptv = NULL; if (timeout != -1) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000)*1000; ptv = &tv; } r = poll (fd_structs, count, timeout); } while (keep_trying (r) && !shutting_down ()); idx = -1; if (r == 0) idx = timeout; else if (r > 0) { int i; for (i = 0; i < count; ++i) { signal_info* h = signals [i]; if (fd_structs[i].revents & POLLIN) { int r; char c; do { r = read (h->read_fd, &c, 1); } while (keep_trying (r) && !shutting_down ()); if (idx == -1) idx = i; } } } return idx; }
static void default_handler (int signum) { int i; for (i = 0; i < NUM_SIGNALS; ++i) { int fd; signal_info* h = &signals [i]; if (mph_int_get (&h->signum) != signum) continue; mph_int_inc (&h->count); fd = mph_int_get (&h->write_fd); if (fd > 0) { int j,pipecounter; char c = signum; pipecounter = mph_int_get (&h->pipecnt); for (j = 0; j < pipecounter; ++j) { int r; do { r = write (fd, &c, 1); } while (keep_trying (r)); } } } }