diff options
author | Pedro Alves <palves@redhat.com> | 2012-07-20 17:27:29 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2012-07-20 17:27:29 +0000 |
commit | 64776a0b2d88d40f308304194d26b766bb12b7e3 (patch) | |
tree | f320794b35f6aed58723c26ccbdd281a72d1edb0 /gdb/testsuite/gdb.threads | |
parent | 09826ec59df0c34fb49e483b88436b0ea0a7bb30 (diff) | |
download | fsf-binutils-gdb-64776a0b2d88d40f308304194d26b766bb12b7e3.zip fsf-binutils-gdb-64776a0b2d88d40f308304194d26b766bb12b7e3.tar.gz fsf-binutils-gdb-64776a0b2d88d40f308304194d26b766bb12b7e3.tar.bz2 |
2012-07-20 Pedro Alves <palves@redhat.com>
PR threads/11692
PR gdb/12203
gdb/
* infrun.c (handle_inferior_event) <new thread>: Don't special
case minus_one_ptid.
<TARGET_WAITKIND_SPURIOUS>: Ditto.
* linux-thread-db.c (thread_get_info_callback): Don't return early
if the thread is zombie.
(thread_from_lwp): Change return type to void. Rewrite stale
comment.
(attach_thread): Don't return early if the thread is zombie,
instead set its "dying" flag.
(thread_db_wait): Don't return TARGET_WAITKIND_SPURIOUS anymore.
(find_new_threads_callback): Don't return early if the thread is
zombie.
gdb/testsuite/
* gdb.threads/create-fail.c: New file.
* gdb.threads/create-fail.exp: New file.
Diffstat (limited to 'gdb/testsuite/gdb.threads')
-rw-r--r-- | gdb/testsuite/gdb.threads/create-fail.c | 119 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/create-fail.exp | 53 |
2 files changed, 172 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.threads/create-fail.c b/gdb/testsuite/gdb.threads/create-fail.c new file mode 100644 index 0000000..b926cf5 --- /dev/null +++ b/gdb/testsuite/gdb.threads/create-fail.c @@ -0,0 +1,119 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sched.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <assert.h> + +/* Count the number of tasks/threads in the PID thread group. */ + +static int +count_tasks (pid_t pid) +{ + char path[100]; + int count; + DIR *d; + + snprintf (path, sizeof (path), "/proc/%d/task/", (int) pid); + d = opendir (path); + if (d == NULL) + return -1; + + for (count = 0; readdir (d) != NULL; count++) + ; + closedir (d); + + /* Account for '.' and '..'. */ + assert (count > 2); + return count - 2; +} + +pthread_attr_t attr[CPU_SETSIZE]; +pthread_t thr[CPU_SETSIZE]; + +static void * +mythread (void *_arg) +{ + return NULL; +} + +int +main () +{ + int i; + + for (i = 0; i < CPU_SETSIZE; i++) + { + cpu_set_t set; + int ret; + + pthread_attr_init (&attr[i]); + CPU_ZERO_S (sizeof (set), &set); + CPU_SET_S (i, sizeof (set), &set); + + ret = pthread_attr_setaffinity_np (&attr[i], sizeof (set), &set); + if (ret != 0) + { + fprintf (stderr, "set_affinity: %d: %s\n", ret, strerror (ret)); + exit (3); + } + ret = pthread_create (&thr[i], &attr[i], mythread, NULL); + /* Should fail with EINVAL at some point. */ + if (ret != 0) + { + unsigned long t; + + fprintf (stderr, "pthread_create: %d: %s\n", ret, strerror (ret)); + + /* Wait for all threads to exit. pthread_create spawns a + clone thread even in the failing case, as it can only try + to set the affinity after creating the thread. That new + thread is immediately canceled (because setting the + affinity fails), by killing it with a SIGCANCEL signal, + which may end up in pthread_cancel/unwind paths, which + may trigger a libgcc_s.so load, making the thread hit the + solib-event breakpoint. Now, if we would let the program + exit without waiting, sometimes it would happen that the + inferior exits just while we're handling the solib-event, + resulting in errors being thrown due to failing ptrace + call fails (with ESCHR), breaking the test. */ + t = 16; + while (count_tasks (getpid ()) > 1) + { + usleep (t); + + if (t < 256) + t *= 2; + } + + /* Normal exit, because this is what we are expecting. */ + exit (0); + } + } + + /* Should not normally be reached. */ + exit (1); +} diff --git a/gdb/testsuite/gdb.threads/create-fail.exp b/gdb/testsuite/gdb.threads/create-fail.exp new file mode 100644 index 0000000..0cdacf6 --- /dev/null +++ b/gdb/testsuite/gdb.threads/create-fail.exp @@ -0,0 +1,53 @@ +# Copyright (C) 2012 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 3 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, see <http://www.gnu.org/licenses/>. + +# On GNU/Linux, a creating a thread bound to an unexisting cpu spawns +# the clone child thread for a bit, which is then immediately +# cancelled. The spawned child may trigger a dlopen (for libgcc_s) +# while being cancelled, which results in a trap being reported to +# GDB, for a thread that libthread_db considers to be TD_THR_ZOMBIE. +# Make sure we handle that scenario properly. + +standard_testfile +set executable ${testfile} + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + return -1 +} + +set iterations 10 +for {set i 1} {$i <= $iterations} {incr i} { + with_test_prefix "iteration $i" { + + clean_restart ${executable} + + if ![runto_main] { + return -1 + } + + set test "run till end" + gdb_test_multiple "continue" "$test" { + -re "exited with code 01.*$gdb_prompt $" { + pass "$test" + } + -re "exited with code 02.*$gdb_prompt $" { + unsupported "$test (too many CPUs for test?)" + } + -re "exited normally.*$gdb_prompt $" { + pass "$test" + } + } + } +} |