Fixed a case where we might be able to acquire a mutex with a try lock and

not release it by making sure a mutex locker object is appropriately used.

llvm-svn: 112996
This commit is contained in:
Greg Clayton 2010-09-03 19:15:43 +00:00
parent 78395e4b8a
commit 54512bd6c9
5 changed files with 41 additions and 13 deletions

View File

@ -78,8 +78,7 @@ Mutex::Locker::Locker (pthread_mutex_t *mutex_ptr) :
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Mutex::Locker::~Locker () Mutex::Locker::~Locker ()
{ {
if (m_mutex_ptr) Reset();
Mutex::Unlock (m_mutex_ptr);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -89,6 +88,10 @@ Mutex::Locker::~Locker ()
void void
Mutex::Locker::Reset (pthread_mutex_t *mutex_ptr) Mutex::Locker::Reset (pthread_mutex_t *mutex_ptr)
{ {
// We already have this mutex locked or both are NULL...
if (m_mutex_ptr == mutex_ptr)
return;
if (m_mutex_ptr) if (m_mutex_ptr)
Mutex::Unlock (m_mutex_ptr); Mutex::Unlock (m_mutex_ptr);
@ -100,9 +103,12 @@ Mutex::Locker::Reset (pthread_mutex_t *mutex_ptr)
bool bool
Mutex::Locker::TryLock (pthread_mutex_t *mutex_ptr) Mutex::Locker::TryLock (pthread_mutex_t *mutex_ptr)
{ {
if (m_mutex_ptr) // We already have this mutex locked!
Mutex::Unlock (m_mutex_ptr); if (m_mutex_ptr == mutex_ptr)
m_mutex_ptr = NULL; return true;
Reset ();
if (mutex_ptr) if (mutex_ptr)
{ {
if (Mutex::TryLock (mutex_ptr) == 0) if (Mutex::TryLock (mutex_ptr) == 0)

View File

@ -124,7 +124,7 @@ GDBRemoteCommunication::SendPacketAndWaitForResponse
timeout_time = TimeValue::Now(); timeout_time = TimeValue::Now();
timeout_time.OffsetWithSeconds (timeout_seconds); timeout_time.OffsetWithSeconds (timeout_seconds);
if (locker.TryLock (m_sequence_mutex.GetMutex())) if (GetSequenceMutex (locker))
{ {
if (SendPacketNoLock (payload, strlen(payload))) if (SendPacketNoLock (payload, strlen(payload)))
return WaitForPacketNoLock (response, &timeout_time); return WaitForPacketNoLock (response, &timeout_time);
@ -139,7 +139,7 @@ GDBRemoteCommunication::SendPacketAndWaitForResponse
m_async_packet_predicate.SetValue (true, eBroadcastNever); m_async_packet_predicate.SetValue (true, eBroadcastNever);
bool timed_out = false; bool timed_out = false;
if (SendInterrupt(1, &timed_out)) if (SendInterrupt(locker, 1, &timed_out))
{ {
if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
{ {
@ -396,14 +396,25 @@ GDBRemoteCommunication::SendAsyncSignal (int signo)
{ {
m_async_signal = signo; m_async_signal = signo;
bool timed_out = false; bool timed_out = false;
if (SendInterrupt(1, &timed_out)) Mutex::Locker locker;
if (SendInterrupt (locker, 1, &timed_out))
return true; return true;
m_async_signal = -1; m_async_signal = -1;
return false; return false;
} }
// This function takes a mutex locker as a parameter in case the GetSequenceMutex
// actually succeeds. If it doesn't succeed in acquiring the sequence mutex
// (the expected result), then it will send the halt packet. If it does succeed
// then the caller that requested the interrupt will want to keep the sequence
// locked down so that no one else can send packets while the caller has control.
// This function usually gets called when we are running and need to stop the
// target. It can also be used when we are running and and we need to do something
// else (like read/write memory), so we need to interrupt the running process
// (gdb remote protocol requires this), and do what we need to do, then resume.
bool bool
GDBRemoteCommunication::SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out) GDBRemoteCommunication::SendInterrupt (Mutex::Locker& locker, uint32_t seconds_to_wait_for_stop, bool *timed_out)
{ {
if (timed_out) if (timed_out)
*timed_out = false; *timed_out = false;
@ -411,7 +422,7 @@ GDBRemoteCommunication::SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *
if (IsConnected() && IsRunning()) if (IsConnected() && IsRunning())
{ {
// Only send an interrupt if our debugserver is running... // Only send an interrupt if our debugserver is running...
if (m_sequence_mutex.TryLock() != 0) if (GetSequenceMutex (locker) == false)
{ {
// Someone has the mutex locked waiting for a response or for the // Someone has the mutex locked waiting for a response or for the
// inferior to stop, so send the interrupt on the down low... // inferior to stop, so send the interrupt on the down low...

View File

@ -99,7 +99,9 @@ public:
SendAsyncSignal (int signo); SendAsyncSignal (int signo);
bool bool
SendInterrupt (uint32_t seconds_to_wait_for_stop, bool *timed_out = NULL); SendInterrupt (lldb_private::Mutex::Locker &locker,
uint32_t seconds_to_wait_for_stop,
bool *timed_out = NULL);
bool bool
GetSequenceMutex(lldb_private::Mutex::Locker& locker); GetSequenceMutex(lldb_private::Mutex::Locker& locker);

View File

@ -1117,7 +1117,8 @@ ProcessGDBRemote::DoHalt ()
if (m_gdb_comm.IsRunning()) if (m_gdb_comm.IsRunning())
{ {
bool timed_out = false; bool timed_out = false;
if (!m_gdb_comm.SendInterrupt (2, &timed_out)) Mutex::Locker locker;
if (!m_gdb_comm.SendInterrupt (locker, 2, &timed_out))
{ {
if (timed_out) if (timed_out)
error.SetErrorString("timed out sending interrupt packet"); error.SetErrorString("timed out sending interrupt packet");
@ -1150,7 +1151,8 @@ ProcessGDBRemote::DoDestroy ()
log->Printf ("ProcessGDBRemote::DoDestroy()"); log->Printf ("ProcessGDBRemote::DoDestroy()");
// Interrupt if our inferior is running... // Interrupt if our inferior is running...
m_gdb_comm.SendInterrupt (1); Mutex::Locker locker;
m_gdb_comm.SendInterrupt (locker, 1);
DisableAllBreakpointSites (); DisableAllBreakpointSites ();
SetExitStatus(-1, "process killed"); SetExitStatus(-1, "process killed");

View File

@ -369,7 +369,14 @@
isa = PBXProject; isa = PBXProject;
buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "debugserver" */; buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "debugserver" */;
compatibilityVersion = "Xcode 3.1"; compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1; hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* dbgnub */; mainGroup = 08FB7794FE84155DC02AAC07 /* dbgnub */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";