bool wait_thread_main()
{
Report.Debug (DebugFlags.Wait, "Wait thread sleeping");
wait_event.WaitOne ();
waiting = true;
again:
Report.Debug (DebugFlags.Wait, "Wait thread again");
int pid = 0, status = 0;
if (abort_requested) {
Report.Debug (DebugFlags.Wait,
"Wait thread abort requested");
//
// Reap all our children.
//
do {
Report.Debug (DebugFlags.Wait,
"Wait thread reaping children");
pid = mono_debugger_server_global_wait (out status);
Report.Debug (DebugFlags.Wait,
"Wait thread received event: {0} {1:x}",
pid, status);
} while (pid > 0);
Report.Debug (DebugFlags.Wait,
"Wait thread done");
return false;
}
if (DateTime.Now - last_pending_sigstop > new TimeSpan (0, 2, 30)) {
foreach (int pending in pending_sigstops.Keys) {
Report.Error ("Got SIGSTOP from unknown PID {0}!", pending);
}
pending_sigstops.Clear ();
last_pending_sigstop = DateTime.Now;
}
Report.Debug (DebugFlags.Wait, "Wait thread waiting");
//
// Wait until we got an event from the target or a command from the user.
//
pid = mono_debugger_server_global_wait (out status);
Report.Debug (DebugFlags.Wait,
"Wait thread received event: {0} {1:x}",
pid, status);
//
// Note: `pid' is basically just an unique number which identifies the
// SingleSteppingEngine of this event.
//
if (abort_requested || (pid <= 0))
return true;
if(!Inferior.HasThreadEvents)
{
int arg;
Inferior.ChildEventType etype = mono_debugger_server_dispatch_simple (status, out arg);
SingleSteppingEngine engine = (SingleSteppingEngine) thread_hash [pid];
if(etype == Inferior.ChildEventType.CHILD_EXITED) {
if(engine != null) {
SingleSteppingEngine[] sses = new SingleSteppingEngine [thread_hash.Count];
thread_hash.Values.CopyTo (sses, 0);
foreach(SingleSteppingEngine sse in sses)
sse.ProcessEvent (status);
Dispose();
waiting = false;
return true;
}
else
goto again;
}
if (engine == null) {
SingleSteppingEngine[] sses = new SingleSteppingEngine [thread_hash.Count];
thread_hash.Values.CopyTo (sses, 0);
Inferior inferior = sses[0].Inferior;
inferior.Process.ThreadCreated (inferior, pid, false, true);
goto again;
}
ArrayList check_threads = new ArrayList();
bool got_threads = true;
foreach(Process process in processes)
got_threads = got_threads && process.CheckForThreads(check_threads);
if(got_threads) {
int[] lwps = new int [thread_hash.Count];
thread_hash.Keys.CopyTo (lwps, 0);
foreach(int lwp in lwps) {
if(!check_threads.Contains(lwp)) {
SingleSteppingEngine old_engine = (SingleSteppingEngine) thread_hash [lwp];
thread_hash.Remove (old_engine.PID);
engine_hash.Remove (old_engine.ID);
old_engine.Process.OnThreadExitedEvent (old_engine);
old_engine.Dispose ();
}
}
}
}
SingleSteppingEngine event_engine = (SingleSteppingEngine) thread_hash [pid];
if (event_engine == null && Inferior.HasThreadEvents) {
int arg;
Inferior.ChildEventType etype = mono_debugger_server_dispatch_simple (status, out arg);
/*
* Ignore exit events from unknown children.
*/
if ((etype == Inferior.ChildEventType.CHILD_EXITED) && (arg == 0))
goto again;
/*
* There is a race condition in the Linux kernel which shows up on >= 2.6.27:
*
* When creating a new thread, the initial stopping event of that thread is sometimes
* sent before sending the `PTRACE_EVENT_CLONE' for it.
*
* Because of this, we explicitly wait for the new thread to stop and ignore any
* "early" stopping signals.
*
* See also the comments in _server_ptrace_wait_for_new_thread() in x86-linux-ptrace.c
* and bugs #423518 and #466012.
*
*/
if ((etype != Inferior.ChildEventType.CHILD_STOPPED) || (arg != 0)) {
Report.Error ("WARNING: Got event {0:x} for unknown pid {1}", status, pid);
waiting = false;
RequestWait ();
return true;
}
if (!pending_sigstops.ContainsKey (pid))
pending_sigstops.Add (pid, DateTime.Now);
Report.Debug (DebugFlags.Wait, "Ignoring SIGSTOP from unknown pid {0}.", pid);
goto again;
}
engine_event.WaitOne ();
event_queue.Lock ();
engine_event.Reset ();
if (current_event != null) {
Console.WriteLine ("Current_event is not null: {0}", Environment.StackTrace);
throw new InternalError ();
}
current_event = event_engine;
current_event_status = status;
waiting = false;
event_queue.Signal ();
event_queue.Unlock ();
return true;
}