Add thread-exit annotation.
authorAmos Bird <amosbird@gmail.com>
Thu, 6 Jun 2019 17:10:14 +0000 (01:10 +0800)
committerTom Tromey <tromey@adacore.com>
Thu, 6 Jun 2019 17:35:15 +0000 (11:35 -0600)
gdb/ChangeLog
2019-04-26  Amos Bird  <amosbird@gmail.com>

* annotate.c (annotate_thread_exited): Add "thread-exited"
annotation.

gdb/doc/ChangeLog
2019-06-06  Amos Bird  <amosbird@gmail.com>

* annotate.texinfo (Multi-threaded Apps): Add entry for thread-exited
annotation.

gdb/testsuite/ChangeLog
2019-06-06  Amos Bird  <amosbird@gmail.com>

* gdb.base/annota1.exp (thread_switch): Add test for
thread-exited annotation.

gdb/ChangeLog
gdb/NEWS
gdb/annotate.c
gdb/doc/ChangeLog
gdb/doc/annotate.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/annota1.exp
gdb/testsuite/gdb.base/watch_thread_num.c
gdb/testsuite/gdb.cp/annota2.exp

index c0cc57f..024e171 100644 (file)
@@ -1,3 +1,8 @@
+2019-04-26  Amos Bird  <amosbird@gmail.com>
+
+       * annotate.c (annotate_thread_exited): Add "thread-exited"
+       annotation.
+
 2019-06-06  Tom Tromey  <tromey@adacore.com>
 
        * maint.h (class scoped_command_stats): Use
index ded1fce..9e1462b 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,8 @@
 
 *** Changes since GDB 8.3
 
+* 'thread-exited' event is now available in the annotations interface.
+
 * New built-in convenience variables $_gdb_major and $_gdb_minor
   provide the GDB version.  They are handy for conditionally using
   features available only in or since specific GDB versions, in
index 088f7c9..e6e8084 100644 (file)
@@ -241,6 +241,19 @@ annotate_thread_changed (void)
     }
 }
 
+/* Emit notification on thread exit.  */
+
+static void
+annotate_thread_exited (struct thread_info *t, int silent)
+{
+  if (annotation_level > 1)
+    {
+      printf_filtered(("\n\032\032thread-exited,"
+                       "id=\"%d\",group-id=\"i%d\"\n"),
+                      t->global_num, t->inf->num);
+    }
+}
+
 void
 annotate_field_begin (struct type *type)
 {
@@ -595,4 +608,5 @@ _initialize_annotate (void)
   gdb::observers::breakpoint_created.attach (breakpoint_changed);
   gdb::observers::breakpoint_deleted.attach (breakpoint_changed);
   gdb::observers::breakpoint_modified.attach (breakpoint_changed);
+  gdb::observers::thread_exit.attach (annotate_thread_exited);
 }
index 5da2599..51a8516 100644 (file)
@@ -1,3 +1,8 @@
+2019-06-06  Amos Bird  <amosbird@gmail.com>
+
+       * annotate.texinfo (Multi-threaded Apps): Add entry for thread-exited
+       annotation.
+
 2019-06-04  Christian Biesinger  <cbiesinger@google.com>
 
        * python.texi: Document new gdb.Type.objfile property.
index b85b759..ee8147f 100644 (file)
@@ -836,6 +836,13 @@ The selected thread has changed.  This may occur at the request of the
 user with the @code{thread} command, or as a result of execution,
 e.g., another thread hits a breakpoint.
 
+@findex thread-exited@r{, annotation}
+@item ^Z^Zthread-exited,id="@var{id}",group-id="@var{gid}"
+
+This annotation is issued once for each thread that exits.  The @var{id}
+field contains the global @value{GDBN} identifier of the thread.  The
+@var{gid} field identifies the thread group this thread belongs to.
+
 @end table
 
 @node GNU Free Documentation License
index 61affed..7cc712b 100644 (file)
@@ -1,3 +1,8 @@
+2019-06-06  Amos Bird  <amosbird@gmail.com>
+
+       * gdb.base/annota1.exp (thread_switch): Add test for
+       thread-exited annotation.
+
 2019-06-06  Tom Tromey  <tromey@adacore.com>
 
        * gdb.base/maint.exp: Expect command started/finished output.
