Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(534)

Unified Diff: src/trusted/gdb_rsp/target.cc

Issue 5633007: This change contains changes that were made on a separate copy of this code,... (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: '' Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,20 @@
Target::Target(const Abi* abi)
: abi_(abi),
- mutex_(NULL),
+ stateMutex_(NULL),
+ publicMutex_(NULL),
sig_start_(NULL),
sig_done_(NULL),
- send_done_(false),
noelallen_use_chromium 2010/12/13 19:28:10 Why did you remove this? You have an uninitialize
mlinck 2010/12/14 17:23:24 I didn't remove this line. It had been removed in
ctx_(NULL),
cur_signal_(-1),
sig_thread_(0),
- run_thread_(-1),
- reg_thread_(-1) {
- if (NULL == abi_) abi_ = Abi::Get();
+ run_req_(-1),
+ run_last_(0),
+ reg_req_(-1),
+ reg_last_(0) {
+ if (NULL == abi_) {
+ abi_ = Abi::Get();
+ }
}
Target::~Target() {
@@ -51,34 +55,96 @@
}
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();
+ 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_);
+ 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 +152,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 +180,7 @@
}
bool Target::RemoveTemporaryBreakpoints() {
+ MutexLock lock(publicMutex_);
const Abi::BPDef *bp = abi_->GetBreakpointDef();
// Iterate through the map, removing breakpoints
@@ -121,7 +189,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 +202,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
noelallen_use_chromium 2010/12/13 19:28:10 prevent
mlinck 2010/12/14 17:23:24 Done.
+ MutexLock lock(stateMutex_);
noelallen_use_chromium 2010/12/13 19:28:10 This comment and surrounding code is a bit confusi
mlinck 2010/12/14 17:23:24 Thanks for bringing this to my attention. There a
- // 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 +219,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
noelallen_use_chromium 2010/12/13 19:28:10 us
mlinck 2010/12/14 17:23:24 Done.
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 +325,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 +361,6 @@
}
-
bool Target::ProcessPacket(Packet* pktIn, Packet* pktOut) {
char cmd;
int32_t seq = -1;
@@ -319,9 +377,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 +393,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 +427,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 +453,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.
noelallen_use_chromium 2010/12/13 19:28:10 Why more than one byte? It should be legal for 'l
mlinck 2010/12/14 17:23:24 Done.
+ 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.
noelallen_use_chromium 2010/12/13 19:28:10 one or more
mlinck 2010/12/14 17:23:24 Done.
+ 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);
noelallen_use_chromium 2010/12/13 19:28:10 Where is the delete[]? Is this a leak?
mlinck 2010/12/14 17:23:24 Done.
- 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 +588,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 +611,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;
noelallen_use_chromium 2010/12/13 19:28:10 Where is SetStep(false)? Make sure we turn off si
mlinck 2010/12/14 17:23:24 Well, there was a massive bug associated SetStep(f
noelallen_use_chromium 2010/12/14 20:18:41 That seems incorrect. This function should be tur
mlinck 2010/12/16 20:03:01 That is false. I haven't looked closely at how st
}
- 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 +636,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 +657,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;

Powered by Google App Engine
This is Rietveld 408576698