return retval;
}
+static void release_listener_mutex(void *ptr)
+{
+ pthread_mutex_unlock(&listener_thread_data_mutex);
+}
+
static void listener_cleanup(void *ptr)
{
pthread_mutex_lock(&listen_sock_mutex);
for (i = 0; i < nfds; i++) {
pthread_mutex_lock(&listener_thread_data_mutex);
+ pthread_cleanup_push(release_listener_mutex, NULL);
epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
if (epoll_sock == listen_sock) {
addr_size = sizeof(struct sockaddr);
epoll_sock->fd);
}
}
- pthread_mutex_unlock(&listener_thread_data_mutex);
+ pthread_cleanup_pop(1); /* release listener mutex */
}
}
void ust_after_fork_parent(ust_fork_info_t *fork_info)
{
- /* Reenable signals */
+ /* Release mutexes and reenable signals */
ust_after_fork_common(fork_info);
}
/* First sanitize the child */
ust_fork();
- /* Then reenable interrupts */
+ /* Then release mutexes and reenable signals */
ust_after_fork_common(fork_info);
+
+ /*
+ * Make sure we clean up the urcu-bp thread list in the child by running
+ * the garbage collection before any pthread_create can be called.
+ * Failure to do so could lead to a deadlock caused by reuse of a thread
+ * ID before urcu-bp garbage collection is performed.
+ */
+ synchronize_rcu();
}