waitpid_queue = new_event;
}
-/* Drain all queued event of PID. If PID is -1, the effect is of
+/* Drain all queued events of PID. If PID is -1, the effect is of
draining all events. */
static void
drain_queued_events (int pid)
static int stop_wait_callback (struct lwp_info *lp, void *data);
static int linux_nat_thread_alive (ptid_t ptid);
static char *linux_child_pid_to_exec_file (int pid);
+static int cancel_breakpoint (struct lwp_info *lp);
+
\f
/* Convert wait status STATUS to a string. Used for printing debug
messages only. */
pid_t pid;
int status;
int cloned = 0;
+ int options = 0;
/* FIXME: We should probably accept a list of process id's, and
attach all of them. */
/* Make sure the initial process is stopped. The user-level threads
layer might want to poke around in the inferior, and that won't
work if things haven't stabilized yet. */
- pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
+ pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
if (pid == -1 && errno == ECHILD)
{
warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
/* Try again with __WCLONE to check cloned processes. */
- pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
+ options = __WCLONE;
+ pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
cloned = 1;
}
lp->cloned = cloned;
lp->stopped = 1;
-
- /* Fake the SIGSTOP that core GDB expects. */
- lp->status = W_STOPCODE (SIGSTOP);
lp->resumed = 1;
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
- if (target_can_async_p ())
+
+ if (!target_can_async_p ())
{
- /* Wake event loop with special token, to get to WFI. */
- linux_nat_event_pipe_push (-1, -1, -1);
+ /* Fake the SIGSTOP that core GDB expects. */
+ lp->status = W_STOPCODE (SIGSTOP);
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+ }
+ else
+ {
+ /* We already waited for this LWP, so put the wait result on the
+ pipe. The event loop will wake up and gets us to handling
+ this event. */
+ linux_nat_event_pipe_push (pid, status, options);
/* Register in the event loop. */
target_async (inferior_event_handler, 0);
}
other threads. This bit of code needs to be synchronized
with linux_nat_wait. */
+ /* In async mode, we never have pending wait status. */
+ if (target_can_async_p () && lp->status)
+ internal_error (__FILE__, __LINE__, "Pending status in async mode");
+
if (lp->status && WIFSTOPPED (lp->status))
{
int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
"LLR: Short circuiting for status 0x%x\n",
lp->status);
- if (target_can_async_p ())
- {
- /* Wake event loop with special token, to get to WFI. */
- linux_nat_event_pipe_push (-1, -1, -1);
-
- target_async (inferior_event_handler, 0);
- }
return;
}
"SWC: Candidate SIGTRAP event in %s\n",
target_pid_to_str (lp->ptid));
}
- /* Hold the SIGTRAP for handling by linux_nat_wait. */
+ /* Hold this event/waitstatus while we check to see if
+ there are any more (we still want to get that SIGSTOP). */
stop_wait_callback (lp, data);
- /* If there's another event, throw it back into the queue. */
- if (lp->status)
+
+ if (target_can_async_p ())
{
- if (debug_linux_nat)
+ /* Don't leave a pending wait status in async mode.
+ Retrigger the breakpoint. */
+ if (!cancel_breakpoint (lp))
{
- fprintf_unfiltered (gdb_stdlog,
- "SWC: kill %s, %s\n",
- target_pid_to_str (lp->ptid),
- status_to_str ((int) status));
+ /* There was no gdb breakpoint set at pc. Put
+ the event back in the queue. */
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: kill %s, %s\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str ((int) status));
+ kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
}
- kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
}
- /* Save the sigtrap event. */
- lp->status = status;
+ else
+ {
+ /* Hold the SIGTRAP for handling by
+ linux_nat_wait. */
+ /* If there's another event, throw it back into the
+ queue. */
+ if (lp->status)
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "SWC: kill %s, %s\n",
+ target_pid_to_str (lp->ptid),
+ status_to_str ((int) status));
+ kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+ }
+ /* Save the sigtrap event. */
+ lp->status = status;
+ }
return 0;
}
else
/* Hold this event/waitstatus while we check to see if
there are any more (we still want to get that SIGSTOP). */
stop_wait_callback (lp, data);
- /* If the lp->status field is still empty, use it to hold
- this event. If not, then this event must be returned
- to the event queue of the LWP. */
- if (lp->status == 0)
- lp->status = status;
- else
+
+ /* If the lp->status field is still empty, use it to
+ hold this event. If not, then this event must be
+ returned to the event queue of the LWP. */
+ if (lp->status || target_can_async_p ())
{
if (debug_linux_nat)
{
}
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
}
+ else
+ lp->status = status;
return 0;
}
}
return 0;
}
+static int
+cancel_breakpoint (struct lwp_info *lp)
+{
+ /* Arrange for a breakpoint to be hit again later. We don't keep
+ the SIGTRAP status and don't forward the SIGTRAP signal to the
+ LWP. We will handle the current event, eventually we will resume
+ this LWP, and this breakpoint will trap again.
+
+ If we do not do this, then we run the risk that the user will
+ delete or disable the breakpoint, but the LWP will have already
+ tripped on it. */
+
+ if (breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
+ gdbarch_decr_pc_after_break
+ (current_gdbarch)))
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "CB: Push back breakpoint for %s\n",
+ target_pid_to_str (lp->ptid));
+
+ /* Back up the PC if necessary. */
+ if (gdbarch_decr_pc_after_break (current_gdbarch))
+ write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
+ (current_gdbarch),
+ lp->ptid);
+ return 1;
+ }
+ return 0;
+}
+
static int
cancel_breakpoints_callback (struct lwp_info *lp, void *data)
{
if (lp->status != 0
&& WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
- && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
- gdbarch_decr_pc_after_break
- (current_gdbarch)))
- {
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "CBC: Push back breakpoint for %s\n",
- target_pid_to_str (lp->ptid));
-
- /* Back up the PC if necessary. */
- if (gdbarch_decr_pc_after_break (current_gdbarch))
- write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
- (current_gdbarch),
- lp->ptid);
-
- /* Throw away the SIGTRAP. */
- lp->status = 0;
- }
+ && cancel_breakpoint (lp))
+ /* Throw away the SIGTRAP. */
+ lp->status = 0;
return 0;
}
while (linux_nat_num_queued_events)
{
int lwpid, status, options;
-
lwpid = linux_nat_event_pipe_pop (&status, &options);
- if (lwpid == -1 && status == -1 && options == -1)
- /* Special wake up event loop token. */
- continue;
-
gdb_assert (lwpid > 0);
push_waitpid (lwpid, status, options);
}
lp = iterate_over_lwps (status_callback, NULL);
if (lp)
{
+ if (target_can_async_p ())
+ internal_error (__FILE__, __LINE__,
+ "Found an LWP with a pending status in async mode.");
+
status = lp->status;
lp->status = 0;