Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 52 additions & 24 deletions libuv_reactor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,12 @@ static bool libuv_timer_start(zend_async_event_t *event)
return false;
}

// Hidden means "keeps firing, but is not a reason to stay alive": unref drops
// the timer out of uv_loop_alive() without stopping it.
if (ZEND_ASYNC_EVENT_IS_HIDDEN(event)) {
uv_unref((uv_handle_t *) &timer->uv_handle);
}

event->loop_ref_count++;
ZEND_ASYNC_INCREASE_EVENT_COUNT(event);
return true;
Expand Down Expand Up @@ -1655,6 +1661,8 @@ static void libuv_handle_process_events(void)
ZEND_ASYNC_CALLBACKS_NOTIFY(event, NULL, NULL);
// Process event will be removed when stopped
}
// ECHILD is not settled here: a notified event outlives this sweep, so a
// second sweep would overwrite its exit code with a made-up one.
#endif
}

Expand Down Expand Up @@ -1694,44 +1702,63 @@ static void libuv_add_process_event(zend_async_event_t *event)

/* }}} */

/* {{{ libuv_remove_process_event */
static void libuv_remove_process_event(zend_async_event_t *event)
/* {{{ libuv_release_process_watch
* Drops the SIGCHLD handler once the last process event is gone. Call from every
* path that empties the table. */
static void libuv_release_process_watch(void)
{
if (ASYNC_G(process_events) == NULL) {
if (ASYNC_G(process_events) == NULL || zend_hash_num_elements(ASYNC_G(process_events)) > 0) {
return;
}

// Get process handle from event to use as key
async_process_event_t *process_event = (async_process_event_t *) event;

zend_hash_index_del(ASYNC_G(process_events), (uintptr_t) process_event->event.process);
bool has_sigchld_signal_events = false;

// Only remove SIGCHLD handler if no more process events AND no regular signal events for SIGCHLD
if (zend_hash_num_elements(ASYNC_G(process_events)) == 0) {
bool has_sigchld_signal_events = false;

// Check if there are regular signal events for SIGCHLD
if (ASYNC_G(signal_events) != NULL) {
HashTable *sigchld_events = zend_hash_index_find_ptr(ASYNC_G(signal_events), SIGCHLD);
if (sigchld_events != NULL && zend_hash_num_elements(sigchld_events) > 0) {
has_sigchld_signal_events = true;
}
// Check if there are regular signal events for SIGCHLD
if (ASYNC_G(signal_events) != NULL) {
HashTable *sigchld_events = zend_hash_index_find_ptr(ASYNC_G(signal_events), SIGCHLD);
if (sigchld_events != NULL && zend_hash_num_elements(sigchld_events) > 0) {
has_sigchld_signal_events = true;
}
}

// Only remove handler if no signal events exist for SIGCHLD
if (!has_sigchld_signal_events && ASYNC_G(signal_handlers) != NULL) {
uv_signal_t *handler = zend_hash_index_find_ptr(ASYNC_G(signal_handlers), SIGCHLD);
if (handler != NULL) {
// Only remove handler if no signal events exist for SIGCHLD
if (!has_sigchld_signal_events && ASYNC_G(signal_handlers) != NULL) {
uv_signal_t *handler = zend_hash_index_find_ptr(ASYNC_G(signal_handlers), SIGCHLD);
if (handler != NULL) {
if ((bool) (uintptr_t) handler->data) {
// pcntl still needs delivery; closing reverts the OS disposition.
uv_unref((uv_handle_t *) handler);
} else {
uv_signal_stop(handler);
#ifdef ZEND_SIGNALS
libuv_restore_signal_handler(SIGCHLD);
#endif
uv_close((uv_handle_t *) handler, libuv_signal_close_cb);
zend_hash_index_del(ASYNC_G(signal_handlers), SIGCHLD);
}
}
}

zend_hash_destroy(ASYNC_G(process_events));
pefree(ASYNC_G(process_events), 0);
ASYNC_G(process_events) = NULL;
zend_hash_destroy(ASYNC_G(process_events));
pefree(ASYNC_G(process_events), 0);
ASYNC_G(process_events) = NULL;
}

/* }}} */

/* {{{ libuv_remove_process_event */
static void libuv_remove_process_event(zend_async_event_t *event)
{
if (ASYNC_G(process_events) == NULL) {
return;
}

// Get process handle from event to use as key
async_process_event_t *process_event = (async_process_event_t *) event;

zend_hash_index_del(ASYNC_G(process_events), (uintptr_t) process_event->event.process);

libuv_release_process_watch();
}

/* }}} */
Expand Down Expand Up @@ -2170,6 +2197,7 @@ static bool libuv_process_event_dispose(zend_async_event_t *event)
const zend_process_t proc_handle = ((zend_async_process_event_t *) event)->process;
if ((uintptr_t) proc_handle != 0 && ASYNC_G(process_events) != NULL) {
zend_hash_index_del(ASYNC_G(process_events), (zend_ulong) (uintptr_t) proc_handle);
libuv_release_process_watch();
}

#ifdef PHP_WIN32
Expand Down
Loading