[non-stop] 10/10 split user/internal threads

Pedro Alves pedro@codesourcery.com
Sun Jun 15 21:49:00 GMT 2008


This is the patch that split the notion of the frontend selected
thread and frame from inferior_ptid.  I've come to the conclusion
this is the path to go for several reasons.

- In non-stop mode, the user/frontend will have a stopped thread
  and frame selected, while a new event in another thread comes
  along.  (Aside from having GDB switch threads automatically or
  not when another thread stops, ) this may just be an
  internal event.  The user should not lose its selection.  More
  on that below.

- We avoided deleting inferior_ptid until the target stopped.  This
  worked in all-stopped mode, as there, the user is not be able to enter
  commands that apply to the thread that has already exited.  This
  split make it safe to notify the threads module that
  inferior_ptid exited.  If we don't split the external/internal
  thread notion, then cases like switching threads and restoring
  the previous thread with a cleanup are tricky, because there is
  no reference anywhere to which thread was the previous one, other
  than inside the cleanup.  Comparing with inferior_ptid only
  doesn't cut it.

- The frontend wants to be reported of thread and frame
  changes that are interesting to the user, not every internal
  thread and selected frame change, used, e.g., while updating
  var-objects.

The patch then updates the behaviour of GDB on the case of
the selected thread exiting.  It implements a scheme similar
to c) of the options listed here:
http://sourceware.org/ml/gdb/2008-06/msg00013.html

This requires some explanation, so here goes.

After having tried solutions
  b) (keep dead threads on the list, until
the user switches threads) and
  c) (don't keep dead threads on the list and make inferior_ptid point
    to some magic ptid if inferior_ptid exits),
and several combinations of the above, including one that added a new
field to ptid (so dead threads would not match ptids comming from the
events from the target layer),

I came to the conclusion that there was something wrong with
the way GDB manages the current user/frontend/external thread.
Overloading inferior_ptid to mean the current thread/process that GDB
is internally operating on, and also the user selected thread is
really not what we want.  It was OK in all-stop mode, but is
not ideal in non-stop.

So, what the patch does is upgrade previous_inferior_ptid (which
already played a small role in the "hey, I've switched to a
new thread" business) to represent the external/user selected thread,
rename it to user_selected_ptid, and add companion user_selected_frame
and user_selected_frame_level, which are used to represent the
frame the user has selected.

The new store_selected_thread_and_frame is used to 
store the record which thread and frame the user/frontend has selected, 
and restore_selected_thread_and_frame is used to switch inferior_ptid
and its selected frame to point back to what the user/frontend expects.

With this patch in place, the target side can now call
delete_thread without caring if inferior_ptid points to it.  The
common code will take care of not deleting it just immediatelly, and
still tagging/notifying of its exit.  It will be deleted whenever
it's safe.  thread_info's running state also gets a small upgrade into
an enum that stores the running/stopped/exited state.

If add_thread* is called, and the ptid being added is already listed,
it means the OS is reusing the tid.  In that case, we delete the old
ptid from the list, and add the new one --- this new one will get a
new GDB thread num.  If the thread just exiting was also the user
selected thread, we invalidate it.  This means that in all-stop,
if the OS is reusing the selected thread's ptid, and this new thread
has the next event, normal_stop will now notice that this is a
new thread, and print a "switched to thread" notice, although the
ptid didn't change (if we added the GDB thread num to that output,
the user could notice the change).

I've added three points where GDB makes the internal (inferior_ptid)
thread switch to the user selected thread (user_selected_ptid):

 1 - execute_command, before executing a command
 2 - execute_command, after executing a command,
 3 - fetch_inferior_event, after handling the event.

With these in place, the user never notices when GDB switches
between threads internally while handing events.

You'll also notice that the implementations of "info threads",
"thread apply all/tid" and a couple of other places get a clean up,
since now execute_command takes care of restoring the user selected
thread and frame.

In the case were we want to temporarily execute a command
to a thread other than the current thread, we switch the internal
thread to the thread we want with switch_to_thread/context_switch_to,
and invoke execute_command_internal.  Unlike execute_command, this
doesn't re-switch the internal thread to the external thread.
There are examples in thread_apply_all_command, and
thread_apply_command.  This can be used to implement the
"--thread" switch in MI commands.

Oh, and here's what happens when the current thread exits in
non-stop mode:

(gdb) b 81
Breakpoint 1 at 0x80485fd: file threads.c, line 81.
(gdb) r
Starting program: /home/pedro/gdb/tests/threads32
[Thread debugging using libthread_db enabled]
[New Thread 0xf7e22b90 (LWP 29573)]
[New Thread 0xf7621b90 (LWP 29574)]

Breakpoint 1, thread_function1 (arg=0x1) at threads.c:81
81              usleep (1);  /* Loop increment.  */
Thread 3 [Thread 0xf7621b90 (LWP 29574)] stopped
(gdb) thread 3
[Switching to thread 3 (Thread 0xf7621b90 (LWP 29574))]#0  thread_function1 
(arg=0x1) at threads.c:81
81              usleep (1);  /* Loop increment.  */
(gdb) info threads
* 3 Thread 0xf7621b90 (LWP 29574)  thread_function1 (arg=0x1) at threads.c:81
  2 Thread 0xf7e22b90 (LWP 29573)  (running)
  1 Thread 0xf7e236b0 (LWP 29570)  (running)
(gdb) p *myp=0
$1 = 0
(gdb) c&
Continuing.
(gdb) [Thread 0xf7621b90 (LWP 29574) exited]
info threads
  2 Thread 0xf7e22b90 (LWP 29573)  (running)
  1 Thread 0xf7e236b0 (LWP 29570)  (running)

No selected thread.  See `help thread'
(gdb) p a
Cannot execute this command without a selected thread.  See `help thread'
(gdb) thread 2
[Switching to thread 2 (Thread 0xf7e22b90 (LWP 29573))](running)
(gdb) info threads
* 2 Thread 0xf7e22b90 (LWP 29573)  (running)
  1 Thread 0xf7e236b0 (LWP 29570)  (running)
(gdb) p a
Cannot execute this command while the target is running.
(gdb) interrupt
(gdb)
Program received signal SIGINT, Interrupt.
0xffffe410 in __kernel_vsyscall ()
info threads
* 2 Thread 0xf7e22b90 (LWP 29573)  0xffffe410 in __kernel_vsyscall ()
  1 Thread 0xf7e236b0 (LWP 29570)  (running)
(gdb) p a
No symbol "a" in current context.
(gdb)

-- 
Pedro Alves
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 010-dont_switch_threads_and_exited_threads.diff
Type: text/x-diff
Size: 61228 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/gdb-patches/attachments/20080615/e27c8478/attachment.bin>


More information about the Gdb-patches mailing list