diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 33 | ||||
-rw-r--r-- | gdb/gdbserver/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/gdbserver/thread-db.c | 18 | ||||
-rw-r--r-- | gdb/linux-nat.c | 65 | ||||
-rw-r--r-- | gdb/linux-nat.h | 16 | ||||
-rw-r--r-- | gdb/linux-thread-db.c | 255 | ||||
-rw-r--r-- | gdb/nat/linux-procfs.c | 13 | ||||
-rw-r--r-- | gdb/nat/linux-procfs.h | 3 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/testsuite/gdb.threads/multi-create-ns-info-thr.exp | 50 |
10 files changed, 291 insertions, 172 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 52a641b..b7a72d9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,38 @@ 2015-02-20 Pedro Alves <palves@redhat.com> + * linux-nat.c (linux_handle_extended_wait): Call + thread_db_notice_clone whenever a new clone LWP is detected. + (linux_stop_and_wait_all_lwps, linux_unstop_all_lwps): New + functions. + * linux-nat.h (thread_db_attach_lwp): Delete declaration. + (thread_db_notice_clone, linux_stop_and_wait_all_lwps) + (linux_unstop_all_lwps): Declare. + * linux-thread-db.c (struct thread_get_info_inout): Delete. + (thread_get_info_callback): Delete. + (thread_from_lwp): Use td_thr_get_info and record_thread. + (thread_db_attach_lwp): Delete. + (thread_db_notice_clone): New function. + (try_thread_db_load_1): If /proc is mounted and shows the + process'es task list, walk over all LWPs and call thread_from_lwp + instead of relying on td_ta_thr_iter. + (attach_thread): Don't call check_thread_signals here. Split the + tail part of the function (which adds the thread to the core GDB + thread list) to ... + (record_thread): ... this function. Call check_thread_signals + here. + (thread_db_wait): Don't call thread_db_find_new_threads_1. Always + call thread_from_lwp. + (thread_db_update_thread_list): Rename to ... + (thread_db_update_thread_list_org): ... this. + (thread_db_update_thread_list): New function. + (thread_db_find_thread_from_tid): Delete. + (thread_db_get_ada_task_ptid): Simplify. + * nat/linux-procfs.c: Include <sys/stat.h>. + (linux_proc_task_list_dir_exists): New function. + * nat/linux-procfs.h (linux_proc_task_list_dir_exists): Declare. + +2015-02-20 Pedro Alves <palves@redhat.com> + * linux-nat.c (lin_lwp_attach_lwp): No longer special case the main LWP. Handle the case of waitpid returning 0 if we're already attached to the LWP. Don't set the LWP's last_resume_kind to diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index cd79d75..cfdb3e7 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,11 @@ 2015-02-20 Pedro Alves <palves@redhat.com> + * thread-db.c: Include "nat/linux-procfs.h". + (thread_db_init): Skip listing new threads if the kernel supports + PTRACE_EVENT_CLONE and /proc/PID/task/ is accessible. + +2015-02-20 Pedro Alves <palves@redhat.com> + * linux-low.c (status_pending_p_callback): Use ptid_match. 2015-02-19 Antoine Tremblay <antoine.tremblay@ericsson.com> diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 2185245..a8b6f42 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -29,6 +29,7 @@ static int thread_db_use_events; #include "gdb_proc_service.h" #include "nat/gdb_thread_db.h" #include "gdb_vecs.h" +#include "nat/linux-procfs.h" #ifndef USE_LIBTHREAD_DB_DIRECTLY #include <dlfcn.h> @@ -859,7 +860,22 @@ thread_db_init (int use_events) thread_db_mourn (proc); return 0; } - thread_db_find_new_threads (); + + /* It's best to avoid td_ta_thr_iter if possible. That walks + data structures in the inferior's address space that may be + corrupted, or, if the target is running, the list may change + while we walk it. In the latter case, it's possible that a + thread exits just at the exact time that causes GDBserver to + get stuck in an infinite loop. If the kernel supports clone + events, and /proc/PID/task/ exits, then we already know about + all threads in the process. When we need info out of + thread_db on a given thread (e.g., for TLS), we'll use + find_one_thread then. That uses thread_db entry points that + do not walk libpthread's thread list, so should be safe, as + well as more efficient. */ + if (use_events + || !linux_proc_task_list_dir_exists (pid_of (proc))) + thread_db_find_new_threads (); thread_db_look_up_symbols (); return 1; } diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index cfde1fd..2e1133d 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -264,6 +264,7 @@ async_file_mark (void) static int kill_lwp (int lwpid, int signo); static int stop_callback (struct lwp_info *lp, void *data); +static int resume_stopped_resumed_lwps (struct lwp_info *lp, void *data); static void block_child_signals (sigset_t *prev_mask); static void restore_child_signals_mask (sigset_t *prev_mask); @@ -2003,34 +2004,24 @@ linux_handle_extended_wait (struct lwp_info *lp, int status, status = 0; } - if (non_stop) + /* If the thread_db layer is active, let it record the user + level thread id and status, and add the thread to GDB's + list. */ + if (!thread_db_notice_clone (lp->ptid, new_lp->ptid)) { - /* Add the new thread to GDB's lists as soon as possible - so that: - - 1) the frontend doesn't have to wait for a stop to - display them, and, - - 2) we tag it with the correct running state. */ - - /* If the thread_db layer is active, let it know about - this new thread, and add it to GDB's list. */ - if (!thread_db_attach_lwp (new_lp->ptid)) - { - /* We're not using thread_db. Add it to GDB's - list. */ - target_post_attach (ptid_get_lwp (new_lp->ptid)); - add_thread (new_lp->ptid); - } + /* The process is not using thread_db. Add the LWP to + GDB's list. */ + target_post_attach (ptid_get_lwp (new_lp->ptid)); + add_thread (new_lp->ptid); + } - if (!stopping) - { - set_running (new_lp->ptid, 1); - set_executing (new_lp->ptid, 1); - /* thread_db_attach_lwp -> lin_lwp_attach_lwp forced - resume_stop. */ - new_lp->last_resume_kind = resume_continue; - } + if (!stopping) + { + set_running (new_lp->ptid, 1); + set_executing (new_lp->ptid, 1); + /* thread_db_attach_lwp -> lin_lwp_attach_lwp forced + resume_stop. */ + new_lp->last_resume_kind = resume_continue; } if (status != 0) @@ -2285,6 +2276,28 @@ linux_stop_lwp (struct lwp_info *lwp) stop_callback (lwp, NULL); } +/* See linux-nat.h */ + +void +linux_stop_and_wait_all_lwps (void) +{ + /* Stop all LWP's ... */ + iterate_over_lwps (minus_one_ptid, stop_callback, NULL); + + /* ... and wait until all of them have reported back that + they're no longer running. */ + iterate_over_lwps (minus_one_ptid, stop_wait_callback, NULL); +} + +/* See linux-nat.h */ + +void +linux_unstop_all_lwps (void) +{ + iterate_over_lwps (minus_one_ptid, + resume_stopped_resumed_lwps, &minus_one_ptid); +} + /* Return non-zero if LWP PID has a pending SIGINT. */ static int diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index 669450d..8c2ceb5 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -142,7 +142,12 @@ extern struct lwp_info *lwp_list; /* Attempt to initialize libthread_db. */ void check_for_thread_db (void); -int thread_db_attach_lwp (ptid_t ptid); +/* Called from the LWP layer to inform the thread_db layer that PARENT + spawned CHILD. Both LWPs are currently stopped. This function + does whatever is required to have the child LWP under the + thread_db's control --- e.g., enabling event reporting. Returns + true on success, false if the process isn't using libpthread. */ +extern int thread_db_notice_clone (ptid_t parent, ptid_t child); /* Return the set of signals used by the threads library. */ extern void lin_thread_get_thread_signals (sigset_t *mask); @@ -155,6 +160,15 @@ extern int lin_lwp_attach_lwp (ptid_t ptid); extern void linux_stop_lwp (struct lwp_info *lwp); +/* Stop all LWPs, synchronously. (Any events that trigger while LWPs + are being stopped are left pending.) */ +extern void linux_stop_and_wait_all_lwps (void); + +/* Set resumed LWPs running again, as they were before being stopped + with linux_stop_and_wait_all_lwps. (LWPS with pending events are + left stopped.) */ +extern void linux_unstop_all_lwps (void); + /* Iterator function for lin-lwp's lwp list. */ struct lwp_info *iterate_over_lwps (ptid_t filter, int (*callback) (struct lwp_info *, diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index 60d8742..f09685e 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -217,6 +217,13 @@ struct thread_db_info *thread_db_list; static void thread_db_find_new_threads_1 (ptid_t ptid); static void thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new); +static void check_thread_signals (void); + +static void record_thread (struct thread_db_info *info, + struct thread_info *tp, + ptid_t ptid, const td_thrhandle_t *th_p, + const td_thrinfo_t *ti_p); + /* Add the current inferior to the list of processes using libpthread. Return a pointer to the newly allocated object that was added to THREAD_DB_LIST. HANDLE is the handle returned by dlopen'ing @@ -398,64 +405,6 @@ have_threads (ptid_t ptid) return iterate_over_threads (have_threads_callback, &pid) != NULL; } -struct thread_get_info_inout -{ - struct thread_info *thread_info; - struct thread_db_info *thread_db_info; -}; - -/* A callback function for td_ta_thr_iter, which we use to map all - threads to LWPs. - - THP is a handle to the current thread; if INFOP is not NULL, the - struct thread_info associated with this thread is returned in - *INFOP. - - If the thread is a zombie, TD_THR_ZOMBIE is returned. Otherwise, - zero is returned to indicate success. */ - -static int -thread_get_info_callback (const td_thrhandle_t *thp, void *argp) -{ - td_thrinfo_t ti; - td_err_e err; - ptid_t thread_ptid; - struct thread_get_info_inout *inout; - struct thread_db_info *info; - - inout = argp; - info = inout->thread_db_info; - - err = info->td_thr_get_info_p (thp, &ti); - if (err != TD_OK) - error (_("thread_get_info_callback: cannot get thread info: %s"), - thread_db_err_str (err)); - - if (ti.ti_lid == -1) - { - /* We'll get this if a threaded program has a thread call clone - with CLONE_VM. `clone' sets the pthread LID of the new LWP - to -1, which ends up clearing the parent thread's LID. */ - return 0; - } - - /* Fill the cache. */ - thread_ptid = ptid_build (info->pid, ti.ti_lid, 0); - inout->thread_info = find_thread_ptid (thread_ptid); - - if (inout->thread_info == NULL) - { - /* New thread. Attach to it now (why wait?). */ - if (!have_threads (thread_ptid)) - thread_db_find_new_threads_1 (thread_ptid); - else - attach_thread (thread_ptid, thp, &ti); - inout->thread_info = find_thread_ptid (thread_ptid); - gdb_assert (inout->thread_info != NULL); - } - - return 0; -} /* Fetch the user-level thread id of PTID. */ @@ -463,9 +412,10 @@ static void thread_from_lwp (ptid_t ptid) { td_thrhandle_t th; + td_thrinfo_t ti; td_err_e err; struct thread_db_info *info; - struct thread_get_info_inout io = {0}; + struct thread_info *tp; /* Just in case td_ta_map_lwp2thr doesn't initialize it completely. */ th.th_unique = 0; @@ -484,56 +434,37 @@ thread_from_lwp (ptid_t ptid) error (_("Cannot find user-level thread for LWP %ld: %s"), ptid_get_lwp (ptid), thread_db_err_str (err)); - /* Long-winded way of fetching the thread info. */ - io.thread_db_info = info; - io.thread_info = NULL; - thread_get_info_callback (&th, &io); + err = info->td_thr_get_info_p (&th, &ti); + if (err != TD_OK) + error (_("thread_get_info_callback: cannot get thread info: %s"), + thread_db_err_str (err)); + + /* Fill the cache. */ + tp = find_thread_ptid (ptid); + record_thread (info, tp, ptid, &th, &ti); } -/* Attach to lwp PTID, doing whatever else is required to have this - LWP under the debugger's control --- e.g., enabling event - reporting. Returns true on success. */ +/* See linux-nat.h. */ + int -thread_db_attach_lwp (ptid_t ptid) +thread_db_notice_clone (ptid_t parent, ptid_t child) { td_thrhandle_t th; td_thrinfo_t ti; td_err_e err; struct thread_db_info *info; - info = get_thread_db_info (ptid_get_pid (ptid)); + info = get_thread_db_info (ptid_get_pid (child)); if (info == NULL) return 0; - /* This ptid comes from linux-nat.c, which should always fill in the - LWP. */ - gdb_assert (ptid_get_lwp (ptid) != 0); + thread_from_lwp (child); - /* Access an lwp we know is stopped. */ - info->proc_handle.ptid = ptid; - - /* If we have only looked at the first thread before libpthread was - initialized, we may not know its thread ID yet. Make sure we do - before we add another thread to the list. */ - if (!have_threads (ptid)) - thread_db_find_new_threads_1 (ptid); - - err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid_get_lwp (ptid), - &th); - if (err != TD_OK) - /* Cannot find user-level thread. */ - return 0; - - err = info->td_thr_get_info_p (&th, &ti); - if (err != TD_OK) - { - warning (_("Cannot get thread info: %s"), thread_db_err_str (err)); - return 0; - } - - attach_thread (ptid, &th, &ti); + /* If we do not know about the main thread yet, this would be a good + time to find it. */ + thread_from_lwp (parent); return 1; } @@ -821,7 +752,30 @@ try_thread_db_load_1 (struct thread_db_info *info) info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr"); info->td_thr_tlsbase_p = dlsym (info->handle, "td_thr_tlsbase"); - if (thread_db_find_new_threads_silently (inferior_ptid) != 0) + /* It's best to avoid td_ta_thr_iter if possible. That walks data + structures in the inferior's address space that may be corrupted, + or, if the target is running, may change while we walk them. If + there's execution (and /proc is mounted), then we're already + attached to all LWPs. Use thread_from_lwp, which uses + td_ta_map_lwp2thr instead, which does not walk the thread list. + + td_ta_map_lwp2thr uses ps_get_thread_area, but we can't use that + currently on core targets, as it uses ptrace directly. */ + if (target_has_execution + && linux_proc_task_list_dir_exists (ptid_get_pid (inferior_ptid))) + { + struct lwp_info *lp; + int pid = ptid_get_pid (inferior_ptid); + + linux_stop_and_wait_all_lwps (); + + ALL_LWPS (lp) + if (ptid_get_pid (lp->ptid) == pid) + thread_from_lwp (lp->ptid); + + linux_unstop_all_lwps (); + } + else if (thread_db_find_new_threads_silently (inferior_ptid) != 0) { /* Even if libthread_db initializes, if the thread list is corrupted, we'd not manage to list any threads. Better reject this @@ -1302,9 +1256,7 @@ static int attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, const td_thrinfo_t *ti_p) { - struct private_thread_info *private; struct thread_info *tp; - td_err_e err; struct thread_db_info *info; /* If we're being called after a TD_CREATE event, we may already @@ -1337,9 +1289,6 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, } } - if (target_has_execution) - check_thread_signals (); - /* Under GNU/Linux, we have to attach to each and every thread. */ if (target_has_execution && tp == NULL) @@ -1363,31 +1312,48 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, /* Otherwise, we sucessfully attached to the thread. */ } + info = get_thread_db_info (ptid_get_pid (ptid)); + record_thread (info, tp, ptid, th_p, ti_p); + return 1; +} + +/* Record a new thread in GDB's thread list. Creates the thread's + private info. If TP is NULL, creates a new thread. Otherwise, + uses TP. */ + +static void +record_thread (struct thread_db_info *info, + struct thread_info *tp, + ptid_t ptid, const td_thrhandle_t *th_p, + const td_thrinfo_t *ti_p) +{ + td_err_e err; + struct private_thread_info *private; + int new_thread = (tp == NULL); + + /* A thread ID of zero may mean the thread library has not + initialized yet. Leave private == NULL until the thread library + has initialized. */ + if (ti_p->ti_tid == 0) + return; + /* Construct the thread's private data. */ private = xmalloc (sizeof (struct private_thread_info)); memset (private, 0, sizeof (struct private_thread_info)); - /* A thread ID of zero may mean the thread library has not initialized - yet. But we shouldn't even get here if that's the case. FIXME: - if we change GDB to always have at least one thread in the thread - list this will have to go somewhere else; maybe private == NULL - until the thread_db target claims it. */ - gdb_assert (ti_p->ti_tid != 0); private->th = *th_p; private->tid = ti_p->ti_tid; update_thread_state (private, ti_p); /* Add the thread to GDB's thread list. */ if (tp == NULL) - add_thread_with_info (ptid, private); + tp = add_thread_with_info (ptid, private); else tp->private = private; - info = get_thread_db_info (ptid_get_pid (ptid)); - /* Enable thread event reporting for this thread, except when debugging a core file. */ - if (target_has_execution && thread_db_use_events ()) + if (target_has_execution && thread_db_use_events () && new_thread) { err = info->td_thr_event_enable_p (th_p, 1); if (err != TD_OK) @@ -1395,7 +1361,8 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p, target_pid_to_str (ptid), thread_db_err_str (err)); } - return 1; + if (target_has_execution) + check_thread_signals (); } static void @@ -1581,21 +1548,13 @@ thread_db_wait (struct target_ops *ops, return ptid; } - /* If we do not know about the main thread yet, this would be a good time to - find it. */ - if (ourstatus->kind == TARGET_WAITKIND_STOPPED && !have_threads (ptid)) - thread_db_find_new_threads_1 (ptid); - if (ourstatus->kind == TARGET_WAITKIND_STOPPED && ourstatus->value.sig == GDB_SIGNAL_TRAP) /* Check for a thread event. */ check_event (ptid); - if (have_threads (ptid)) - { - /* Fill in the thread's user-level thread id. */ - thread_from_lwp (ptid); - } + /* Fill in the thread's user-level thread id and status. */ + thread_from_lwp (ptid); return ptid; } @@ -1727,6 +1686,9 @@ find_new_threads_once (struct thread_db_info *info, int iteration, data.info = info; data.new_threads = 0; + /* See comment in thread_db_update_thread_list. */ + gdb_assert (!target_has_execution || thread_db_use_events ()); + TRY_CATCH (except, RETURN_MASK_ERROR) { /* Iterate over all user-space threads to discover new threads. */ @@ -1805,8 +1767,10 @@ update_thread_core (struct lwp_info *info, void *closure) return 0; } +/* Update the thread list using td_ta_thr_iter. */ + static void -thread_db_update_thread_list (struct target_ops *ops) +thread_db_update_thread_list_td_ta_thr_iter (struct target_ops *ops) { struct thread_db_info *info; struct inferior *inf; @@ -1830,6 +1794,29 @@ thread_db_update_thread_list (struct target_ops *ops) thread_db_find_new_threads_1 (thread->ptid); } +} + +/* Implement the to_update_thread_list target method for this + target. */ + +static void +thread_db_update_thread_list (struct target_ops *ops) +{ + /* It's best to avoid td_ta_thr_iter if possible. That walks data + structures in the inferior's address space that may be corrupted, + or, if the target is running, the list may change while we walk + it. In the latter case, it's possible that a thread exits just + at the exact time that causes GDB to get stuck in an infinite + loop. To avoid pausing all threads whenever the core wants to + refresh the thread list, if the kernel supports clone events + (meaning we're always already attached to all LWPs), we use + thread_from_lwp immediately when we see an LWP stop. That uses + thread_db entry points that do not walk libpthread's thread list, + so should be safe, as well as more efficient. */ + if (target_has_execution && !thread_db_use_events ()) + ops->beneath->to_update_thread_list (ops->beneath); + else + thread_db_update_thread_list_td_ta_thr_iter (ops); if (target_has_execution) iterate_over_lwps (minus_one_ptid /* iterate over all */, @@ -1962,33 +1949,13 @@ thread_db_get_thread_local_address (struct target_ops *ops, return beneath->to_get_thread_local_address (beneath, ptid, lm, offset); } -/* Callback routine used to find a thread based on the TID part of - its PTID. */ - -static int -thread_db_find_thread_from_tid (struct thread_info *thread, void *data) -{ - long *tid = (long *) data; - - if (thread->private->tid == *tid) - return 1; - - return 0; -} - /* Implement the to_get_ada_task_ptid target method for this target. */ static ptid_t thread_db_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) { - struct thread_info *thread_info; - - thread_db_find_new_threads_1 (inferior_ptid); - thread_info = iterate_over_threads (thread_db_find_thread_from_tid, &thread); - - gdb_assert (thread_info != NULL); - - return (thread_info->ptid); + /* NPTL uses a 1:1 model, so the LWP id suffices. */ + return ptid_build (ptid_get_pid (inferior_ptid), lwp, 0); } static void diff --git a/gdb/nat/linux-procfs.c b/gdb/nat/linux-procfs.c index 5dd2b92..1e922b9 100644 --- a/gdb/nat/linux-procfs.c +++ b/gdb/nat/linux-procfs.c @@ -20,6 +20,7 @@ #include "linux-procfs.h" #include "filestuff.h" #include <dirent.h> +#include <sys/stat.h> /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not found. */ @@ -251,3 +252,15 @@ linux_proc_attach_tgid_threads (pid_t pid, closedir (dir); } + +/* See linux-procfs.h. */ + +int +linux_proc_task_list_dir_exists (pid_t pid) +{ + char pathname[128]; + struct stat buf; + + xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid); + return (stat (pathname, &buf) == 0); +} diff --git a/gdb/nat/linux-procfs.h b/gdb/nat/linux-procfs.h index 6f2a404..979ae0d 100644 --- a/gdb/nat/linux-procfs.h +++ b/gdb/nat/linux-procfs.h @@ -68,4 +68,7 @@ typedef int (*linux_proc_attach_lwp_func) (ptid_t ptid); extern void linux_proc_attach_tgid_threads (pid_t pid, linux_proc_attach_lwp_func func); +/* Return true if the /proc/PID/task/ directory exists. */ +extern int linux_proc_task_list_dir_exists (pid_t pid); + #endif /* COMMON_LINUX_PROCFS_H */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 050f98c..2ea6940 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2015-02-20 Pedro Alves <palves@redhat.com> + * gdb.threads/multi-create-ns-info-thr.exp: New file. + +2015-02-20 Pedro Alves <palves@redhat.com> + * gdb.trace/no-attach-trace.exp: Don't run to main. Do clean_restart before gdb_target_supports_trace. diff --git a/gdb/testsuite/gdb.threads/multi-create-ns-info-thr.exp b/gdb/testsuite/gdb.threads/multi-create-ns-info-thr.exp new file mode 100644 index 0000000..906532e --- /dev/null +++ b/gdb/testsuite/gdb.threads/multi-create-ns-info-thr.exp @@ -0,0 +1,50 @@ +# Copyright (C) 2007-2015 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/>. + +# Test running "info threads" while threads are being created and +# exiting, in non-stop mode. Originally based on multi-create.exp. + +standard_testfile multi-create.c + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} { + return -1 +} + +gdb_test_no_output "set pagination off" +gdb_test_no_output "set non-stop on" + +runto_main + +# Create a breakpoint that does "info threads" when hit, which will be +# just while other threads are being created or exiting. +set bp_location1 [gdb_get_line_number "set breakpoint 1 here"] +gdb_breakpoint $srcfile:$bp_location1 +gdb_test "commands\ninfo threads\ncontinue&\nend" ".*" "set breakpoint commands" + +set test "continue -a&" +gdb_test_multiple $test $test { + -re "$gdb_prompt " { + pass $test + } +} + +for {set i 0} {$i < 32} {incr i} { + set test "continue to breakpoint $i" + gdb_test_multiple "" $test { + -re "Breakpoint $decimal,.*$srcfile:$bp_location1" { + pass $test + } + } +} |