Chromium Code Reviews| Index: src/trusted/gdb_rsp/target.cc |
| =================================================================== |
| --- src/trusted/gdb_rsp/target.cc (revision 3879) |
| +++ src/trusted/gdb_rsp/target.cc (working copy) |
| @@ -34,16 +34,25 @@ |
| Target::Target(const Abi* abi) |
| : abi_(abi), |
|
noelallen_use_chromium
2010/12/07 23:04:44
This should generate a warning. Initializers nee
mlinck
2010/12/10 21:10:27
In this particular case, it is the same order as i
|
| - mutex_(NULL), |
| + stateMutex_(NULL), |
| + publicMutex_(NULL), |
| sig_start_(NULL), |
| sig_done_(NULL), |
| - send_done_(false), |
| ctx_(NULL), |
| cur_signal_(-1), |
| sig_thread_(0), |
| - run_thread_(-1), |
| - reg_thread_(-1) { |
| - if (NULL == abi_) abi_ = Abi::Get(); |
| + run_req_(-1), |
|
mmortensen
2010/12/07 22:53:58
Since this is an unsigned int, do we cause warning
mlinck
2010/12/10 21:10:27
I'll resolve this once I get some feedback on how
|
| + run_last_(0), |
| + reg_req_(-1), |
| + reg_last_(0) { |
| + printf("Target constructed "); |
|
noelallen_use_chromium
2010/12/07 23:04:44
looks like bogus prints. Fix this one and the on
mlinck
2010/12/10 21:10:27
Done.
|
| + if (NULL == abi_) { |
| + printf("without ABI.\n"); |
| + abi_ = Abi::Get(); |
| + } else { |
| + printf("with ABI.\n"); |
| + } |
| + printf("Target got ABI: %s \n", abi_->GetName()); |
| } |
| Target::~Target() { |
| @@ -51,34 +60,98 @@ |
| } |
| bool Target::Init() { |
| - string targ_xml = "l<target><architecture>"; |
| - |
| - targ_xml += abi_->GetName(); |
| - targ_xml += "</architecture></target>"; |
| - |
| - // Set a more specific result which won't change. |
| - properties_["target.xml"] = targ_xml; |
| - properties_["Supported"] = |
| - "PacketSize=7cf;qXfer:libraries:read+;qXfer:features:read+"; |
| - |
| - mutex_ = IMutex::Allocate(); |
| + stateMutex_ = IMutex::Allocate(); |
| + publicMutex_ = IMutex::Allocate(); |
| sig_start_ = IEvent::Allocate(); |
| sig_done_ = IEvent::Allocate(); |
| ctx_ = new uint8_t[abi_->GetContextSize()]; |
| - if ((NULL == mutex_) || (NULL == sig_start_) || (NULL == sig_done_) |
| - || (NULL == ctx_)) { |
| + if ((NULL == stateMutex_) || (NULL == publicMutex_) || (NULL == sig_start_) |
| + || (NULL == sig_done_) || (NULL == ctx_)) { |
| Destroy(); |
| return false; |
| } |
| + string targ_xml = "l<target><architecture>"; |
| + targ_xml += abi_->GetName(); |
| + printf("Populating Target Architecture with: #%s#.\n", abi_->GetName()); |
|
noelallen_use_chromium
2010/12/07 23:04:44
print
(I'll assume you will grep for print instead
|
| + targ_xml += "</architecture></target>"; |
| + |
| + // Set a more specific result which won't change. |
| + SetProperty("Xfer:features:read:target.xml", targ_xml); |
| + SetProperty("Supported", |
| + "PacketSize=7cf;qXfer:libraries:read+;qXfer:features:read+"); |
| + |
| // Allow one exception to happen |
| sig_start_->Signal(); |
| return true; |
| } |
| +bool Target::SetProperty(const std::string& name, const std::string& val) { |
| + MutexLock lock(publicMutex_); |
| + printf("SetProperty called with: %s.\n", name.c_str()); |
| + properties_[name] = val; |
| + return true; |
| +} |
| + |
| +bool Target::GetProperty(const std::string& name, std::string* val) const { |
| + MutexLock lock(publicMutex_); |
| + PropertyMap_t::const_iterator itr = properties_.find(name); |
| + if (itr == properties_.end()) return false; |
| + |
| + *val = itr->second; |
| + return true; |
| +} |
| + |
| +// MatchQuery looks for the longest prefix match, and returns that value. |
| +// A match key is in one of two forms: |
| +// 1 - <keyA>[:<keyB>[:<keyC>[...]]] |
| +// 2 - <Cmd>:<Type>:read/write:<Object>:<start>,<end> |
| +// We look for the second case, and assume the first if the format does not |
| +// match. The second case is special in that it encodes a substring request. |
| +// This allows transfers of very large values on a transport with a much |
| +// smaller max packet size. |
| +size_t Target::MatchQuery(const std::string& match, std::string* val) const { |
| + // Starting at longest match... |
| + stringvec parts = StringSplit(match, ":"); |
| + for (size_t cnt = parts.size(); cnt ; cnt--) { |
| + // Append the sub-parts and look for a match. |
| + std::string cmp; |
| + for (size_t i = 0; i < cnt; i++) { |
| + if (i) cmp += ":"; |
| + cmp += parts[i]; |
| + } |
| + |
| + // If we find this cached value, return it and the match length |
| + if (GetProperty(cmp, val)) { |
| + // Check for a "<CMD>:<TYPE>:read:<OBJ>:<start>,<len> |
| + if ((cnt == 4) && (parts[3] == "read") && (parts.size() == 5)) { |
| + // Split the start,length field |
| + stringvec args = StringSplit(parts[4], ","); |
| + if (args.size() != 2) return cnt; |
| + |
| + std::string tmp = *val; |
| + size_t offs = strtoul(args[0].data(), NULL, 16); |
| + size_t max = strtoul(args[1].data(), NULL, 16) + offs; |
| + size_t len = tmp.size(); |
| + |
| + // Clear val and only send the requested portion |
| + *val = ""; |
| + if (max >= len) max = len; |
| + while (offs < max) { |
| + *val += tmp[offs]; |
| + offs++; |
| + } |
| + } |
| + return cnt; |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| void Target::Destroy() { |
| - if (mutex_) IMutex::Free(mutex_); |
| + if (stateMutex_) IMutex::Free(stateMutex_); |
| + if (publicMutex_) IMutex::Free(publicMutex_); |
| if (sig_start_) IEvent::Free(sig_start_); |
| if (sig_done_) IEvent::Free(sig_done_); |
| @@ -86,12 +159,13 @@ |
| } |
| bool Target::AddTemporaryBreakpoint(uint64_t address) { |
| + MutexLock lock(publicMutex_); |
| const Abi::BPDef *bp = abi_->GetBreakpointDef(); |
| // If this ABI does not support breakpoints then fail |
| if (NULL == bp) return false; |
| - // If we alreay have a breakpoint here then don't add it |
| + // If we already have a breakpoint here then don't add it |
| BreakMap_t::iterator itr = breakMap_.find(address); |
| if (itr != breakMap_.end()) return false; |
| @@ -113,6 +187,7 @@ |
| } |
| bool Target::RemoveTemporaryBreakpoints() { |
| + MutexLock lock(publicMutex_); |
| const Abi::BPDef *bp = abi_->GetBreakpointDef(); |
| // Iterate through the map, removing breakpoints |
| @@ -121,7 +196,7 @@ |
| BreakMap_t::iterator cur = breakMap_.begin(); |
| uint64_t addr = cur->first; |
| uint8_t *data = cur->second; |
| - |
| + |
| // Then remove it from the map |
| breakMap_.erase(cur); |
| @@ -134,30 +209,16 @@ |
| } |
| - |
| void Target::Signal(uint32_t id, int8_t sig, bool wait) { |
| // Wait for this signal's turn in the signal Q. |
| sig_start_->Wait(); |
| { |
| - // Now lock the target, sleeping all active threads |
| - MutexLock lock(mutex_); |
| + // Lock the signal state information to revent a race |
| + MutexLock lock(stateMutex_); |
| - // Suspend all threads except this one |
| - uint32_t curId; |
| - bool more = GetFirstThreadId(&curId); |
| - while (more) { |
| - if (curId != id) { |
| - IThread *thread = threads_[curId]; |
| - thread->Suspend(); |
| - } |
| - more = GetNextThreadId(&curId); |
| - } |
| - |
| - // Signal the stub (Run thread) that we are ready to process |
| - // a trap, by updating the signal information and releasing |
| - // the lock. |
| - reg_thread_ = id; |
| - run_thread_ = id; |
| + // Signal the stub that we are ready to process a trap |
| + // by locking the signal information, and updating it. |
| + sig_thread_ = id; |
| cur_signal_ = sig; |
| } |
| @@ -165,56 +226,93 @@ |
| if (wait) sig_done_->Wait(); |
| } |
| +void Target::Update() { |
| + // Next update the current thread info |
| + char tmp[16]; |
| + snprintf(tmp, sizeof(tmp), "QC%x", sig_thread_); |
| + SetProperty("C", tmp); |
| +} |
| + |
| +void Target::Pause() { |
| + // put all active threads to sleep. |
| + uint32_t curId; |
| + bool more = GetFirstThreadId(&curId); |
| + while (more) { |
| + IThread *thread = GetThread(curId); |
| + if (thread->GetState() == IThread::RUNNING) thread->Suspend(); |
| + more = GetNextThreadId(&curId); |
| + } |
| +} |
| + |
| +void Target::Resume() { |
| + // Now that we are done, we want to continue in the "correct order". |
| + // This means letting the active thread go first, in case we are single |
| + // stepping and want to catch it again. This is a desired behavior but |
| + // it is not guaranteed since another thread may already be in an |
| + // exception state and next in line to notify the target. |
| + |
| + // Wake up the run thread if it needs it, so it can go first |
| + IThread* thread = GetThread(GetRunThreadId()); |
| + if (thread->GetState() == IThread::SUSPENDED) thread->Resume(); |
| + |
| + // If we took an exception, let the handler resume and allow |
| + // the next exception to trigger (although it will still |
| + // block until we release the mutex). |
| + if (cur_signal_) { |
| + sig_done_->Signal(); |
| + sig_start_->Signal(); |
| + } |
| + |
| + // Now wake up everyone else that needs it |
| + uint32_t curId; |
| + bool more = GetFirstThreadId(&curId); |
| + while (more) { |
| + IThread* thread = GetThread(curId); |
| + |
| + // Definitely don't mess with breakpoint state here and let debugger decide |
| + // when it's time to turn off breakpoints. |
| + if (thread->GetState() == IThread::SUSPENDED) thread->Resume(); |
| + more = GetNextThreadId(&curId); |
| + } |
| +} |
| + |
| void Target::Run(Session *ses) { |
| bool first = true; |
| + |
| do { |
| // Give everyone else a chance to use the lock |
| IPlatform::Relinquish(100); |
| // Lock to prevent anyone else from modifying threads |
| // or updating the signal information. |
| - MutexLock lock(mutex_); |
| + MutexLock lock(stateMutex_); |
| Packet recv, reply; |
| - uint32_t id = 0; |
| - |
| // If no signal is waiting for this iteration... |
| if (-1 == cur_signal_) { |
| - // but the debugger is talking to us then force a break |
| + // but the debugger is talking to use |
| if (ses->DataAvailable()) { |
| - // set signal to 0 to signify paused |
| + // Then simulate a signal, by setting the state data |
| + // Set signal to 0 to signify paused |
| cur_signal_ = 0; |
| - // put all the threads to sleep. |
| - uint32_t curId; |
| - bool more = GetFirstThreadId(&curId); |
| - while (more) { |
| - if (curId != id) { |
| - IThread *thread = threads_[curId]; |
| - thread->Suspend(); |
| - } |
| - more = GetNextThreadId(&curId); |
| - } |
| + // Set the "signaling" thread to the preferred thread |
| + sig_thread_ = GetRunThreadId(); |
| } else { |
| - // otherwise, nothing to do so try again. |
| + // otherwise, we are not signaled, and we are not chatting |
| + // release the lock, and try again. |
| continue; |
| } |
| - } else { |
| - // otherwise there really is an exception so get the id of the thread |
| - id = GetRegThreadId(); |
| } |
| - // If we got this far, then there is some kind of signal. |
| - // So first, remove the breakpoints |
| - RemoveTemporaryBreakpoints(); |
| + // We have a signal, so pause everyone |
| + Pause(); |
| - // Next update the current thread info |
| - char tmp[16]; |
| - snprintf(tmp, sizeof(tmp), "QC%x", id); |
| - properties_["C"] = tmp; |
| + // Update our local state information |
| + Update(); |
| if (first) { |
| - // First time on a connection, we don't sent the signal |
| + // First time on a connection, we don't send the signal |
| first = false; |
| } else { |
| // All other times, send the signal that triggered us |
| @@ -234,59 +332,27 @@ |
| // If this is a continue command, break out of this loop |
| break; |
| } else { |
| - // Othwerise send the reponse |
| + // Otherwise send the reponse |
| ses->SendPacket(&reply); |
| } |
| } |
| } while (ses->Connected()); |
| + // Start everyone again. |
| + Resume(); |
| - // Now that we are done, we want to continue in the "correct order". |
| - // This means letting the active thread go first, in case we are single |
| - // stepping and want to catch it again. This is a desired behavior but |
| - // it is not guaranteed since another thread may already be in an |
| - // exception state and next in line to notify the target. |
| - |
| - // If the run thread is not the exception thread, wake it up now. |
| - uint32_t run_thread = GetRunThreadId(); |
| - if (run_thread != id |
| - && run_thread != static_cast<uint32_t>(-1)) { |
| - IThread* thread = threads_[run_thread]; |
| - thread->Resume(); |
| - } |
| - |
| - // Next, wake up the exception thread, if there is one and it needs |
| - // to wake up. |
| - if (id && send_done_) sig_done_->Signal(); |
| - |
| - // Now wake up everyone else |
| - uint32_t curId; |
| - bool more = GetFirstThreadId(&curId); |
| - while (more) { |
| - if ((curId != id) && (curId != GetRunThreadId())) { |
| - IThread *thread = threads_[curId]; |
| - thread->Resume(); |
| - } |
| - more = GetNextThreadId(&curId); |
| - } |
| - |
| - // Reset the signal value |
| + // Reset our state before we return, clearing the signal. However |
| + // we do not reset run_thread or reg_thread to preserve the last context. |
| cur_signal_ = -1; |
| + sig_thread_ = 0; |
| - // If we took an exception, let the handler resume and allow |
| - // the next exception to come in. |
| - if (cur_signal_) { |
| - sig_done_->Signal(); |
| - sig_start_->Signal(); |
| - } |
| - |
| + // At this point, we destroy the MutexLock, allowing anyone else to |
| + // and/remove threads or register a new signal. |
| // Continue running until the connection is lost. |
| } while (ses->Connected()); |
| } |
| - |
| - |
| bool Target::GetFirstThreadId(uint32_t *id) { |
| threadItr_ = threads_.begin(); |
| return GetNextThreadId(id); |
| @@ -302,7 +368,6 @@ |
| } |
| - |
| bool Target::ProcessPacket(Packet* pktIn, Packet* pktOut) { |
| char cmd; |
| int32_t seq = -1; |
| @@ -319,9 +384,15 @@ |
| pktIn->GetRawChar(&cmd); |
| switch (cmd) { |
| + // In the case of a force break, drop through |
| + // and print the signal. We have already suspended |
| + // the threads at this point. |
| + case 0x03: |
| + |
| // IN : $? |
| // OUT: $Sxx |
| case '?': |
| + // This case asks why the target has halted. |
| pktOut->AddRawChar('S'); |
| pktOut->AddWord8(cur_signal_); |
| break; |
| @@ -329,12 +400,15 @@ |
| // IN : $d |
| // OUT: -NONE- |
| case 'd': |
| + // This packet could be asking the debugger to detach but |
| + // we should never receive it. |
| Detach(); |
| - break; |
| + return true; |
| // IN : $g |
| // OUT: $xx...xx |
| case 'g': { |
| + // This packet is requesting the value of a general register. |
| uint32_t id = GetRegThreadId(); |
| if (0 == id) { |
| err = BAD_ARGS; |
| @@ -360,6 +434,8 @@ |
| // IN : $Gxx..xx |
| // OUT: $OK |
| case 'G': { |
| + // This packet is requesting that the value of a general register be |
| + // changed to something else. |
| uint32_t id = GetRegThreadId(); |
| if (0 == id) { |
| err = BAD_ARGS; |
| @@ -384,105 +460,122 @@ |
| // IN : $H(c/g)(-1,0,xxxx) |
| // OUT: $OK |
| case 'H': { |
| - char type; |
| - uint64_t id; |
| + // This packet is requesting that the thread be set for subsequent |
| + // operations. |
| + char type; |
| + uint64_t id; |
| - if (!pktIn->GetRawChar(&type)) { |
| - err = BAD_FORMAT; |
| - break; |
| - } |
| - if (!pktIn->GetNumberSep(&id, 0)) { |
| - err = BAD_FORMAT; |
| - break; |
| - } |
| + if (!pktIn->GetRawChar(&type)) { |
| + err = BAD_FORMAT; |
| + break; |
| + } |
| + if (!pktIn->GetNumberSep(&id, 0)) { |
| + err = BAD_FORMAT; |
| + break; |
| + } |
| - if (threads_.begin() == threads_.end()) { |
| - err = BAD_ARGS; |
| - break; |
| - } |
| + if (threads_.begin() == threads_.end()) { |
| + err = BAD_ARGS; |
| + break; |
| + } |
| - // If we are using "any" get the first thread |
| - if (id == static_cast<uint64_t>(-1)) id = threads_.begin()->first; |
| + // If we are using "any" get the first thread |
| + if (id == static_cast<uint64_t>(-1)) id = threads_.begin()->first; |
| - // Verify that we have the thread |
| - if (threads_.find(static_cast<uint32_t>(id)) == threads_.end()) { |
| - err = BAD_ARGS; |
| - break; |
| - } |
| - |
| - pktOut->AddString("OK"); |
| - switch (type) { |
| - case 'g': |
| - reg_thread_ = static_cast<uint32_t>(id); |
| - break; |
| - |
| - case 'c': |
| - run_thread_ = static_cast<uint32_t>(id); |
| - break; |
| - |
| - default: |
| - err = BAD_ARGS; |
| - break; |
| - } |
| + // Verify that we have the thread |
| + if (threads_.find(static_cast<uint32_t>(id)) == threads_.end()) { |
| + err = BAD_ARGS; |
| break; |
| } |
| - // IN : $maaaa,llll |
| - // OUT: $xx..xx |
| - case 'm': { |
| - uint64_t addr; |
| - uint64_t wlen; |
| - uint32_t len; |
| - if (!pktIn->GetNumberSep(&addr, 0)) { |
| - err = BAD_FORMAT; |
| + pktOut->AddString("OK"); |
| + switch (type) { |
| + case 'g': |
| + reg_req_ = static_cast<uint32_t>(id); |
| break; |
| - } |
| - if (!pktIn->GetNumberSep(&wlen, 0)) { |
| - err = BAD_FORMAT; |
| + case 'c': |
| + run_req_ = static_cast<uint32_t>(id); |
| break; |
| + |
| + default: |
| + err = BAD_ARGS; |
| + break; |
| } |
| + break; |
| + } |
| - len = static_cast<uint32_t>(wlen); |
| - uint8_t *block = new uint8_t[len]; |
| - if (!port::IPlatform::GetMemory(addr, len, block)) err = FAILED; |
| + case 'k': |
| + port::IPlatform::LogError("Process killed by debugger."); |
| + break; |
| - pktOut->AddBlock(block, len); |
| + // IN : $maaaa,llll |
| + // OUT: $xx..xx |
| + case 'm': { |
| + // This packet is requesting a read operation for more than one byte. |
| + uint64_t addr; |
| + uint64_t wlen; |
| + uint32_t len; |
| + if (!pktIn->GetNumberSep(&addr, 0)) { |
| + err = BAD_FORMAT; |
| break; |
| } |
| + if (!pktIn->GetNumberSep(&wlen, 0)) { |
| + err = BAD_FORMAT; |
| + break; |
| + } |
| + |
| + len = static_cast<uint32_t>(wlen); |
| + uint8_t *block = new uint8_t[len]; |
| + if (!port::IPlatform::GetMemory(addr, len, block)) err = FAILED; |
| + |
| + pktOut->AddBlock(block, len); |
| + break; |
| + } |
| + |
| // IN : $Maaaa,llll:xx..xx |
| // OUT: $OK |
| case 'M': { |
| - uint64_t addr; |
| - uint64_t wlen; |
| - uint32_t len; |
| + // This packet is requesting that multiple bytes be overwritten, |
| + // starting at a specific address. |
| + uint64_t addr; |
| + uint64_t wlen; |
| + uint32_t len; |
| - if (!pktIn->GetNumberSep(&addr, 0)) { |
| - err = BAD_FORMAT; |
| - break; |
| - } |
| - if (!pktIn->GetNumberSep(&wlen, 0)) { |
| - err = BAD_FORMAT; |
| - break; |
| - } |
| + if (!pktIn->GetNumberSep(&addr, 0)) { |
| + err = BAD_FORMAT; |
| + break; |
| + } |
| + if (!pktIn->GetNumberSep(&wlen, 0)) { |
| + err = BAD_FORMAT; |
| + break; |
| + } |
| - len = static_cast<uint32_t>(wlen); |
| - uint8_t *block = new uint8_t[len]; |
| - pktIn->GetBlock(block, len); |
| + len = static_cast<uint32_t>(wlen); |
| + uint8_t *block = new uint8_t[len]; |
| + pktIn->GetBlock(block, len); |
| - if (!port::IPlatform::SetMemory(addr, len, block)) err = FAILED; |
| + if (!port::IPlatform::SetMemory(addr, len, block)) err = FAILED; |
| - pktOut->AddString("OK"); |
| - break; |
| - } |
| + pktOut->AddString("OK"); |
| + break; |
| + } |
| case 'q': { |
| + // This packet is carrying out a general query, possibly for supported |
| + // commands and the like. |
| string tmp; |
| const char *str = &pktIn->GetPayload()[1]; |
| - stringvec toks = StringSplit(str, ":;"); |
| - PropertyMap_t::const_iterator itr = properties_.find(toks[0]); |
| + stringvec toks = StringSplit(str, ";"); |
| + std::string strout; |
| + // Check if we can find this query in the local cache |
| + if (MatchQuery(toks[0], &strout)) { |
| + pktOut->AddString(strout.data()); |
| + break; |
| + } |
| + |
| // If this is a thread query |
| if (!strcmp(str, "fThreadInfo") || !strcmp(str, "sThreadInfo")) { |
| uint32_t curr; |
| @@ -502,34 +595,13 @@ |
| break; |
| } |
| - // Check for architecture query |
| - tmp = "Xfer:features:read:target.xml"; |
| - if (!strncmp(str, tmp.data(), tmp.length())) { |
| - stringvec args = StringSplit(&str[tmp.length()+1], ","); |
| - if (args.size() != 2) break; |
| - |
| - const char *out = properties_["target.xml"].data(); |
| - int offs = strtol(args[0].data(), NULL, 16); |
| - int max = strtol(args[1].data(), NULL, 16) + offs; |
| - int len = static_cast<int>(strlen(out)); |
| - |
| - if (max >= len) max = len; |
| - |
| - while (offs < max) { |
| - pktOut->AddRawChar(out[offs]); |
| - offs++; |
| - } |
| - break; |
| - } |
| - |
| - // Check the property cache |
| - if (itr != properties_.end()) { |
| - pktOut->AddString(itr->second.data()); |
| - } |
| + // Didn't find anything |
| break; |
| } |
| case 'T': { |
| + // This packet constitutes a check, whether a given thread is alive or |
| + // dead. |
| uint64_t id; |
| if (!pktIn->GetNumberSep(&id, 0)) { |
| err = BAD_FORMAT; |
| @@ -546,22 +618,18 @@ |
| } |
| case 's': { |
| + // This packet is asking for a thread to step a single instruction |
| IThread *thread = GetThread(GetRunThreadId()); |
| if (thread) thread->SetStep(true); |
| return true; |
| } |
| - case 'c': |
| - return true; |
| - |
| - default: { |
| - // If the command is not recognzied, ignore it by sending an |
| - // empty reply. |
| - string str; |
| - pktIn->GetString(&str); |
| - port::IPlatform::LogError("Unknown command: %s", str.data()); |
| - return false; |
| - } |
| + default: |
| + // If the command is not recognized, ignore it by sending an empty reply. |
| + // Don't use LogError here or the debug stub will crash instead of |
| + // negotiating a protocol with the debugger. |
| + port::IPlatform::LogInfo("Unknown command: %s", pktIn->GetPayload()); |
| + break; |
| } |
| // If there is an error, return the error code instead of a payload |
| @@ -575,19 +643,18 @@ |
| void Target::TrackThread(IThread* thread) { |
| + MutexLock lock(stateMutex_); |
| + |
| uint32_t id = thread->GetId(); |
| - mutex_->Lock(); |
| threads_[id] = thread; |
| - mutex_->Unlock(); |
| } |
| void Target::IgnoreThread(IThread* thread) { |
| + MutexLock lock(stateMutex_); |
| + |
| uint32_t id = thread->GetId(); |
| - mutex_->Lock(); |
| ThreadMap_t::iterator itr = threads_.find(id); |
| - |
| if (itr != threads_.end()) threads_.erase(itr); |
| - mutex_->Lock(); |
| } |
| @@ -597,30 +664,74 @@ |
| uint32_t Target::GetRegThreadId() const { |
| - ThreadMap_t::const_iterator itr; |
| + IThread* thread; |
| + uint32_t id = 0; |
| - switch (reg_thread_) { |
| - // If we wany "any" then try the signal'd thread first |
| + switch (reg_req_) { |
| case 0: |
| case 0xFFFFFFFF: |
| - itr = threads_.begin(); |
| + // If we wany "any" then try the last result first |
| + thread = GetThread(reg_last_); |
| + |
| + // If not there, try the sig_thread next |
| + if (NULL == thread) thread = GetThread(sig_thread_); |
| + |
| + // If stil not there, get the first thread |
| + if (NULL == thread) thread = threads_.begin()->second; |
| break; |
| default: |
| - itr = threads_.find(reg_thread_); |
| + // Otherwise, get the specificly requested one |
| + thread = GetThread(reg_req_); |
| break; |
| } |
| - if (itr == threads_.end()) return 0; |
| + // Update last result. |
| + if (NULL == thread) { |
| + reg_last_ = 0; |
| + } else { |
| + reg_last_ = thread->GetId(); |
| + } |
| - return itr->first; |
| + // Return the result |
| + return reg_last_; |
| } |
| uint32_t Target::GetRunThreadId() const { |
| - return run_thread_; |
| + IThread* thread; |
| + uint32_t id = 0; |
| + |
| + switch (run_req_) { |
| + case 0: |
| + case 0xFFFFFFFF: |
| + // If we wany "any" then try the last result first |
| + thread = GetThread(run_last_); |
| + |
| + // If not there, try the sig_thread next |
| + if (NULL == thread) thread = GetThread(sig_thread_); |
| + |
| + // If stil not there, get the first thread |
| + if (NULL == thread) thread = threads_.begin()->second; |
| + break; |
| + |
| + default: |
| + // Otherwise, get the specificly requested one |
| + thread = GetThread(run_req_); |
| + break; |
| + } |
| + |
| + // Update last result. |
| + if (NULL == thread) { |
| + run_last_ = 0; |
| + } else { |
| + run_last_ = thread->GetId(); |
| + } |
| + |
| + // Return the result |
| + return run_last_; |
| } |
| -IThread* Target::GetThread(uint32_t id) { |
| +IThread* Target::GetThread(uint32_t id) const { |
| ThreadMap_t::const_iterator itr; |
| itr = threads_.find(id); |
| if (itr != threads_.end()) return itr->second; |