130fdc8d8SChris Lattner //===-- ThreadList.cpp ------------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner #include <stdlib.h> 1030fdc8d8SChris Lattner 1130fdc8d8SChris Lattner #include <algorithm> 1230fdc8d8SChris Lattner 132cad65a5SGreg Clayton #include "lldb/Core/Log.h" 14*29d65744SAndrew Kaylor #include "lldb/Core/State.h" 152cad65a5SGreg Clayton #include "lldb/Target/RegisterContext.h" 1630fdc8d8SChris Lattner #include "lldb/Target/ThreadList.h" 1730fdc8d8SChris Lattner #include "lldb/Target/Thread.h" 1830fdc8d8SChris Lattner #include "lldb/Target/ThreadPlan.h" 1930fdc8d8SChris Lattner #include "lldb/Target/Process.h" 2030fdc8d8SChris Lattner 2130fdc8d8SChris Lattner using namespace lldb; 2230fdc8d8SChris Lattner using namespace lldb_private; 2330fdc8d8SChris Lattner 2430fdc8d8SChris Lattner ThreadList::ThreadList (Process *process) : 2530fdc8d8SChris Lattner m_process (process), 2630fdc8d8SChris Lattner m_stop_id (0), 2730fdc8d8SChris Lattner m_threads(), 282976d00aSJim Ingham m_selected_tid (LLDB_INVALID_THREAD_ID) 2930fdc8d8SChris Lattner { 3030fdc8d8SChris Lattner } 3130fdc8d8SChris Lattner 3230fdc8d8SChris Lattner ThreadList::ThreadList (const ThreadList &rhs) : 33ba4e61d3SAndrew Kaylor m_process (rhs.m_process), 34ba4e61d3SAndrew Kaylor m_stop_id (rhs.m_stop_id), 3530fdc8d8SChris Lattner m_threads (), 362976d00aSJim Ingham m_selected_tid () 3730fdc8d8SChris Lattner { 3830fdc8d8SChris Lattner // Use the assignment operator since it uses the mutex 3930fdc8d8SChris Lattner *this = rhs; 4030fdc8d8SChris Lattner } 4130fdc8d8SChris Lattner 4230fdc8d8SChris Lattner const ThreadList& 4330fdc8d8SChris Lattner ThreadList::operator = (const ThreadList& rhs) 4430fdc8d8SChris Lattner { 4530fdc8d8SChris Lattner if (this != &rhs) 4630fdc8d8SChris Lattner { 4730fdc8d8SChris Lattner // Lock both mutexes to make sure neither side changes anyone on us 4830fdc8d8SChris Lattner // while the assignement occurs 49ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 5030fdc8d8SChris Lattner m_process = rhs.m_process; 5130fdc8d8SChris Lattner m_stop_id = rhs.m_stop_id; 5230fdc8d8SChris Lattner m_threads = rhs.m_threads; 532976d00aSJim Ingham m_selected_tid = rhs.m_selected_tid; 5430fdc8d8SChris Lattner } 5530fdc8d8SChris Lattner return *this; 5630fdc8d8SChris Lattner } 5730fdc8d8SChris Lattner 5830fdc8d8SChris Lattner 5930fdc8d8SChris Lattner ThreadList::~ThreadList() 6030fdc8d8SChris Lattner { 61ac358da5SGreg Clayton // Clear the thread list. Clear will take the mutex lock 62ac358da5SGreg Clayton // which will ensure that if anyone is using the list 63ac358da5SGreg Clayton // they won't get it removed while using it. 64ac358da5SGreg Clayton Clear(); 6530fdc8d8SChris Lattner } 6630fdc8d8SChris Lattner 6730fdc8d8SChris Lattner 6830fdc8d8SChris Lattner uint32_t 6930fdc8d8SChris Lattner ThreadList::GetStopID () const 7030fdc8d8SChris Lattner { 7130fdc8d8SChris Lattner return m_stop_id; 7230fdc8d8SChris Lattner } 7330fdc8d8SChris Lattner 7430fdc8d8SChris Lattner void 7530fdc8d8SChris Lattner ThreadList::SetStopID (uint32_t stop_id) 7630fdc8d8SChris Lattner { 7730fdc8d8SChris Lattner m_stop_id = stop_id; 7830fdc8d8SChris Lattner } 7930fdc8d8SChris Lattner 8030fdc8d8SChris Lattner 8130fdc8d8SChris Lattner void 82c3776bf2SGreg Clayton ThreadList::AddThread (const ThreadSP &thread_sp) 8330fdc8d8SChris Lattner { 84ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 8530fdc8d8SChris Lattner m_threads.push_back(thread_sp); 8630fdc8d8SChris Lattner } 8730fdc8d8SChris Lattner 8830fdc8d8SChris Lattner uint32_t 8930fdc8d8SChris Lattner ThreadList::GetSize (bool can_update) 9030fdc8d8SChris Lattner { 91ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 9230fdc8d8SChris Lattner if (can_update) 9330fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 9430fdc8d8SChris Lattner return m_threads.size(); 9530fdc8d8SChris Lattner } 9630fdc8d8SChris Lattner 9730fdc8d8SChris Lattner ThreadSP 9830fdc8d8SChris Lattner ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update) 9930fdc8d8SChris Lattner { 100ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 10130fdc8d8SChris Lattner if (can_update) 10230fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 10330fdc8d8SChris Lattner 10430fdc8d8SChris Lattner ThreadSP thread_sp; 10530fdc8d8SChris Lattner if (idx < m_threads.size()) 10630fdc8d8SChris Lattner thread_sp = m_threads[idx]; 10730fdc8d8SChris Lattner return thread_sp; 10830fdc8d8SChris Lattner } 10930fdc8d8SChris Lattner 11030fdc8d8SChris Lattner ThreadSP 11130fdc8d8SChris Lattner ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update) 11230fdc8d8SChris Lattner { 113ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 11430fdc8d8SChris Lattner 11530fdc8d8SChris Lattner if (can_update) 11630fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 11730fdc8d8SChris Lattner 11830fdc8d8SChris Lattner ThreadSP thread_sp; 11930fdc8d8SChris Lattner uint32_t idx = 0; 12030fdc8d8SChris Lattner const uint32_t num_threads = m_threads.size(); 12130fdc8d8SChris Lattner for (idx = 0; idx < num_threads; ++idx) 12230fdc8d8SChris Lattner { 12330fdc8d8SChris Lattner if (m_threads[idx]->GetID() == tid) 12430fdc8d8SChris Lattner { 12530fdc8d8SChris Lattner thread_sp = m_threads[idx]; 12630fdc8d8SChris Lattner break; 12730fdc8d8SChris Lattner } 12830fdc8d8SChris Lattner } 12930fdc8d8SChris Lattner return thread_sp; 13030fdc8d8SChris Lattner } 13130fdc8d8SChris Lattner 13230fdc8d8SChris Lattner ThreadSP 133160c9d81SGreg Clayton ThreadList::FindThreadByProtocolID (lldb::tid_t tid, bool can_update) 134160c9d81SGreg Clayton { 135ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 136160c9d81SGreg Clayton 137160c9d81SGreg Clayton if (can_update) 138160c9d81SGreg Clayton m_process->UpdateThreadListIfNeeded(); 139160c9d81SGreg Clayton 140160c9d81SGreg Clayton ThreadSP thread_sp; 141160c9d81SGreg Clayton uint32_t idx = 0; 142160c9d81SGreg Clayton const uint32_t num_threads = m_threads.size(); 143160c9d81SGreg Clayton for (idx = 0; idx < num_threads; ++idx) 144160c9d81SGreg Clayton { 145160c9d81SGreg Clayton if (m_threads[idx]->GetProtocolID() == tid) 146160c9d81SGreg Clayton { 147160c9d81SGreg Clayton thread_sp = m_threads[idx]; 148160c9d81SGreg Clayton break; 149160c9d81SGreg Clayton } 150160c9d81SGreg Clayton } 151160c9d81SGreg Clayton return thread_sp; 152160c9d81SGreg Clayton } 153160c9d81SGreg Clayton 154160c9d81SGreg Clayton 155160c9d81SGreg Clayton ThreadSP 156c2c423eaSHan Ming Ong ThreadList::RemoveThreadByID (lldb::tid_t tid, bool can_update) 157c2c423eaSHan Ming Ong { 158ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 159c2c423eaSHan Ming Ong 160c2c423eaSHan Ming Ong if (can_update) 161c2c423eaSHan Ming Ong m_process->UpdateThreadListIfNeeded(); 162c2c423eaSHan Ming Ong 163c2c423eaSHan Ming Ong ThreadSP thread_sp; 164c2c423eaSHan Ming Ong uint32_t idx = 0; 165c2c423eaSHan Ming Ong const uint32_t num_threads = m_threads.size(); 166c2c423eaSHan Ming Ong for (idx = 0; idx < num_threads; ++idx) 167c2c423eaSHan Ming Ong { 168c2c423eaSHan Ming Ong if (m_threads[idx]->GetID() == tid) 169c2c423eaSHan Ming Ong { 170c2c423eaSHan Ming Ong thread_sp = m_threads[idx]; 171c2c423eaSHan Ming Ong m_threads.erase(m_threads.begin()+idx); 172c2c423eaSHan Ming Ong break; 173c2c423eaSHan Ming Ong } 174c2c423eaSHan Ming Ong } 175c2c423eaSHan Ming Ong return thread_sp; 176c2c423eaSHan Ming Ong } 177c2c423eaSHan Ming Ong 178c2c423eaSHan Ming Ong ThreadSP 179160c9d81SGreg Clayton ThreadList::RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update) 180160c9d81SGreg Clayton { 181ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 182160c9d81SGreg Clayton 183160c9d81SGreg Clayton if (can_update) 184160c9d81SGreg Clayton m_process->UpdateThreadListIfNeeded(); 185160c9d81SGreg Clayton 186160c9d81SGreg Clayton ThreadSP thread_sp; 187160c9d81SGreg Clayton uint32_t idx = 0; 188160c9d81SGreg Clayton const uint32_t num_threads = m_threads.size(); 189160c9d81SGreg Clayton for (idx = 0; idx < num_threads; ++idx) 190160c9d81SGreg Clayton { 191160c9d81SGreg Clayton if (m_threads[idx]->GetProtocolID() == tid) 192160c9d81SGreg Clayton { 193160c9d81SGreg Clayton thread_sp = m_threads[idx]; 194160c9d81SGreg Clayton m_threads.erase(m_threads.begin()+idx); 195160c9d81SGreg Clayton break; 196160c9d81SGreg Clayton } 197160c9d81SGreg Clayton } 198160c9d81SGreg Clayton return thread_sp; 199160c9d81SGreg Clayton } 200160c9d81SGreg Clayton 201160c9d81SGreg Clayton ThreadSP 20230fdc8d8SChris Lattner ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr) 20330fdc8d8SChris Lattner { 20430fdc8d8SChris Lattner ThreadSP thread_sp; 20530fdc8d8SChris Lattner if (thread_ptr) 20630fdc8d8SChris Lattner { 207ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 20830fdc8d8SChris Lattner 20930fdc8d8SChris Lattner uint32_t idx = 0; 21030fdc8d8SChris Lattner const uint32_t num_threads = m_threads.size(); 21130fdc8d8SChris Lattner for (idx = 0; idx < num_threads; ++idx) 21230fdc8d8SChris Lattner { 21330fdc8d8SChris Lattner if (m_threads[idx].get() == thread_ptr) 21430fdc8d8SChris Lattner { 21530fdc8d8SChris Lattner thread_sp = m_threads[idx]; 21630fdc8d8SChris Lattner break; 21730fdc8d8SChris Lattner } 21830fdc8d8SChris Lattner } 21930fdc8d8SChris Lattner } 22030fdc8d8SChris Lattner return thread_sp; 22130fdc8d8SChris Lattner } 22230fdc8d8SChris Lattner 22330fdc8d8SChris Lattner 22430fdc8d8SChris Lattner 22530fdc8d8SChris Lattner ThreadSP 22630fdc8d8SChris Lattner ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update) 22730fdc8d8SChris Lattner { 228ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 22930fdc8d8SChris Lattner 23030fdc8d8SChris Lattner if (can_update) 23130fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 23230fdc8d8SChris Lattner 23330fdc8d8SChris Lattner ThreadSP thread_sp; 23430fdc8d8SChris Lattner const uint32_t num_threads = m_threads.size(); 23530fdc8d8SChris Lattner for (uint32_t idx = 0; idx < num_threads; ++idx) 23630fdc8d8SChris Lattner { 23730fdc8d8SChris Lattner if (m_threads[idx]->GetIndexID() == index_id) 23830fdc8d8SChris Lattner { 23930fdc8d8SChris Lattner thread_sp = m_threads[idx]; 24030fdc8d8SChris Lattner break; 24130fdc8d8SChris Lattner } 24230fdc8d8SChris Lattner } 24330fdc8d8SChris Lattner return thread_sp; 24430fdc8d8SChris Lattner } 24530fdc8d8SChris Lattner 24630fdc8d8SChris Lattner bool 24730fdc8d8SChris Lattner ThreadList::ShouldStop (Event *event_ptr) 24830fdc8d8SChris Lattner { 24930fdc8d8SChris Lattner // Running events should never stop, obviously... 25030fdc8d8SChris Lattner 2515160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 25230fdc8d8SChris Lattner 253b42f3af3SJim Ingham // The ShouldStop method of the threads can do a whole lot of work, 254b42f3af3SJim Ingham // running breakpoint commands & conditions, etc. So we don't want 255b42f3af3SJim Ingham // to keep the ThreadList locked the whole time we are doing this. 256b42f3af3SJim Ingham // FIXME: It is possible that running code could cause new threads 257b42f3af3SJim Ingham // to be created. If that happens we will miss asking them whether 258b42f3af3SJim Ingham // then should stop. This is not a big deal, since we haven't had 259b42f3af3SJim Ingham // a chance to hang any interesting operations on those threads yet. 26030fdc8d8SChris Lattner 261b42f3af3SJim Ingham collection threads_copy; 262b42f3af3SJim Ingham { 263b42f3af3SJim Ingham // Scope for locker 264ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 265b42f3af3SJim Ingham 266b42f3af3SJim Ingham m_process->UpdateThreadListIfNeeded(); 267b42f3af3SJim Ingham threads_copy = m_threads; 268b42f3af3SJim Ingham } 269b42f3af3SJim Ingham 270b42f3af3SJim Ingham collection::iterator pos, end = threads_copy.end(); 27130fdc8d8SChris Lattner 2722cad65a5SGreg Clayton if (log) 27310c4b249SJim Ingham { 27410c4b249SJim Ingham log->PutCString(""); 275d01b2953SDaniel Malea log->Printf ("ThreadList::%s: %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size()); 27610c4b249SJim Ingham } 2772cad65a5SGreg Clayton 278a0079044SJim Ingham bool did_anybody_stop_for_a_reason = false; 279a0079044SJim Ingham bool should_stop = false; 2807bc3465fSJim Ingham 2817bc3465fSJim Ingham // Now we run through all the threads and get their stop info's. We want to make sure to do this first before 2827bc3465fSJim Ingham // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a 2837bc3465fSJim Ingham // thread specific breakpoint another thread had stopped at) which could lead us to compute the StopInfo incorrectly. 2847bc3465fSJim Ingham // We don't need to use it here, we just want to make sure it gets computed. 2857bc3465fSJim Ingham 2867bc3465fSJim Ingham for (pos = threads_copy.begin(); pos != end; ++pos) 2877bc3465fSJim Ingham { 2887bc3465fSJim Ingham ThreadSP thread_sp(*pos); 2897bc3465fSJim Ingham thread_sp->GetStopInfo(); 2907bc3465fSJim Ingham } 291a0079044SJim Ingham 292b42f3af3SJim Ingham for (pos = threads_copy.begin(); pos != end; ++pos) 29330fdc8d8SChris Lattner { 29430fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 2952cad65a5SGreg Clayton 296a0079044SJim Ingham did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); 297a0079044SJim Ingham 29810c4b249SJim Ingham const bool thread_should_stop = thread_sp->ShouldStop(event_ptr); 2992cad65a5SGreg Clayton if (thread_should_stop) 3002cad65a5SGreg Clayton should_stop |= true; 3012cad65a5SGreg Clayton } 3022cad65a5SGreg Clayton 303a0079044SJim Ingham // We should never get a stop for which no thread had a stop reason, but sometimes we do see this - 304a0079044SJim Ingham // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out 305a0079044SJim Ingham // the right thing to do and stopping gives the user control over what to do in this instance. 306a0079044SJim Ingham 307a0079044SJim Ingham if (!should_stop && !did_anybody_stop_for_a_reason) 308a0079044SJim Ingham { 309a0079044SJim Ingham should_stop = true; 310a0079044SJim Ingham if (log) 311a0079044SJim Ingham log->Printf ("ThreadList::%s we stopped but no threads had a stop reason, overriding should_stop and stopping.", __FUNCTION__); 312a0079044SJim Ingham } 313a0079044SJim Ingham 3142cad65a5SGreg Clayton if (log) 31510c4b249SJim Ingham log->Printf ("ThreadList::%s overall should_stop = %i", __FUNCTION__, should_stop); 3162cad65a5SGreg Clayton 31730fdc8d8SChris Lattner if (should_stop) 31830fdc8d8SChris Lattner { 319b42f3af3SJim Ingham for (pos = threads_copy.begin(); pos != end; ++pos) 32030fdc8d8SChris Lattner { 32130fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 32230fdc8d8SChris Lattner thread_sp->WillStop (); 32330fdc8d8SChris Lattner } 32430fdc8d8SChris Lattner } 32530fdc8d8SChris Lattner 32630fdc8d8SChris Lattner return should_stop; 32730fdc8d8SChris Lattner } 32830fdc8d8SChris Lattner 32930fdc8d8SChris Lattner Vote 33030fdc8d8SChris Lattner ThreadList::ShouldReportStop (Event *event_ptr) 33130fdc8d8SChris Lattner { 332ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 3332cad65a5SGreg Clayton 33430fdc8d8SChris Lattner Vote result = eVoteNoOpinion; 33530fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 33630fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 33730fdc8d8SChris Lattner 3385160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 3392cad65a5SGreg Clayton 3402cad65a5SGreg Clayton if (log) 341d01b2953SDaniel Malea log->Printf ("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size()); 3422cad65a5SGreg Clayton 34330fdc8d8SChris Lattner // Run through the threads and ask whether we should report this event. 34430fdc8d8SChris Lattner // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion. 34530fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 34630fdc8d8SChris Lattner { 34730fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 348e0d378b3SGreg Clayton const Vote vote = thread_sp->ShouldReportStop (event_ptr); 3492cad65a5SGreg Clayton switch (vote) 35030fdc8d8SChris Lattner { 35130fdc8d8SChris Lattner case eVoteNoOpinion: 35230fdc8d8SChris Lattner continue; 3532cad65a5SGreg Clayton 35430fdc8d8SChris Lattner case eVoteYes: 35530fdc8d8SChris Lattner result = eVoteYes; 35630fdc8d8SChris Lattner break; 3572cad65a5SGreg Clayton 35830fdc8d8SChris Lattner case eVoteNo: 35930fdc8d8SChris Lattner if (result == eVoteNoOpinion) 3602cad65a5SGreg Clayton { 36130fdc8d8SChris Lattner result = eVoteNo; 3622cad65a5SGreg Clayton } 3632cad65a5SGreg Clayton else 3642cad65a5SGreg Clayton { 3652cad65a5SGreg Clayton if (log) 366d01b2953SDaniel Malea log->Printf ("ThreadList::%s thread 0x%4.4" PRIx64 ": voted %s, but lost out because result was %s", 3672cad65a5SGreg Clayton __FUNCTION__, 3682cad65a5SGreg Clayton thread_sp->GetID (), 3692cad65a5SGreg Clayton GetVoteAsCString (vote), 3702cad65a5SGreg Clayton GetVoteAsCString (result)); 3712cad65a5SGreg Clayton } 37230fdc8d8SChris Lattner break; 37330fdc8d8SChris Lattner } 37430fdc8d8SChris Lattner } 3752cad65a5SGreg Clayton if (log) 37610c4b249SJim Ingham log->Printf ("ThreadList::%s returning %s", __FUNCTION__, GetVoteAsCString (result)); 37730fdc8d8SChris Lattner return result; 37830fdc8d8SChris Lattner } 37930fdc8d8SChris Lattner 380221d51cfSJim Ingham void 381221d51cfSJim Ingham ThreadList::SetShouldReportStop (Vote vote) 382221d51cfSJim Ingham { 383221d51cfSJim Ingham Mutex::Locker locker(GetMutex()); 384221d51cfSJim Ingham m_process->UpdateThreadListIfNeeded(); 385221d51cfSJim Ingham collection::iterator pos, end = m_threads.end(); 386221d51cfSJim Ingham for (pos = m_threads.begin(); pos != end; ++pos) 387221d51cfSJim Ingham { 388221d51cfSJim Ingham ThreadSP thread_sp(*pos); 389221d51cfSJim Ingham thread_sp->SetShouldReportStop (vote); 390221d51cfSJim Ingham } 391221d51cfSJim Ingham } 392221d51cfSJim Ingham 39330fdc8d8SChris Lattner Vote 39430fdc8d8SChris Lattner ThreadList::ShouldReportRun (Event *event_ptr) 39530fdc8d8SChris Lattner { 3962cad65a5SGreg Clayton 397ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 3982cad65a5SGreg Clayton 39930fdc8d8SChris Lattner Vote result = eVoteNoOpinion; 40030fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 40130fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 40230fdc8d8SChris Lattner 40330fdc8d8SChris Lattner // Run through the threads and ask whether we should report this event. 40430fdc8d8SChris Lattner // The rule is NO vote wins over everything, a YES vote wins over no opinion. 40530fdc8d8SChris Lattner 4065160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 407ce579839SJim Ingham 40830fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 40930fdc8d8SChris Lattner { 410ce579839SJim Ingham if ((*pos)->GetResumeState () != eStateSuspended) 411ce579839SJim Ingham { 412ce579839SJim Ingham switch ((*pos)->ShouldReportRun (event_ptr)) 41330fdc8d8SChris Lattner { 41430fdc8d8SChris Lattner case eVoteNoOpinion: 41530fdc8d8SChris Lattner continue; 41630fdc8d8SChris Lattner case eVoteYes: 41730fdc8d8SChris Lattner if (result == eVoteNoOpinion) 41830fdc8d8SChris Lattner result = eVoteYes; 41930fdc8d8SChris Lattner break; 42030fdc8d8SChris Lattner case eVoteNo: 421abcbc8acSGreg Clayton if (log) 422d01b2953SDaniel Malea log->Printf ("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 ") says don't report.", 423ce579839SJim Ingham (*pos)->GetIndexID(), 424ce579839SJim Ingham (*pos)->GetID()); 42530fdc8d8SChris Lattner result = eVoteNo; 42630fdc8d8SChris Lattner break; 42730fdc8d8SChris Lattner } 42830fdc8d8SChris Lattner } 429ce579839SJim Ingham } 43030fdc8d8SChris Lattner return result; 43130fdc8d8SChris Lattner } 43230fdc8d8SChris Lattner 43330fdc8d8SChris Lattner void 43430fdc8d8SChris Lattner ThreadList::Clear() 43530fdc8d8SChris Lattner { 436ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 43730fdc8d8SChris Lattner m_stop_id = 0; 43830fdc8d8SChris Lattner m_threads.clear(); 4392976d00aSJim Ingham m_selected_tid = LLDB_INVALID_THREAD_ID; 44030fdc8d8SChris Lattner } 44130fdc8d8SChris Lattner 44230fdc8d8SChris Lattner void 443e1cd1be6SGreg Clayton ThreadList::Destroy() 444e1cd1be6SGreg Clayton { 445ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 446e1cd1be6SGreg Clayton const uint32_t num_threads = m_threads.size(); 447e1cd1be6SGreg Clayton for (uint32_t idx = 0; idx < num_threads; ++idx) 448e1cd1be6SGreg Clayton { 449e1cd1be6SGreg Clayton m_threads[idx]->DestroyThread(); 450e1cd1be6SGreg Clayton } 451e1cd1be6SGreg Clayton } 452e1cd1be6SGreg Clayton 453e1cd1be6SGreg Clayton void 45430fdc8d8SChris Lattner ThreadList::RefreshStateAfterStop () 45530fdc8d8SChris Lattner { 456ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 45730fdc8d8SChris Lattner 45830fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 45930fdc8d8SChris Lattner 4605160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 46110c4b249SJim Ingham if (log && log->GetVerbose()) 4621c823b43SJim Ingham log->Printf ("Turning off notification of new threads while single stepping a thread."); 4631c823b43SJim Ingham 46430fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 46530fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 46630fdc8d8SChris Lattner (*pos)->RefreshStateAfterStop (); 46730fdc8d8SChris Lattner } 46830fdc8d8SChris Lattner 46930fdc8d8SChris Lattner void 47030fdc8d8SChris Lattner ThreadList::DiscardThreadPlans () 47130fdc8d8SChris Lattner { 47230fdc8d8SChris Lattner // You don't need to update the thread list here, because only threads 47330fdc8d8SChris Lattner // that you currently know about have any thread plans. 474ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 47530fdc8d8SChris Lattner 47630fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 47730fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 47830fdc8d8SChris Lattner (*pos)->DiscardThreadPlans (true); 47930fdc8d8SChris Lattner 48030fdc8d8SChris Lattner } 48130fdc8d8SChris Lattner 48230fdc8d8SChris Lattner bool 48330fdc8d8SChris Lattner ThreadList::WillResume () 48430fdc8d8SChris Lattner { 48530fdc8d8SChris Lattner // Run through the threads and perform their momentary actions. 48630fdc8d8SChris Lattner // But we only do this for threads that are running, user suspended 48730fdc8d8SChris Lattner // threads stay where they are. 48830fdc8d8SChris Lattner 489ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 49030fdc8d8SChris Lattner m_process->UpdateThreadListIfNeeded(); 49130fdc8d8SChris Lattner 49230fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 49330fdc8d8SChris Lattner 494a3241c1bSJim Ingham // See if any thread wants to run stopping others. If it does, then we won't 495a3241c1bSJim Ingham // setup the other threads for resume, since they aren't going to get a chance 496a3241c1bSJim Ingham // to run. This is necessary because the SetupForResume might add "StopOthers" 497a3241c1bSJim Ingham // plans which would then get to be part of the who-gets-to-run negotiation, but 498a3241c1bSJim Ingham // they're coming in after the fact, and the threads that are already set up should 499a3241c1bSJim Ingham // take priority. 500a3241c1bSJim Ingham 501a3241c1bSJim Ingham bool wants_solo_run = false; 50230fdc8d8SChris Lattner 50330fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 504a3241c1bSJim Ingham { 505a3241c1bSJim Ingham if ((*pos)->GetResumeState() != eStateSuspended && 506a3241c1bSJim Ingham (*pos)->GetCurrentPlan()->StopOthers()) 507a3241c1bSJim Ingham { 5086e0ff1a3SGreg Clayton if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) 5096e0ff1a3SGreg Clayton continue; 510a3241c1bSJim Ingham wants_solo_run = true; 511a3241c1bSJim Ingham break; 512a3241c1bSJim Ingham } 513a3241c1bSJim Ingham } 514a3241c1bSJim Ingham 5151c823b43SJim Ingham if (wants_solo_run) 5161c823b43SJim Ingham { 5175160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 51810c4b249SJim Ingham if (log && log->GetVerbose()) 5191c823b43SJim Ingham log->Printf ("Turning on notification of new threads while single stepping a thread."); 5201c823b43SJim Ingham m_process->StartNoticingNewThreads(); 5211c823b43SJim Ingham } 5221c823b43SJim Ingham else 5231c823b43SJim Ingham { 5245160ce5cSGreg Clayton Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 52510c4b249SJim Ingham if (log && log->GetVerbose()) 5261c823b43SJim Ingham log->Printf ("Turning off notification of new threads while single stepping a thread."); 5271c823b43SJim Ingham m_process->StopNoticingNewThreads(); 5281c823b43SJim Ingham } 529a3241c1bSJim Ingham 530a3241c1bSJim Ingham // Give all the threads that are likely to run a last chance to set up their state before we 531a3241c1bSJim Ingham // negotiate who is actually going to get a chance to run... 532a3241c1bSJim Ingham // Don't set to resume suspended threads, and if any thread wanted to stop others, only 533a3241c1bSJim Ingham // call setup on the threads that request StopOthers... 534a3241c1bSJim Ingham 535a3241c1bSJim Ingham for (pos = m_threads.begin(); pos != end; ++pos) 536a3241c1bSJim Ingham { 537a3241c1bSJim Ingham if ((*pos)->GetResumeState() != eStateSuspended 538a3241c1bSJim Ingham && (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers())) 539a3241c1bSJim Ingham { 5406e0ff1a3SGreg Clayton if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) 5416e0ff1a3SGreg Clayton continue; 54230fdc8d8SChris Lattner (*pos)->SetupForResume (); 543a3241c1bSJim Ingham } 544a3241c1bSJim Ingham } 54530fdc8d8SChris Lattner 54630fdc8d8SChris Lattner // Now go through the threads and see if any thread wants to run just itself. 54730fdc8d8SChris Lattner // if so then pick one and run it. 548a3241c1bSJim Ingham 54930fdc8d8SChris Lattner ThreadList run_me_only_list (m_process); 55030fdc8d8SChris Lattner 55130fdc8d8SChris Lattner run_me_only_list.SetStopID(m_process->GetStopID()); 55230fdc8d8SChris Lattner 55330fdc8d8SChris Lattner bool run_only_current_thread = false; 55430fdc8d8SChris Lattner 55530fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 55630fdc8d8SChris Lattner { 55730fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 558b15bfc75SJim Ingham if (thread_sp->GetResumeState() != eStateSuspended && 55930fdc8d8SChris Lattner thread_sp->GetCurrentPlan()->StopOthers()) 56030fdc8d8SChris Lattner { 5616e0ff1a3SGreg Clayton if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) 5626e0ff1a3SGreg Clayton continue; 5636e0ff1a3SGreg Clayton 56430fdc8d8SChris Lattner // You can't say "stop others" and also want yourself to be suspended. 56530fdc8d8SChris Lattner assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended); 56630fdc8d8SChris Lattner 5672976d00aSJim Ingham if (thread_sp == GetSelectedThread()) 56830fdc8d8SChris Lattner { 56930fdc8d8SChris Lattner run_only_current_thread = true; 57030fdc8d8SChris Lattner run_me_only_list.Clear(); 57130fdc8d8SChris Lattner run_me_only_list.AddThread (thread_sp); 57230fdc8d8SChris Lattner break; 57330fdc8d8SChris Lattner } 57430fdc8d8SChris Lattner 57530fdc8d8SChris Lattner run_me_only_list.AddThread (thread_sp); 57630fdc8d8SChris Lattner } 57730fdc8d8SChris Lattner 57830fdc8d8SChris Lattner } 57930fdc8d8SChris Lattner 580513c6bb8SJim Ingham bool need_to_resume = true; 581513c6bb8SJim Ingham 5826e0ff1a3SGreg Clayton if (run_me_only_list.GetSize (false) == 0) 58330fdc8d8SChris Lattner { 58430fdc8d8SChris Lattner // Everybody runs as they wish: 58530fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 58630fdc8d8SChris Lattner { 58730fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 588cb5d5a57SJim Ingham StateType run_state; 589cb5d5a57SJim Ingham if (thread_sp->GetResumeState() != eStateSuspended) 590cb5d5a57SJim Ingham run_state = thread_sp->GetCurrentPlan()->RunState(); 591cb5d5a57SJim Ingham else 592cb5d5a57SJim Ingham run_state = eStateSuspended; 593160c9d81SGreg Clayton if (!thread_sp->ShouldResume(run_state)) 594513c6bb8SJim Ingham need_to_resume = false; 59530fdc8d8SChris Lattner } 59630fdc8d8SChris Lattner } 59730fdc8d8SChris Lattner else 59830fdc8d8SChris Lattner { 59930fdc8d8SChris Lattner ThreadSP thread_to_run; 60030fdc8d8SChris Lattner 60130fdc8d8SChris Lattner if (run_only_current_thread) 60230fdc8d8SChris Lattner { 6032976d00aSJim Ingham thread_to_run = GetSelectedThread(); 60430fdc8d8SChris Lattner } 60530fdc8d8SChris Lattner else if (run_me_only_list.GetSize (false) == 1) 60630fdc8d8SChris Lattner { 60730fdc8d8SChris Lattner thread_to_run = run_me_only_list.GetThreadAtIndex (0); 60830fdc8d8SChris Lattner } 60930fdc8d8SChris Lattner else 61030fdc8d8SChris Lattner { 61130fdc8d8SChris Lattner int random_thread = (int) 61230fdc8d8SChris Lattner ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0)); 61330fdc8d8SChris Lattner thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread); 61430fdc8d8SChris Lattner } 61530fdc8d8SChris Lattner 61630fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 61730fdc8d8SChris Lattner { 61830fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 61930fdc8d8SChris Lattner if (thread_sp == thread_to_run) 620513c6bb8SJim Ingham { 621160c9d81SGreg Clayton if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState())) 622513c6bb8SJim Ingham need_to_resume = false; 623513c6bb8SJim Ingham } 62430fdc8d8SChris Lattner else 625160c9d81SGreg Clayton thread_sp->ShouldResume (eStateSuspended); 62630fdc8d8SChris Lattner } 62730fdc8d8SChris Lattner } 62830fdc8d8SChris Lattner 629513c6bb8SJim Ingham return need_to_resume; 63030fdc8d8SChris Lattner } 63130fdc8d8SChris Lattner 63230fdc8d8SChris Lattner void 63330fdc8d8SChris Lattner ThreadList::DidResume () 63430fdc8d8SChris Lattner { 635ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 63630fdc8d8SChris Lattner collection::iterator pos, end = m_threads.end(); 63730fdc8d8SChris Lattner for (pos = m_threads.begin(); pos != end; ++pos) 63830fdc8d8SChris Lattner { 63930fdc8d8SChris Lattner // Don't clear out threads that aren't going to get a chance to run, rather 64030fdc8d8SChris Lattner // leave their state for the next time around. 64130fdc8d8SChris Lattner ThreadSP thread_sp(*pos); 64230fdc8d8SChris Lattner if (thread_sp->GetResumeState() != eStateSuspended) 64330fdc8d8SChris Lattner thread_sp->DidResume (); 64430fdc8d8SChris Lattner } 64530fdc8d8SChris Lattner } 64630fdc8d8SChris Lattner 647*29d65744SAndrew Kaylor void 648*29d65744SAndrew Kaylor ThreadList::DidStop () 649*29d65744SAndrew Kaylor { 650*29d65744SAndrew Kaylor Mutex::Locker locker(GetMutex()); 651*29d65744SAndrew Kaylor collection::iterator pos, end = m_threads.end(); 652*29d65744SAndrew Kaylor for (pos = m_threads.begin(); pos != end; ++pos) 653*29d65744SAndrew Kaylor { 654*29d65744SAndrew Kaylor // Notify threads that the process just stopped. 655*29d65744SAndrew Kaylor // Note, this currently assumes that all threads in the list 656*29d65744SAndrew Kaylor // stop when the process stops. In the future we will want to support 657*29d65744SAndrew Kaylor // a debugging model where some threads continue to run while others 658*29d65744SAndrew Kaylor // are stopped. We either need to handle that somehow here or 659*29d65744SAndrew Kaylor // create a special thread list containing only threads which will 660*29d65744SAndrew Kaylor // stop in the code that calls this method (currently 661*29d65744SAndrew Kaylor // Process::SetPrivateState). 662*29d65744SAndrew Kaylor ThreadSP thread_sp(*pos); 663*29d65744SAndrew Kaylor if (StateIsRunningState(thread_sp->GetState())) 664*29d65744SAndrew Kaylor thread_sp->DidStop (); 665*29d65744SAndrew Kaylor } 666*29d65744SAndrew Kaylor } 667*29d65744SAndrew Kaylor 66830fdc8d8SChris Lattner ThreadSP 6692976d00aSJim Ingham ThreadList::GetSelectedThread () 67030fdc8d8SChris Lattner { 671ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 672943ddb73SJohnny Chen ThreadSP thread_sp = FindThreadByID(m_selected_tid); 673943ddb73SJohnny Chen if (!thread_sp.get()) 674943ddb73SJohnny Chen { 675354b9a65SJason Molenda if (m_threads.size() == 0) 676354b9a65SJason Molenda return thread_sp; 677943ddb73SJohnny Chen m_selected_tid = m_threads[0]->GetID(); 678943ddb73SJohnny Chen thread_sp = m_threads[0]; 679943ddb73SJohnny Chen } 680943ddb73SJohnny Chen return thread_sp; 68130fdc8d8SChris Lattner } 68230fdc8d8SChris Lattner 68330fdc8d8SChris Lattner bool 684c3faa195SJim Ingham ThreadList::SetSelectedThreadByID (lldb::tid_t tid, bool notify) 68530fdc8d8SChris Lattner { 686ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 687b7f6b2faSJim Ingham ThreadSP selected_thread_sp(FindThreadByID(tid)); 688b7f6b2faSJim Ingham if (selected_thread_sp) 689b7f6b2faSJim Ingham { 6902976d00aSJim Ingham m_selected_tid = tid; 691b7f6b2faSJim Ingham selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); 692b7f6b2faSJim Ingham } 69330fdc8d8SChris Lattner else 6942976d00aSJim Ingham m_selected_tid = LLDB_INVALID_THREAD_ID; 69530fdc8d8SChris Lattner 696c3faa195SJim Ingham if (notify) 697c3faa195SJim Ingham NotifySelectedThreadChanged(m_selected_tid); 698c3faa195SJim Ingham 6992976d00aSJim Ingham return m_selected_tid != LLDB_INVALID_THREAD_ID; 70030fdc8d8SChris Lattner } 70130fdc8d8SChris Lattner 70230fdc8d8SChris Lattner bool 703c3faa195SJim Ingham ThreadList::SetSelectedThreadByIndexID (uint32_t index_id, bool notify) 70430fdc8d8SChris Lattner { 705ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 706b7f6b2faSJim Ingham ThreadSP selected_thread_sp (FindThreadByIndexID(index_id)); 707b7f6b2faSJim Ingham if (selected_thread_sp.get()) 708b7f6b2faSJim Ingham { 709b7f6b2faSJim Ingham m_selected_tid = selected_thread_sp->GetID(); 710b7f6b2faSJim Ingham selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); 711b7f6b2faSJim Ingham } 71230fdc8d8SChris Lattner else 7132976d00aSJim Ingham m_selected_tid = LLDB_INVALID_THREAD_ID; 71430fdc8d8SChris Lattner 715c3faa195SJim Ingham if (notify) 716c3faa195SJim Ingham NotifySelectedThreadChanged(m_selected_tid); 717c3faa195SJim Ingham 7182976d00aSJim Ingham return m_selected_tid != LLDB_INVALID_THREAD_ID; 71930fdc8d8SChris Lattner } 72030fdc8d8SChris Lattner 72156d9a1b3SGreg Clayton void 722c3faa195SJim Ingham ThreadList::NotifySelectedThreadChanged (lldb::tid_t tid) 723c3faa195SJim Ingham { 724c3faa195SJim Ingham ThreadSP selected_thread_sp (FindThreadByID(tid)); 725c3faa195SJim Ingham if (selected_thread_sp->EventTypeHasListeners(Thread::eBroadcastBitThreadSelected)) 726c3faa195SJim Ingham selected_thread_sp->BroadcastEvent(Thread::eBroadcastBitThreadSelected, 727c3faa195SJim Ingham new Thread::ThreadEventData(selected_thread_sp)); 728c3faa195SJim Ingham } 729c3faa195SJim Ingham 730c3faa195SJim Ingham void 73156d9a1b3SGreg Clayton ThreadList::Update (ThreadList &rhs) 73256d9a1b3SGreg Clayton { 73356d9a1b3SGreg Clayton if (this != &rhs) 73456d9a1b3SGreg Clayton { 73556d9a1b3SGreg Clayton // Lock both mutexes to make sure neither side changes anyone on us 73656d9a1b3SGreg Clayton // while the assignement occurs 737ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 73856d9a1b3SGreg Clayton m_process = rhs.m_process; 73956d9a1b3SGreg Clayton m_stop_id = rhs.m_stop_id; 74056d9a1b3SGreg Clayton m_threads.swap(rhs.m_threads); 74156d9a1b3SGreg Clayton m_selected_tid = rhs.m_selected_tid; 742e1cd1be6SGreg Clayton 743e1cd1be6SGreg Clayton 744e1cd1be6SGreg Clayton // Now we look for threads that we are done with and 745e1cd1be6SGreg Clayton // make sure to clear them up as much as possible so 746e1cd1be6SGreg Clayton // anyone with a shared pointer will still have a reference, 747e1cd1be6SGreg Clayton // but the thread won't be of much use. Using std::weak_ptr 748e1cd1be6SGreg Clayton // for all backward references (such as a thread to a process) 749e1cd1be6SGreg Clayton // will eventually solve this issue for us, but for now, we 750e1cd1be6SGreg Clayton // need to work around the issue 751e1cd1be6SGreg Clayton collection::iterator rhs_pos, rhs_end = rhs.m_threads.end(); 752e1cd1be6SGreg Clayton for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) 753e1cd1be6SGreg Clayton { 754e1cd1be6SGreg Clayton const lldb::tid_t tid = (*rhs_pos)->GetID(); 755e1cd1be6SGreg Clayton bool thread_is_alive = false; 756e1cd1be6SGreg Clayton const uint32_t num_threads = m_threads.size(); 757e1cd1be6SGreg Clayton for (uint32_t idx = 0; idx < num_threads; ++idx) 758e1cd1be6SGreg Clayton { 759e1cd1be6SGreg Clayton if (m_threads[idx]->GetID() == tid) 760e1cd1be6SGreg Clayton { 761e1cd1be6SGreg Clayton thread_is_alive = true; 762e1cd1be6SGreg Clayton break; 763e1cd1be6SGreg Clayton } 764e1cd1be6SGreg Clayton } 765e1cd1be6SGreg Clayton if (!thread_is_alive) 766e1cd1be6SGreg Clayton (*rhs_pos)->DestroyThread(); 767e1cd1be6SGreg Clayton } 76856d9a1b3SGreg Clayton } 76956d9a1b3SGreg Clayton } 77056d9a1b3SGreg Clayton 771fa559e5cSGreg Clayton void 772fa559e5cSGreg Clayton ThreadList::Flush () 773fa559e5cSGreg Clayton { 774ba4e61d3SAndrew Kaylor Mutex::Locker locker(GetMutex()); 775fa559e5cSGreg Clayton collection::iterator pos, end = m_threads.end(); 776fa559e5cSGreg Clayton for (pos = m_threads.begin(); pos != end; ++pos) 777fa559e5cSGreg Clayton (*pos)->Flush (); 778fa559e5cSGreg Clayton } 77956d9a1b3SGreg Clayton 780ba4e61d3SAndrew Kaylor Mutex & 781ba4e61d3SAndrew Kaylor ThreadList::GetMutex () 782ba4e61d3SAndrew Kaylor { 783ba4e61d3SAndrew Kaylor return m_process->m_thread_mutex; 784ba4e61d3SAndrew Kaylor } 785ba4e61d3SAndrew Kaylor 786