• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

GNU Binutils with patches for OS216


Commit MetaInfo

Révision3922b302645fda04da42a5279399578ae2f6206c (tree)
l'heure2020-06-19 07:18:36
AuteurPedro Alves <palves@redh...>
CommiterPedro Alves

Message de Log

Decouple inferior_ptid/inferior_thread(); dup ptids in thread list (PR 25412)

In PR 25412, Simon noticed that after the multi-target series, the
tid-reuse.exp testcase manages to create a duplicate thread in the
thread list. Or rather, two threads with the same PTID.

add_thread_silent has code in place to detect the case of a new thread
reusing some older thread's ptid, but it doesn't work correctly
anymore when the old thread is NOT the current thread and it has a
refcount higher than 0. Either condition prevents a thread from being
deleted, but the refcount case wasn't being considered. I think the
reason that case wasn't considered is that that code predates
thread_info refcounting. Back when it was originally written,
delete_thread always deleted the thread.

That add_thread_silent code in question has some now-unnecessary
warts, BTW. For instance, this:

/* Make switch_to_thread not read from the thread. */
new_thr->state = THREAD_EXITED;

... used to be required because switch_to_thread would update
'stop_pc' otherwise. I.e., it would read registers from an exited
thread otherwise. switch_to_thread no longer reads the stop_pc, since:

commit f2ffa92bbce9dd5fbedc138ac2a3bc8a88327d09
Author: Pedro Alves <palves@redhat.com>
AuthorDate: Thu Jun 28 20:18:24 2018 +0100
gdb: Eliminate the 'stop_pc' global

Also, if the ptid of the now-gone current thread is reused, we
currently return from add_thread_silent with the current thread
pointing at the _new_ thread. Either pointing at the old thread, or
at no thread selected would be reasonable. But pointing at an
unrelated thread (the new thread that happens to reuse the ptid) is
just broken. Seems like I was the one who wrote it like that but I
have no clue why, FWIW.

Currently, an exited thread kept in the thread list still holds its
original ptid. The idea was that we need the ptid to be able to
temporarily switch to another thread and then switch back to the
original thread, because thread switching is really inferior_ptid
switching. Switching back to the original thread requires a ptid
lookup.

Now, in order to avoid exited threads with the same ptid as a live
thread in the same thread list, one thing I considered (and tried) was
to change an exited thread's ptid to minus_one_ptid. However, with
that, there's a case that we won't handle well, which is if we end up
with more than one exited thread in the list, since then all exited
threads will all have the same ptid. Since inferior_thread() relies
on inferior_ptid, may well return the wrong thread.

My next attempt to address this, was to switch an exited thread's ptid
to a globally unique "exited" ptid, which is a ptid with pid == -1 and
tid == 'the thread's global GDB thread number'. Note that GDB assumes
that the GDB global thread number is monotonically increasing and
doesn't wrap around. (We should probably make GDB thread numbers
64-bit to prevent that happening in practice; they're currently signed
32-bit.) This attempt went a long way, but still ran into a number of
issues. It was a major hack too, obviously.

My next attempt is the one that I'm proposing, which is to bite the
bullet and break the connection between inferior_ptid and
inferior_thread(), aka the current thread. I.e., make the current
thread be a global thread_info pointer that is written to directly by
switch_to_thread, etc., and making inferior_thread() return that
pointer, instead of having inferior_thread() lookup up the
inferior_ptid thread, by ptid_t. You can look at this as a
continuation of the effort of using more thread_info pointers instead
of ptids when possible.

By making the current thread a global thread_info pointer, we can make
switch_to_thread simply write to the global thread pointer, which
makes scoped_restore_current_thread able to restore back to an exited
thread without relying on unrelyable ptid look ups. I.e., this makes
it not a real problem to have more than one thread with the same ptid
in the thread list. There will always be only one live thread with a
given ptid, so code that looks up a live thread by ptid will always be
able to find the right one.

This change required auditing the whole codebase for places where we
were writing to inferior_ptid directly to change the current thread,
and change them to use switch_to_thread instead or one of its
siblings, because otherwise inferior_thread() would return a thread
unrelated to the changed-to inferior_ptid. That was all (hopefully)
done in previous patches.

After this, inferior_ptid is mainly used by target backend code. It
is also relied on by a number of target methods. E.g., the
target_resume interface and the memory reading routines -- we still
need it there because we need to be able to access memory off of
processes for which we don't have a corresponding inferior/thread
object, like when handling forks. Maybe we could pass down a context
explicitly to target_read_memory, etc.

gdb/ChangeLog:
2020-06-18 Pedro Alves <palves@redhat.com>