index 5237bc9..dfa3083 100644 (file)
@@ -428,7 +428,7 @@ if [target_info exists gdb,nosignals] {
     unsupported "signal sent"
 } else {
     gdb_test_multiple "signal SIGTRAP" "signal sent" {
-       -re ".*\032\032post-prompt\r\nContinuing with signal SIGTRAP.\r\n\r\n\032\032starting\(\r\n\r\n\032\032frames-invalid\)+\r\n\r\n\032\032signalled\r\n\r\nProgram terminated with signal \r\n\032\032signal-name\r\nSIGTRAP\r\n\032\032signal-name-end\r\n, \r\n\032\032signal-string\r\nTrace.breakpoint trap\r\n\032\032signal-string-end\r\n.\r\nThe program no longer exists.\r\n\r\n\032\032stopped\r\n$gdb_prompt$" {
+       -re ".*\032\032post-prompt\r\nContinuing with signal SIGTRAP.\r\n\r\n\032\032starting\(\r\n\r\n\032\032frames-invalid\)+\r\n\r\n\032\032signalled\r\n\r\nProgram terminated with signal \r\n\032\032signal-name\r\nSIGTRAP\r\n\032\032signal-name-end\r\n, \r\n\032\032signal-string\r\nTrace.breakpoint trap\r\n\032\032signal-string-end\r\n.\r\nThe program no longer exists.\r\n\r\n\032\032thread-exited,id=\"${decimal}\",group-id=\"i${decimal}\"\r\n\r\n\032\032stopped\r\n$gdb_prompt$" {
            pass "signal sent"
        }
     }
@@ -450,6 +450,7 @@ if { [remote_file host exists core] } {
 proc thread_test {} {
     global subdir srcdir testfile srcfile binfile
     global gdb_prompt old_gdb_prompt
+    global decimal
     set srcfile watch_thread_num.c
     set binfile [standard_output_file ${testfile}-watch_thread_num]
     set gdb_prompt $old_gdb_prompt
@@ -468,6 +469,9 @@ proc thread_test {} {
        set linenum [gdb_get_line_number "all threads started"]
        gdb_breakpoint "$linenum"
 
+       set linenum [gdb_get_line_number "first child thread exited"]
+       gdb_breakpoint "$linenum"
+
        set gdb_prompt \
            "\r\n\032\032pre-prompt\r\n$gdb_prompt \r\n\032\032prompt\r\n"
 
@@ -481,6 +485,12 @@ proc thread_test {} {
                pass "new thread"
            }
        }
+
+    gdb_test_multiple "continue" "thread exit" {
+           -re "\032\032thread-exited,id=\"${decimal}\",group-id=\"i${decimal}\".*\r\n$gdb_prompt$" {
+               pass "thread exit"
+           }
+    }
     }
 }
 
index a5195c7..fe9d602 100644 (file)
@@ -29,6 +29,8 @@ void *thread_function (void *arg); /* Pointer to function executed by each threa
 
 static pthread_barrier_t threads_started_barrier;
 
+static pthread_barrier_t threads_started_barrier2;
+
 #define NUM 15
 
 static int num_threads = NUM;
@@ -43,6 +45,8 @@ int main () {
 
     pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
 
+    pthread_barrier_init (&threads_started_barrier2, NULL, 2);
+
     for (i = 0; i < NUM; i++)
       {
         res = pthread_create (&threads[i],
@@ -53,7 +57,11 @@ int main () {
 
     pthread_barrier_wait (&threads_started_barrier);
 
-    sleep (180); /* all threads started */
+    pthread_barrier_wait (&threads_started_barrier2);  /* all threads started */
+
+    pthread_join (threads[0], NULL);
+
+    sleep (180);  /* first child thread exited */
 
     exit (EXIT_SUCCESS);
 }
@@ -68,13 +76,18 @@ void *thread_function (void *arg) {
 
     pthread_barrier_wait (&threads_started_barrier);
 
-    /* Don't run forever.  Run just short of it :)  */
-    while (shared_var > 0)
+    if (my_number > 0)
       {
-        shared_var++;
-       usleep (1); /* Loop increment.  */
-       loop ();
+       /* Don't run forever.  Run just short of it :)  */
+       while (shared_var > 0)
+         {
+           shared_var++;
+           usleep (1); /* Loop increment.  */
+           loop ();
+         }
       }
+    else
+      pthread_barrier_wait (&threads_started_barrier2);
 
     pthread_exit (NULL);
 }
index 982020a..745f461 100644 (file)
@@ -138,6 +138,8 @@ set pat [multi_line "" \
             "\032\032exited 0" \
             "$inferior_exited_re normally." \
             "" \
+            "\032\032thread-exited,id=\"1\",group-id=\"i1\"" \
+            "" \
             "\032\032stopped" \
             $gdb_prompt$]
 gdb_test_multiple "continue" "continue until exit" {