* linux-nat.c (struct simple_pid_list): Add status.

(add_to_pid_list): Record the PID's status.
	(linux_record_stopped_pid): Likewise.  Make static.
	(pull_pid_from_list): Return the saved status.
	(linux_nat_handle_extended): Deleted.
	(linux_handle_extended_wait): Combine with linux_nat_handle_extended.
	Make static.  Handle non-SIGSTOP for a new thread's first signal.
	(flush_callback): Handle unexpected pending signals.
	(linux_nat_wait): Update calls to changed functions.
	* linux-nat.h (linux_record_stopped_pid, linux_handle_extended_wait):
	Remove prototypes for newly static functions.

	* gdb.threads/sigthread.c, gdb.threads/sigthread.exp: New.
This commit is contained in:
Daniel Jacobowitz
2007-01-08 21:09:47 +00:00
parent 9acbedc0c0
commit 3d799a9542
6 changed files with 257 additions and 102 deletions

View File

@@ -0,0 +1,67 @@
/* Test case for C-c sent to threads with pending signals. Before I
even get there, creating a thread and sending it a signal before it
has a chance to run leads to an internal error in GDB. We need to
record that there's a pending SIGSTOP, so that we'll ignore it
later, and pass the current signal back to the thread.
The fork/vfork case has similar trouble but that's even harder
to get around. We may need to send a SIGCONT to cancel out the
SIGSTOP. Different kernels may do different things if the thread
is stopped by ptrace and sent a SIGSTOP. */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
/* Loop long enough for GDB to send a few signals of its own, but
don't hang around eating CPU forever if something goes wrong during
testing. */
#define NSIGS 1000000
void
handler (int sig)
{
;
}
pthread_t main_thread;
pthread_t child_thread, child_thread_two;
void *
child_two (void *arg)
{
int i;
for (i = 0; i < NSIGS; i++)
pthread_kill (child_thread, SIGUSR1);
}
void *
thread_function (void *arg)
{
int i;
for (i = 0; i < NSIGS; i++)
pthread_kill (child_thread_two, SIGUSR2);
}
int main()
{
int i;
signal (SIGUSR1, handler);
signal (SIGUSR2, handler);
main_thread = pthread_self ();
pthread_create (&child_thread, NULL, thread_function, NULL);
pthread_create (&child_thread_two, NULL, child_two, NULL);
for (i = 0; i < NSIGS; i++)
pthread_kill (child_thread_two, SIGUSR1);
pthread_join (child_thread, NULL);
exit (0);
}

View File

@@ -0,0 +1,56 @@
# sigthread.exp -- Expect script to test thread and signal interaction
# Copyright (C) 2007 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
set testfile sigthread
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
executable { debug }] != "" } {
return -1
}
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
if ![runto_main] then {
fail "Can't run to main"
return 0
}
gdb_test "handle SIGUSR1 nostop noprint pass"
gdb_test "handle SIGUSR2 nostop noprint pass"
send_gdb "continue\n"
gdb_expect {
-re "Continuing" {
pass "continue"
}
timeout {
fail "continue (timeout)"
}
}
# For this to work we must be sure to consume the "Continuing."
# message first, or GDB's signal handler may not be in place.
after 500 {send_gdb "\003"}
# Make sure we do not get an internal error from hitting Control-C
# while many signals are flying back and forth.
gdb_test "" "Program received signal SIGINT.*" "stop with control-c"