+/*
+ * Use of pthread_atfork depends on glibc 2.24 to eliminate hangs when
+ * waiting for the agent thread if the agent thread calls malloc. This
+ * is corrected by GNU libc
+ * commit 8a727af925be63aa6ea0f5f90e16751fd541626b.
+ * Ref. https://bugzilla.redhat.com/show_bug.cgi?id=906468
+ */
+static
+void side_before_fork(void)
+{
+ int attempt = 0;
+
+ pthread_mutex_lock(&side_agent_thread_lock);
+ if (!statedump_agent_thread.ref)
+ return;
+ /* Pause agent thread. */
+ pthread_mutex_lock(&side_statedump_lock);
+ (void)__atomic_or_fetch(&statedump_agent_thread.state, AGENT_THREAD_STATE_PAUSE, __ATOMIC_SEQ_CST);
+ pthread_cond_broadcast(&statedump_agent_thread.worker_cond);
+ pthread_mutex_unlock(&side_statedump_lock);
+ /* Wait for agent thread acknowledge. */
+ while (!(__atomic_load_n(&statedump_agent_thread.state, __ATOMIC_SEQ_CST) & AGENT_THREAD_STATE_PAUSE_ACK)) {
+ if (attempt > SIDE_RETRY_BUSY_LOOP_ATTEMPTS) {
+ (void)poll(NULL, 0, SIDE_RETRY_DELAY_MS);
+ continue;
+ }
+ attempt++;
+ side_cpu_relax();
+ }
+}
+
+static
+void side_after_fork_parent(void)
+{
+ if (statedump_agent_thread.ref)
+ (void)__atomic_and_fetch(&statedump_agent_thread.state,
+ ~(AGENT_THREAD_STATE_PAUSE | AGENT_THREAD_STATE_PAUSE_ACK),
+ __ATOMIC_SEQ_CST);
+ pthread_mutex_unlock(&side_agent_thread_lock);
+}
+
+/*
+ * The agent thread does not exist in the child process after a fork.
+ * Re-initialize its data structures and create a new agent thread.
+ */
+static
+void side_after_fork_child(void)
+{
+ if (statedump_agent_thread.ref) {
+ int ret;
+
+ statedump_agent_thread_fini();
+ statedump_agent_thread_init();
+ ret = pthread_create(&statedump_agent_thread.id, NULL,
+ statedump_agent_func, NULL);
+ if (ret) {
+ abort();
+ }
+ }
+ pthread_mutex_unlock(&side_agent_thread_lock);
+}
+