X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fthread.c;h=3e7d6e14bf740a4d9b28972a6c279961e318f8ec;hb=c04da66c264162e6efc37686c0e4ee46c5b048ab;hp=d499400544929e9158adf89868af7a3831344e45;hpb=9dccd06e8a4e55adb58d8ebe7f2ed7d9d7dc17de;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/thread.c b/gdb/thread.c index d499400544..3e7d6e14bf 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1,6 +1,6 @@ /* Multi-process/thread control for GDB, the GNU debugger. - Copyright (C) 1986-2020 Free Software Foundation, Inc. + Copyright (C) 1986-2021 Free Software Foundation, Inc. Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA. @@ -58,29 +58,6 @@ static int highest_thread_num; /* The current/selected thread. */ static thread_info *current_thread_; -/* RAII type used to increase / decrease the refcount of each thread - in a given list of threads. */ - -class scoped_inc_dec_ref -{ -public: - explicit scoped_inc_dec_ref (const std::vector &thrds) - : m_thrds (thrds) - { - for (thread_info *thr : m_thrds) - thr->incref (); - } - - ~scoped_inc_dec_ref () - { - for (thread_info *thr : m_thrds) - thr->decref (); - } - -private: - const std::vector &m_thrds; -}; - /* Returns true if THR is the current thread. */ static bool @@ -205,9 +182,9 @@ clear_thread_inferior_resources (struct thread_info *tp) static void set_thread_exited (thread_info *tp, bool silent) { - /* Dead threads don't need to step-over. Remove from queue. */ + /* Dead threads don't need to step-over. Remove from chain. */ if (tp->step_over_next != NULL) - thread_step_over_chain_remove (tp); + global_thread_step_over_chain_remove (tp); if (tp->state != THREAD_EXITED) { @@ -269,6 +246,8 @@ new_thread (struct inferior *inf, ptid_t ptid) struct thread_info * add_thread_silent (process_stratum_target *targ, ptid_t ptid) { + gdb_assert (targ != nullptr); + inferior *inf = find_inferior_ptid (targ, ptid); /* We may have an old thread with the same id in the thread list. @@ -362,10 +341,10 @@ step_over_chain_enqueue (struct thread_info **list_p, struct thread_info *tp) } } -/* Remove TP from step-over chain LIST_P. */ +/* See gdbthread.h. */ -static void -step_over_chain_remove (struct thread_info **list_p, struct thread_info *tp) +void +thread_step_over_chain_remove (thread_info **list_p, thread_info *tp) { gdb_assert (tp->step_over_next != NULL); gdb_assert (tp->step_over_prev != NULL); @@ -385,12 +364,20 @@ step_over_chain_remove (struct thread_info **list_p, struct thread_info *tp) /* See gdbthread.h. */ -struct thread_info * -thread_step_over_chain_next (struct thread_info *tp) +thread_info * +thread_step_over_chain_next (thread_info *chain_head, thread_info *tp) { - struct thread_info *next = tp->step_over_next; + thread_info *next = tp->step_over_next; - return (next == step_over_queue_head ? NULL : next); + return next == chain_head ? NULL : next; +} + +/* See gdbthread.h. */ + +struct thread_info * +global_thread_step_over_chain_next (struct thread_info *tp) +{ + return thread_step_over_chain_next (global_thread_step_over_chain_head, tp); } /* See gdbthread.h. */ @@ -403,18 +390,66 @@ thread_is_in_step_over_chain (struct thread_info *tp) /* See gdbthread.h. */ +int +thread_step_over_chain_length (thread_info *tp) +{ + if (tp == nullptr) + return 0; + + gdb_assert (thread_is_in_step_over_chain (tp)); + + int num = 1; + + for (thread_info *iter = tp->step_over_next; + iter != tp; + iter = iter->step_over_next) + ++num; + + return num; +} + +/* See gdbthread.h. */ + void -thread_step_over_chain_enqueue (struct thread_info *tp) +global_thread_step_over_chain_enqueue (struct thread_info *tp) { - step_over_chain_enqueue (&step_over_queue_head, tp); + infrun_debug_printf ("enqueueing thread %s in global step over chain", + target_pid_to_str (tp->ptid).c_str ()); + + step_over_chain_enqueue (&global_thread_step_over_chain_head, tp); } /* See gdbthread.h. */ void -thread_step_over_chain_remove (struct thread_info *tp) +global_thread_step_over_chain_enqueue_chain (thread_info *chain_head) { - step_over_chain_remove (&step_over_queue_head, tp); + gdb_assert (chain_head->step_over_next != nullptr); + gdb_assert (chain_head->step_over_prev != nullptr); + + if (global_thread_step_over_chain_head == nullptr) + global_thread_step_over_chain_head = chain_head; + else + { + thread_info *global_last = global_thread_step_over_chain_head->step_over_prev; + thread_info *chain_last = chain_head->step_over_prev; + + chain_last->step_over_next = global_thread_step_over_chain_head; + global_last->step_over_next = chain_head; + global_thread_step_over_chain_head->step_over_prev = chain_last; + chain_head->step_over_prev = global_last; + } +} + +/* See gdbthread.h. */ + +void +global_thread_step_over_chain_remove (struct thread_info *tp) +{ + infrun_debug_printf ("removing thread %s from global step over chain", + target_pid_to_str (tp->ptid).c_str ()); + + thread_step_over_chain_remove (&global_thread_step_over_chain_head, tp); } /* Delete the thread referenced by THR. If SILENT, don't notify @@ -502,6 +537,8 @@ find_thread_ptid (process_stratum_target *targ, ptid_t ptid) struct thread_info * find_thread_ptid (inferior *inf, ptid_t ptid) { + gdb_assert (inf != nullptr); + for (thread_info *tp : inf->non_exited_threads ()) if (tp->ptid == ptid) return tp; @@ -805,7 +842,7 @@ set_running_thread (struct thread_info *tp, bool running) the step-over queue, so that we don't try to resume it until the user wants it to. */ if (tp->step_over_next != NULL) - thread_step_over_chain_remove (tp); + global_thread_step_over_chain_remove (tp); } return started; @@ -1325,64 +1362,7 @@ switch_to_thread (process_stratum_target *proc_target, ptid_t ptid) switch_to_thread (thr); } -static void -restore_selected_frame (struct frame_id a_frame_id, int frame_level) -{ - struct frame_info *frame = NULL; - int count; - - /* This means there was no selected frame. */ - if (frame_level == -1) - { - select_frame (NULL); - return; - } - - gdb_assert (frame_level >= 0); - - /* Restore by level first, check if the frame id is the same as - expected. If that fails, try restoring by frame id. If that - fails, nothing to do, just warn the user. */ - - count = frame_level; - frame = find_relative_frame (get_current_frame (), &count); - if (count == 0 - && frame != NULL - /* The frame ids must match - either both valid or both outer_frame_id. - The latter case is not failsafe, but since it's highly unlikely - the search by level finds the wrong frame, it's 99.9(9)% of - the time (for all practical purposes) safe. */ - && frame_id_eq (get_frame_id (frame), a_frame_id)) - { - /* Cool, all is fine. */ - select_frame (frame); - return; - } - - frame = frame_find_by_id (a_frame_id); - if (frame != NULL) - { - /* Cool, refound it. */ - select_frame (frame); - return; - } - - /* Nothing else to do, the frame layout really changed. Select the - innermost stack frame. */ - select_frame (get_current_frame ()); - - /* Warn the user. */ - if (frame_level > 0 && !current_uiout->is_mi_like_p ()) - { - warning (_("Couldn't restore frame #%d in " - "current thread. Bottom (innermost) frame selected:"), - frame_level); - /* For MI, we should probably have a notification about - current frame change. But this error is not very - likely, so don't bother for now. */ - print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1); - } -} +/* See frame.h. */ void scoped_restore_current_thread::restore () @@ -1409,64 +1389,28 @@ scoped_restore_current_thread::restore () && target_has_stack () && target_has_memory ()) restore_selected_frame (m_selected_frame_id, m_selected_frame_level); + + set_language (m_lang); } scoped_restore_current_thread::~scoped_restore_current_thread () { if (!m_dont_restore) - { - try - { - restore (); - } - catch (const gdb_exception &ex) - { - /* We're in a dtor, there's really nothing else we can do - but swallow the exception. */ - } - } + restore (); } scoped_restore_current_thread::scoped_restore_current_thread () { m_inf = inferior_ref::new_reference (current_inferior ()); + m_lang = current_language->la_language; + if (inferior_ptid != null_ptid) { m_thread = thread_info_ref::new_reference (inferior_thread ()); - struct frame_info *frame; - m_was_stopped = m_thread->state == THREAD_STOPPED; - if (m_was_stopped - && target_has_registers () - && target_has_stack () - && target_has_memory ()) - { - /* When processing internal events, there might not be a - selected frame. If we naively call get_selected_frame - here, then we can end up reading debuginfo for the - current frame, but we don't generally need the debuginfo - at this point. */ - frame = get_selected_frame_if_set (); - } - else - frame = NULL; - - try - { - m_selected_frame_id = get_frame_id (frame); - m_selected_frame_level = frame_relative_level (frame); - } - catch (const gdb_exception_error &ex) - { - m_selected_frame_id = null_frame_id; - m_selected_frame_level = -1; - - /* Better let this propagate. */ - if (ex.error == TARGET_CLOSE_ERROR) - throw; - } + save_selected_frame (&m_selected_frame_id, &m_selected_frame_level); } } @@ -1505,7 +1449,7 @@ print_thread_id (struct thread_info *thr) ascending order. */ static bool -tp_array_compar_ascending (const thread_info *a, const thread_info *b) +tp_array_compar_ascending (const thread_info_ref &a, const thread_info_ref &b) { if (a->inf->num != b->inf->num) return a->inf->num < b->inf->num; @@ -1518,7 +1462,7 @@ tp_array_compar_ascending (const thread_info *a, const thread_info *b) descending order. */ static bool -tp_array_compar_descending (const thread_info *a, const thread_info *b) +tp_array_compar_descending (const thread_info_ref &a, const thread_info_ref &b) { if (a->inf->num != b->inf->num) return a->inf->num > b->inf->num; @@ -1526,15 +1470,16 @@ tp_array_compar_descending (const thread_info *a, const thread_info *b) return (a->per_inf_num > b->per_inf_num); } -/* Switch to thread THR and execute CMD. +/* Assuming that THR is the current thread, execute CMD. FLAGS.QUIET controls the printing of the thread information. - FLAGS.CONT and FLAGS.SILENT control how to handle errors. */ + FLAGS.CONT and FLAGS.SILENT control how to handle errors. Can throw an + exception if !FLAGS.SILENT and !FLAGS.CONT and CMD fails. */ static void thr_try_catch_cmd (thread_info *thr, const char *cmd, int from_tty, const qcs_flags &flags) { - switch_to_thread (thr); + gdb_assert (is_current_thread (thr)); /* The thread header is computed before running the command since the command can change the inferior, which is not permitted @@ -1656,17 +1601,13 @@ thread_apply_all_command (const char *cmd, int from_tty) thread, in case the command is one that wipes threads. E.g., detach, kill, disconnect, etc., or even normally continuing over an inferior or thread exit. */ - std::vector thr_list_cpy; + std::vector thr_list_cpy; thr_list_cpy.reserve (tc); for (thread_info *tp : all_non_exited_threads ()) - thr_list_cpy.push_back (tp); + thr_list_cpy.push_back (thread_info_ref::new_reference (tp)); gdb_assert (thr_list_cpy.size () == tc); - /* Increment the refcounts, and restore them back on scope - exit. */ - scoped_inc_dec_ref inc_dec_ref (thr_list_cpy); - auto *sorter = (ascending ? tp_array_compar_ascending : tp_array_compar_descending); @@ -1674,9 +1615,9 @@ thread_apply_all_command (const char *cmd, int from_tty) scoped_restore_current_thread restore_thread; - for (thread_info *thr : thr_list_cpy) - if (switch_to_thread_if_alive (thr)) - thr_try_catch_cmd (thr, cmd, from_tty, flags); + for (thread_info_ref &thr : thr_list_cpy) + if (switch_to_thread_if_alive (thr.get ())) + thr_try_catch_cmd (thr.get (), cmd, from_tty, flags); } } @@ -2183,11 +2124,11 @@ _initialize_thread () = gdb::option::build_help (_("\ Display currently known threads.\n\ Usage: info threads [OPTION]... [ID]...\n\ +If ID is given, it is a space-separated list of IDs of threads to display.\n\ +Otherwise, all threads are displayed.\n\ \n\ Options:\n\ -%OPTIONS%\ -If ID is given, it is a space-separated list of IDs of threads to display.\n\ -Otherwise, all threads are displayed."), +%OPTIONS%"), info_threads_opts); c = add_info ("threads", info_threads_command, info_threads_help.c_str ());