PR gdb/25412
* gdbthread.h (delete_thread, delete_thread_silent)
(find_thread_ptid): Update comments.
* thread.c (current_thread_): New global.
(is_current_thread): Move higher, and reimplement.
(inferior_thread): Reimplement.
(set_thread_exited): Use bool. Add assertions.
(add_thread_silent): Simplify thread-reuse handling by always
calling delete_thread.
(delete_thread): Remove intro comment.
(find_thread_ptid): Skip exited threads.
(switch_to_thread_no_regs): Write to current_thread_.
(switch_to_no_thread): Check CURRENT_THREAD_ instead of
INFERIOR_PTID. Clear current_thread_.

Change Summary

Modification

--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,22 @@
11 2020-06-18 Pedro Alves <palves@redhat.com>
22
3+ PR gdb/25412
4+ * gdbthread.h (delete_thread, delete_thread_silent)
5+ (find_thread_ptid): Update comments.
6+ * thread.c (current_thread_): New global.
7+ (is_current_thread): Move higher, and reimplement.
8+ (inferior_thread): Reimplement.
9+ (set_thread_exited): Use bool. Add assertions.
10+ (add_thread_silent): Simplify thread-reuse handling by always
11+ calling delete_thread.
12+ (delete_thread): Remove intro comment.
13+ (find_thread_ptid): Skip exited threads.
14+ (switch_to_thread_no_regs): Write to current_thread_.
15+ (switch_to_no_thread): Check CURRENT_THREAD_ instead of
16+ INFERIOR_PTID. Clear current_thread_.
17+
18+2020-06-18 Pedro Alves <palves@redhat.com>
19+
320 * aix-thread.c (pd_update): Use switch_to_thread.
421
522 2020-06-18 Pedro Alves <palves@redhat.com>
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -415,12 +415,13 @@ extern struct thread_info *add_thread_with_info (process_stratum_target *targ,
415415 ptid_t ptid,
416416 private_thread_info *);
417417
418-/* Delete an existing thread list entry. */
418+/* Delete thread THREAD and notify of thread exit. If the thread is
419+ currently not deletable, don't actually delete it but still tag it
420+ as exited and do the notification. */
419421 extern void delete_thread (struct thread_info *thread);
420422
421-/* Delete an existing thread list entry, and be quiet about it. Used
422- after the process this thread having belonged to having already
423- exited, for example. */
423+/* Like delete_thread, but be quiet about it. Used when the process
424+ this thread belonged to has already exited, for example. */
424425 extern void delete_thread_silent (struct thread_info *thread);
425426
426427 /* Delete a step_resume_breakpoint from the thread database. */
@@ -460,15 +461,15 @@ extern bool in_thread_list (process_stratum_target *targ, ptid_t ptid);
460461 global id, not the system's). */
461462 extern int valid_global_thread_id (int global_id);
462463
463-/* Find thread PTID of inferior INF. */
464+/* Find (non-exited) thread PTID of inferior INF. */
464465 extern thread_info *find_thread_ptid (inferior *inf, ptid_t ptid);
465466
466-/* Search function to lookup a thread by 'pid'. */
467+/* Search function to lookup a (non-exited) thread by 'ptid'. */
467468 extern struct thread_info *find_thread_ptid (process_stratum_target *targ,
468469 ptid_t ptid);
469470
470-/* Search function to lookup a thread by 'ptid'. Only searches in
471- threads of INF. */
471+/* Search function to lookup a (non-exited) thread by 'ptid'. Only
472+ searches in threads of INF. */
472473 extern struct thread_info *find_thread_ptid (inferior *inf, ptid_t ptid);
473474
474475 /* Find thread by GDB global thread ID. */
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -55,6 +55,9 @@
5555
5656 static int highest_thread_num;
5757
58+/* The current/selected thread. */
59+static thread_info *current_thread_;
60+
5861 /* RAII type used to increase / decrease the refcount of each thread
5962 in a given list of threads. */
6063
@@ -78,13 +81,19 @@ private:
7881 const std::vector<thread_info *> &m_thrds;
7982 };
8083
84+/* Returns true if THR is the current thread. */
85+
86+static bool
87+is_current_thread (const thread_info *thr)
88+{
89+ return thr == current_thread_;
90+}
8191
8292 struct thread_info*
8393 inferior_thread (void)
8494 {
85- struct thread_info *tp = find_thread_ptid (current_inferior (), inferior_ptid);
86- gdb_assert (tp);
87- return tp;
95+ gdb_assert (current_thread_ != nullptr);
96+ return current_thread_;
8897 }
8998
9099 /* Delete the breakpoint pointed at by BP_P, if there's one. */
@@ -194,7 +203,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
194203 /* Set the TP's state as exited. */
195204
196205 static void
197-set_thread_exited (thread_info *tp, int silent)
206+set_thread_exited (thread_info *tp, bool silent)
198207 {
199208 /* Dead threads don't need to step-over. Remove from queue. */
200209 if (tp->step_over_next != NULL)
@@ -245,7 +254,12 @@ new_thread (struct inferior *inf, ptid_t ptid)
245254 struct thread_info *last;
246255
247256 for (last = inf->thread_list; last->next != NULL; last = last->next)
248- ;
257+ gdb_assert (ptid != last->ptid
258+ || last->state == THREAD_EXITED);
259+
260+ gdb_assert (ptid != last->ptid
261+ || last->state == THREAD_EXITED);
262+
249263 last->next = tp;
250264 }
251265
@@ -255,51 +269,15 @@ new_thread (struct inferior *inf, ptid_t ptid)
255269 struct thread_info *
256270 add_thread_silent (process_stratum_target *targ, ptid_t ptid)
257271 {
258- inferior *inf;
259-
260- thread_info *tp = find_thread_ptid (targ, ptid);
261- if (tp)
262- /* Found an old thread with the same id. It has to be dead,
263- otherwise we wouldn't be adding a new thread with the same id.
264- The OS is reusing this id --- delete it, and recreate a new
265- one. */
266- {
267- /* In addition to deleting the thread, if this is the current
268- thread, then we need to take care that delete_thread doesn't
269- really delete the thread if it is inferior_ptid. Create a
270- new template thread in the list with an invalid ptid, switch
271- to it, delete the original thread, reset the new thread's
272- ptid, and switch to it. */
273-
274- if (inferior_ptid == ptid)
275- {
276- thread_info *new_thr = new_thread (tp->inf, null_ptid);
277-
278- /* Make switch_to_thread not read from the thread. */
279- new_thr->state = THREAD_EXITED;
280- switch_to_no_thread ();
281-
282- /* Now we can delete it. */
283- delete_thread (tp);
284-
285- /* Now reset its ptid, and reswitch inferior_ptid to it. */
286- new_thr->ptid = ptid;
287- new_thr->state = THREAD_STOPPED;
288- switch_to_thread (new_thr);
289-
290- gdb::observers::new_thread.notify (new_thr);
291-
292- /* All done. */
293- return new_thr;
294- }
272+ inferior *inf = find_inferior_ptid (targ, ptid);
295273
296- inf = tp->inf;
297-
298- /* Just go ahead and delete it. */
299- delete_thread (tp);
300- }
301- else
302- inf = find_inferior_ptid (targ, ptid);
274+ /* We may have an old thread with the same id in the thread list.
275+ If we do, it must be dead, otherwise we wouldn't be adding a new
276+ thread with the same id. The OS is reusing this id --- delete
277+ the old thread, and create a new one. */
278+ thread_info *tp = find_thread_ptid (inf, ptid);
279+ if (tp != nullptr)
280+ delete_thread (tp);
303281
304282 tp = new_thread (inf, ptid);
305283 gdb::observers::new_thread.notify (tp);
@@ -349,14 +327,6 @@ thread_info::~thread_info ()
349327 xfree (this->name);
350328 }
351329
352-/* Returns true if THR is the current thread. */
353-
354-static bool
355-is_current_thread (const thread_info *thr)
356-{
357- return thr->inf == current_inferior () && thr->ptid == inferior_ptid;
358-}
359-
360330 /* See gdbthread.h. */
361331
362332 bool
@@ -482,10 +452,7 @@ delete_thread_1 (thread_info *thr, bool silent)
482452 delete tp;
483453 }
484454
485-/* Delete thread THREAD and notify of thread exit. If this is the
486- current thread, don't actually delete it, but tag it as exited and
487- do the notification. If this is the user selected thread, clear
488- it. */
455+/* See gdbthread.h. */
489456
490457 void
491458 delete_thread (thread_info *thread)
@@ -535,7 +502,7 @@ find_thread_ptid (process_stratum_target *targ, ptid_t ptid)
535502 struct thread_info *
536503 find_thread_ptid (inferior *inf, ptid_t ptid)
537504 {
538- for (thread_info *tp : inf->threads ())
505+ for (thread_info *tp : inf->non_exited_threads ())
539506 if (tp->ptid == ptid)
540507 return tp;
541508
@@ -1317,7 +1284,8 @@ switch_to_thread_no_regs (struct thread_info *thread)
13171284 set_current_program_space (inf->pspace);
13181285 set_current_inferior (inf);
13191286
1320- inferior_ptid = thread->ptid;
1287+ current_thread_ = thread;
1288+ inferior_ptid = current_thread_->ptid;
13211289 }
13221290
13231291 /* See gdbthread.h. */
@@ -1325,9 +1293,10 @@ switch_to_thread_no_regs (struct thread_info *thread)
13251293 void
13261294 switch_to_no_thread ()
13271295 {
1328- if (inferior_ptid == null_ptid)
1296+ if (current_thread_ == nullptr)
13291297 return;
13301298
1299+ current_thread_ = nullptr;
13311300 inferior_ptid = null_ptid;
13321301 reinit_frame_cache ();
13331302 }