From f1fa9ef37b29c3e12b4b5489ec05ad6cd7168175 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 Nov 2016 18:31:28 -0700 Subject: [PATCH 1/2] proccontrol: Synchronize additional threads found during attach When additional threads are found during the attach process, we should synchronize to their stopping point, and check for new threads again, until no new threads are found. This keeps a more consistent state if threads are racing to start while we're attaching. --- proccontrol/src/int_process.h | 2 ++ proccontrol/src/process.C | 58 ++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h index f389175a0a..20a8648a79 100644 --- a/proccontrol/src/int_process.h +++ b/proccontrol/src/int_process.h @@ -271,7 +271,9 @@ class int_process static bool reattach(int_processSet *pset); virtual bool plat_attach(bool allStopped, bool &should_sync) = 0; + bool attachThreads(bool &found_new_threads); bool attachThreads(); + bool attachThreadsSync(); virtual async_ret_t post_attach(bool wasDetached, std::set &aresps); async_ret_t initializeAddressSpace(std::set &async_responses); diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C index 1522a7577e..5df445b520 100644 --- a/proccontrol/src/process.C +++ b/proccontrol/src/process.C @@ -211,8 +211,10 @@ void int_process::plat_threadAttachDone() { } -bool int_process::attachThreads() +bool int_process::attachThreads(bool &found_new_threads) { + found_new_threads = false; + if (!needIndividualThreadAttach()) return true; @@ -224,9 +226,9 @@ bool int_process::attachThreads() * a list of LWPs, but then new threads are created before we attach to * all the existing threads. **/ - bool found_new_threads; + bool loop_new_threads; do { - found_new_threads = false; + loop_new_threads = false; vector lwps; bool result = getThreadLWPs(lwps); if (!result) { @@ -242,13 +244,56 @@ bool int_process::attachThreads() } pthrd_printf("Creating new thread for %d/%d during attach\n", pid, *i); thr = int_thread::createThread(this, NULL_THR_ID, *i, false, int_thread::as_needs_attach); - found_new_threads = true; + found_new_threads = loop_new_threads = true; } - } while (found_new_threads); + } while (loop_new_threads); return true; } +bool int_process::attachThreads() +{ + bool found_new_threads = false; + return attachThreads(found_new_threads); +} + +// Attach any new threads and synchronize, until there are no new threads +bool int_process::attachThreadsSync() +{ + while (true) { + bool found_new_threads = false; + + ProcPool()->condvar()->lock(); + bool result = attachThreads(found_new_threads); + if (found_new_threads) + ProcPool()->condvar()->broadcast(); + ProcPool()->condvar()->unlock(); + + if (!result) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; + } + + if (!found_new_threads) + return true; + + pthrd_printf("Wait again for attach from process %d\n", pid); + bool proc_exited = false; + result = waitAndHandleForProc(true, this, proc_exited); + if (!result) { + perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); + setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n"); + return false; + } + if (proc_exited) { + perr_printf("Process exited while waiting for user thread stop, erroring\n"); + setLastError(err_exited, "Process exited while thread being stopped.\n"); + return false; + } + } +} + bool int_process::attach(int_processSet *ps, bool reattach) { bool had_error = false, should_sync = false; @@ -443,10 +488,9 @@ bool int_process::attach(int_processSet *ps, bool reattach) int_process *proc = *i; if (proc->getState() == errorstate) continue; - bool result = proc->attachThreads(); + bool result = proc->attachThreadsSync(); if (!result) { pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid); - proc->setLastError(err_internal, "Could not get threads during attach\n"); procs.erase(i++); had_error = true; continue; From 897f0c4a7fd30a34f9b711274c9628b3d76f29ea Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Nov 2016 18:13:28 -0800 Subject: [PATCH 2/2] proccontrol: move thread sync to linux_process, and count neonatal --- proccontrol/src/int_process.h | 3 ++- proccontrol/src/linux.C | 38 +++++++++++++++++++++++++++++++ proccontrol/src/linux.h | 1 + proccontrol/src/process.C | 43 ++++++++--------------------------- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/proccontrol/src/int_process.h b/proccontrol/src/int_process.h index 20a8648a79..0c292f297b 100644 --- a/proccontrol/src/int_process.h +++ b/proccontrol/src/int_process.h @@ -273,7 +273,8 @@ class int_process bool attachThreads(bool &found_new_threads); bool attachThreads(); - bool attachThreadsSync(); + virtual bool plat_attachThreadsSync(); + virtual async_ret_t post_attach(bool wasDetached, std::set &aresps); async_ret_t initializeAddressSpace(std::set &async_responses); diff --git a/proccontrol/src/linux.C b/proccontrol/src/linux.C index d701693761..573f1f6032 100644 --- a/proccontrol/src/linux.C +++ b/proccontrol/src/linux.C @@ -1110,6 +1110,44 @@ bool linux_process::plat_attach(bool, bool &) return true; } +// Attach any new threads and synchronize, until there are no new threads +bool linux_process::plat_attachThreadsSync() +{ + while (true) { + bool found_new_threads = false; + + ProcPool()->condvar()->lock(); + bool result = attachThreads(found_new_threads); + if (found_new_threads) + ProcPool()->condvar()->broadcast(); + ProcPool()->condvar()->unlock(); + + if (!result) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; + } + + if (!found_new_threads) + return true; + + while (Counter::processCount(Counter::NeonatalThreads, this) > 0) { + bool proc_exited = false; + pthrd_printf("Waiting for neonatal threads in process %d\n", pid); + result = waitAndHandleForProc(true, this, proc_exited); + if (!result) { + perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); + return false; + } + if (proc_exited) { + perr_printf("Process exited while waiting for user thread stop, erroring\n"); + setLastError(err_exited, "Process exited while thread being stopped.\n"); + return false; + } + } + } +} + bool linux_process::plat_attachWillTriggerStop() { char procName[64]; char cmd[256]; diff --git a/proccontrol/src/linux.h b/proccontrol/src/linux.h index 4972fb7114..56326ad9e6 100644 --- a/proccontrol/src/linux.h +++ b/proccontrol/src/linux.h @@ -111,6 +111,7 @@ class linux_process : public sysv_process, public unix_process, public thread_db virtual bool plat_create(); virtual bool plat_create_int(); virtual bool plat_attach(bool allStopped, bool &); + virtual bool plat_attachThreadsSync(); virtual bool plat_attachWillTriggerStop(); virtual bool plat_forked(); virtual bool plat_execed(); diff --git a/proccontrol/src/process.C b/proccontrol/src/process.C index 5df445b520..90bde49ab8 100644 --- a/proccontrol/src/process.C +++ b/proccontrol/src/process.C @@ -257,41 +257,16 @@ bool int_process::attachThreads() return attachThreads(found_new_threads); } -// Attach any new threads and synchronize, until there are no new threads -bool int_process::attachThreadsSync() +bool int_process::plat_attachThreadsSync() { - while (true) { - bool found_new_threads = false; - - ProcPool()->condvar()->lock(); - bool result = attachThreads(found_new_threads); - if (found_new_threads) - ProcPool()->condvar()->broadcast(); - ProcPool()->condvar()->unlock(); - - if (!result) { - pthrd_printf("Failed to attach to threads in %d\n", pid); - setLastError(err_internal, "Could not get threads during attach\n"); - return false; - } - - if (!found_new_threads) - return true; - - pthrd_printf("Wait again for attach from process %d\n", pid); - bool proc_exited = false; - result = waitAndHandleForProc(true, this, proc_exited); - if (!result) { - perr_printf("Internal error calling waitAndHandleForProc on %d\n", getPid()); - setLastError(err_internal, "Error while calling waitAndHandleForProc for attached threads\n"); - return false; - } - if (proc_exited) { - perr_printf("Process exited while waiting for user thread stop, erroring\n"); - setLastError(err_exited, "Process exited while thread being stopped.\n"); - return false; - } + // By default, platforms just call the idempotent attachThreads(). + // Some platforms may override, e.g. Linux should sync with all threads. + if (!attachThreads()) { + pthrd_printf("Failed to attach to threads in %d\n", pid); + setLastError(err_internal, "Could not get threads during attach\n"); + return false; } + return true; } bool int_process::attach(int_processSet *ps, bool reattach) @@ -488,7 +463,7 @@ bool int_process::attach(int_processSet *ps, bool reattach) int_process *proc = *i; if (proc->getState() == errorstate) continue; - bool result = proc->attachThreadsSync(); + bool result = proc->plat_attachThreadsSync(); if (!result) { pthrd_printf("Failed to attach to threads in %d--now an error\n", proc->pid); procs.erase(i++);