The branch, scox/globalstate has been updated via bc4b0dbeec0fb45f9fd169cb9b3a984e9378d055 (commit) from c94dca1a4db81df5753f2ec7c42b416920908897 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit bc4b0dbeec0fb45f9fd169cb9b3a984e9378d055 Author: Stan Cox <scox@redhat.com> Date: Tue Feb 23 15:07:29 2016 -0500 Improve multiple client thread support. * server.c (setup_multiplexing): Add pending_step_waiter, vConts, and pending_waitee cases. (do_multiplexing): Add vConts case. Grab pc from the current thread's cache. * multi-client.exp: Add next, strace, and pthreads tests. ----------------------------------------------------------------------- Summary of changes: gdb/gdbserver/ChangeLog | 7 + gdb/gdbserver/server.c | 181 ++++++++++++--------- gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.server/multi-client.exp | 251 ++++++++++++++++++++-------- 4 files changed, 298 insertions(+), 145 deletions(-) First 500 lines of diff: diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 88d55fd..49c0407 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,10 @@ +2016-02-23 Stan Cox <scox@redhat.com> + + * server.c (setup_multiplexing): Add pending_step_waiter, vConts, + and pending_waitee cases. + (do_multiplexing): Add vConts case. Grab pc from the current + thread's cache. + 2016-02-06 Stan Cox <scox@redhat.com> * server.c (waitkind_str): New diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 378b174..df1ea3c 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -85,7 +85,7 @@ static struct client_states client_states; static void handle_status (char *); -enum pending_types {none_pending, pending_waitee, pending_cont_waiter,pending_step_waiter,pending_stop}; +enum pending_types {none_pending, pending_waitee, pending_cont_waiter, pending_step_waiter, pending_stop}; char *pending_types_str[] = {"not-waiting","waitee","waiter","step-waiter","stop"}; char *packet_types_str[] = {"other", "vContc", "vConts","vContt","vStopped","vRun", "vAttach"}; char *waitkind_str[] = {"exited", "stopped", "signalled", "loaded", "forked", "vforked", "execed", "vfork-done", "syscall-entry", "syscall-exit", "spurious", "ignore", "no-history", "not-resumed", "thread-created", "thread-exited", ""}; @@ -442,19 +442,15 @@ void resolve_waiter (client_state *cs, client_state *waitee_cs) { enum packet_types this_packet_type = (cs->packet_type) ? cs->packet_type : cs->last_packet_type; + client_state *save_client_state; + save_client_state = client_states.current_cs; + set_client_state (cs->file_desc); switch (this_packet_type) { case vContc: { strcpy (own_buffer, "?"); - if (debug_threads) - { - prepare_resume_reply (own_buffer, cs->last_cont_ptid, &cs->last_cont_waitstatus); - debug_printf ("%s:%d %d %#lx %#lx %s %s prepare_resume_reply=%s\n", __FUNCTION__, __LINE__, - cs->file_desc, (unsigned long)cs->last_cont_ptid.pid, (unsigned long)cs->ss->last_ptid_.pid, - waitkind_str[cs->last_cont_waitstatus.kind], waitkind_str[cs->ss->last_status_.kind], own_buffer); - } if (non_stop) { if (last_status.kind != TARGET_WAITKIND_EXITED @@ -504,11 +500,15 @@ resolve_waiter (client_state *cs, client_state *waitee_cs) { if (last_status.kind != TARGET_WAITKIND_EXITED) { - /* reply to vContc with a status */ + /* reply to vConts with a status */ strcpy (own_buffer, "?"); handle_status (own_buffer); putpkt (own_buffer); } + else if (last_status.kind == TARGET_WAITKIND_EXITED) + { + putpkt (waitee_cs->own_buffer_); + } break; } case vContt: @@ -543,6 +543,25 @@ resolve_waiter (client_state *cs, client_state *waitee_cs) default: break; }; + + set_client_state (save_client_state->file_desc); +} + + +void +analyze_group (client_state *current_cs, int *have_nonwaiter) +{ + client_state *csi; + *have_nonwaiter = 0; + + for (csi = client_states.first->next; csi != NULL; csi = csi->next) + { + if (attached_to_same_proc (current_cs, csi)) + { + if (csi->pending == pending_waitee || csi->pending == none_pending) + *have_nonwaiter += 1; + } + } } @@ -582,14 +601,15 @@ setup_multiplexing (client_state *current_cs) { if (! attached_to_same_proc (current_cs, same_pid_cs)) continue; + switch (same_pid_cs->pending) { - case none_pending: + case /* same_pid_cs->pending */ none_pending: /* found a client that has nothing pending */ /* The current_cs vContc will wait; found same_pid_cs will proceed */ switch (current_cs->packet_type) { - case vContc: + case /* current_cs->packet_type */ vContc: if (current_cs->last_packet_type != vRun) { current_cs->pending = pending_cont_waiter; @@ -597,7 +617,7 @@ setup_multiplexing (client_state *current_cs) } break; /* TODO else if (current_cs->packet_type == vContt) */ - case vConts: + case /* current_cs->packet_type */ vConts: if (same_pid_cs->last_packet_type != vContt) { current_cs->pending = pending_step_waiter; @@ -605,33 +625,56 @@ setup_multiplexing (client_state *current_cs) } } break; - case pending_cont_waiter: + case /* same_pid_cs->pending */ pending_step_waiter: switch (current_cs->packet_type) { - /* Current client is continuing and found another waiter client */ - case vContc: + case /* current_cs->packet_type */ vContc: { - client_state *csi; - int waitee_count = 0; - - /* Does the client group have a waitee? */ - for (csi = client_states.first->next; csi != NULL; csi = csi->next) - { - if (current_cs != csi && csi->pending == pending_waitee - && attached_to_same_proc (current_cs, csi)) - waitee_count = 1; - } - + current_cs->pending = pending_cont_waiter; + resolve_waiter (same_pid_cs, current_cs); + same_pid_cs->pending = pending_waitee; + } + } + /* fall through for vConts case */ + case /* same_pid_cs->pending */ pending_cont_waiter: + switch (current_cs->packet_type) + { + /* Current client is continuing and found another waiter client */ + case /* current_cs->packet_type */ vContc: + { + int have_nonwaiter; + analyze_group (current_cs, &have_nonwaiter); dump_client_state (__FUNCTION__, "waitee/waiter switch"); - if (debug_threads) - debug_printf ("waitee count=%d\n", waitee_count); - /* Don't want to deadlock on everyone waiting */ - if (current_cs->pending == pending_waitee && waitee_count > 0) + if (current_cs->pending == pending_waitee && have_nonwaiter) current_cs->pending = pending_cont_waiter; } + break; + case /* current_cs->packet_type */ vConts: + { + int have_waitee; + analyze_group (current_cs, &have_waitee); + /* Don't want to deadlock on everyone waiting */ + if (current_cs->pending == pending_waitee && have_waitee) + current_cs->pending = pending_step_waiter; + } } - } + break; + case /* same_pid_cs->pending */ pending_waitee: + switch (current_cs->packet_type) + { + /* Current client is continuing and found another waitee client */ + case /* current_cs->packet_type */ vContc: + { + current_cs->pending = pending_cont_waiter; + } + break; + case /* current_cs->packet_type */ vConts: + { + current_cs->pending = pending_step_waiter; + } + } + } /* switch same_pid_cs->pending */ } /* for same_pid_cs */ @@ -640,15 +683,15 @@ setup_multiplexing (client_state *current_cs) case pending_cont_waiter: case pending_step_waiter: case pending_stop: - switch (current_cs->last_packet_type) - { + { case vRun: case vStopped: break; default: /* Current client is continuing and waiting so don't reply to this packet now; it will be replied to later in do_multiplexing */ + if (current_cs->ss->last_status_exited != have_exit) { dump_client_state (__FUNCTION__, "return 0"); @@ -656,11 +699,11 @@ setup_multiplexing (client_state *current_cs) current_cs->last_cont_waitstatus = current_cs->ss->last_status_; return 0; /* Reply to packet later */ } - } - default: + } /* switch current_cs->last_packet_type */ + default: /* fall through */ dump_client_state (__FUNCTION__, "return 1"); return 1; /* Reply to packet now */ - } + } /* switch current_cs->pending */ } @@ -723,24 +766,6 @@ do_multiplexing (client_state *current_cs, char ch) 7 vContc vContc waiter stopped ***/ - /* - syscall halt 3 current - 3 waitee 7 waiter - 7 syscall? wake 7 wait 3 else continue 3 - syscall halt 7 current - 3 waiter 7 waitee - continue 7 - stopped halt 3 current - 3 waitee 7 waiter - continue 3 - stopped halt 7 current - 3 waiter 7 waitee - 3 break? wake 3 wait 7 else continue 7 - current_cs.packet_type == vContc and current_cs.catch_syscalls -current_cs.kind == - and - */ - client_state *same_pid_cs = NULL; int make_waitee_a_waiter = 0; @@ -755,7 +780,7 @@ current_cs.kind == dump_client_state (__FUNCTION__, "resolved vContt"); return 0; } - default: + default: /* fall through */ current_cs->last_packet_type = current_cs->packet_type; } @@ -766,9 +791,10 @@ current_cs.kind == { case vContt: case vContc: - if ((current_cs->pending == pending_waitee)) + case vConts: + if (current_cs->pending == pending_waitee) break; - default: + default: /* fall through */ dump_client_state (__FUNCTION__, "no action taken"); return 1; } @@ -789,26 +815,22 @@ current_cs.kind == continue; switch (same_pid_cs->pending) { - case pending_cont_waiter: + case /* same_pid_cs->pending */ pending_cont_waiter: /* Found a vContc packet that is waiting */ switch (same_pid_cs->packet_type) { - case vContc: + case /* same_pid_cs->packet_type */ vContc: prepare_to_access_memory (); - /**/ if (current_cs->packet_type == vContc && (current_cs->ss->last_status_.kind == TARGET_WAITKIND_SYSCALL_ENTRY || current_cs->ss->last_status_.kind == TARGET_WAITKIND_SYSCALL_RETURN)) { if (same_pid_cs->catch_syscalls) { - waiter_cs = set_client_state (same_pid_cs->file_desc); resolve_waiter (same_pid_cs, current_cs); dump_client_state (__FUNCTION__, "resolved syscall"); - current_cs = set_client_state (current_cs->file_desc); - waiter_cs->pending = pending_waitee; - make_waitee_a_waiter = 1; + same_pid_cs->pending = pending_waitee; } else if (current_cs->catch_syscalls) { @@ -816,7 +838,11 @@ current_cs.kind == same_pid_cs_has_bp = 1; } } - /**/ + else if (current_cs->packet_type == vConts) + { + current_cs->last_cont_ptid = current_cs->ss->general_thread_; + current_cs->last_cont_waitstatus = current_cs->ss->last_status_; + } if (current_cs->ss->last_status_.kind == TARGET_WAITKIND_EXITED) { @@ -827,10 +853,17 @@ current_cs.kind == else /* not exited */ { /* Does current client have a breakpoint at PC? */ - if (get_first_thread () != NULL && set_desired_thread (1)) + if (get_first_thread () != NULL) { - struct regcache *regcache = get_thread_regcache (current_thread, 1); - CORE_ADDR pc = (*the_target->read_pc) (regcache); + struct regcache *regcache; + struct thread_info *thread; + CORE_ADDR pc; + if (non_stop) + thread = current_thread; + else + thread = find_thread_ptid (last_ptid); + regcache = get_thread_regcache (thread, 1); + pc = (*the_target->read_pc) (regcache); current_cs_has_bp = has_client_breakpoint_at (pc); waiter_cs = set_client_state (same_pid_cs->file_desc); /* Does found client have a breakpoint at PC? */ @@ -861,11 +894,13 @@ current_cs.kind == current_cs = set_client_state (current_cs->file_desc); done_accessing_memory (); - } - - break; - case pending_step_waiter: + } /* switch same_pid_cs->packet_type */ + break; /* case vContc */ + + case /* same_pid_cs->pending */ pending_step_waiter: waiter_cs = set_client_state (same_pid_cs->file_desc); + if (debug_threads) + debug_printf ("%s:%d resolving %d/%d %s", __FUNCTION__, __LINE__, current_cs->file_desc,same_pid_cs->pending,packet_types_str[current_cs->packet_type]); if (current_cs->packet_type == vConts || current_cs->packet_type == vContc) { @@ -873,7 +908,7 @@ current_cs.kind == current_cs->pending = same_pid_cs->pending = none_pending; } current_cs = set_client_state (current_cs->file_desc); - } + } /* switch same_pid_cs->pending */ } if (make_waitee_a_waiter && current_cs->packet_type == vContc) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e250aee..c0b2623 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2016-02-23 Stan Cox <scox@redhat.com> + + * gdb.server/multi-client.exp: Add next, strace, and pthreads tests. + 2016-02-06 Stan Cox <scox@redhat.com> * gdb.server/multi-client.exp: Add syscall test. diff --git a/gdb/testsuite/gdb.server/multi-client.exp b/gdb/testsuite/gdb.server/multi-client.exp index ae75ed3..d61c024 100644 --- a/gdb/testsuite/gdb.server/multi-client.exp +++ b/gdb/testsuite/gdb.server/multi-client.exp @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -exp_internal 1 +# exp_internal 1 load_lib gdbserver-support.exp set test "multi-client" @@ -31,6 +31,10 @@ set testfile3 catch-syscall set srcfile3 ../gdb.base/catch-syscall.c set testpath3 [pwd]/$subdir/$testfile3 +set testfile4 thread_check +set srcfile4 ../gdb.threads/thread_check.c +set testpath4 [pwd]/$subdir/$testfile4 + if { [prepare_for_testing $test $testfile $srcfile debug] } { return -1 } @@ -40,6 +44,9 @@ if {[build_executable $test $testfile2 $srcfile2 debug] == -1} { if {[build_executable $test $testfile3 $srcfile3 debug] == -1} { return -1 } +if {[build_executable $test $testfile4 $srcfile4 {debug pthreads}] == -1} { + return -1 +} set use_gdb_stub [target_info exists use_gdb_stub] @@ -86,9 +93,9 @@ proc start_client { N ATTACH_FLAGS } { } set gdb_spawn_id $res if { $ok == 1 } { - pass "$test gdbserver attach client $N" + pass "$test attach client $N" } else { - fail "$test gdbserver attach client $N" + fail "$test attach client $N" } return $res } @@ -109,9 +116,9 @@ proc start_strace { ATTACH_FLAGS } { } set gdb_spawn_id $res if { $ok == 1 } { - pass "$test gdbserver strace \"$expect_out(buffer)\"" + pass "$test strace \"$expect_out(buffer)\"" } else { - unresolved "$test gdbserver strace \"$expect_out(buffer)\"" + unresolved "$test strace \"$expect_out(buffer)\"" } return $res } @@ -160,44 +167,42 @@ proc gdb_command { CLIENT COMMAND RESPONSE COMMENT } { } else { if { $i == 3 } { fail "$test $COMMENT" - } else { sleep 1 } + } else { sleep 4 } } } } } -verbose "##### Run one process and attach to it" - +verbose "##### Test coordination of three clients doing break/continue" set gdb_server_spawn_id [start_gdbserver] set MULTI_GDBFLAGS "-iex \"file $testpath\" -iex \"set remotetimeout 600\" -iex \"target extended-remote localhost:65432\" -iex \"set remote exec-file $testpath\" --silent --data-directory=[file dirname $GDB]/data-directory" set gdb_client1_spawn_id [start_client 1 ""] -gdb_command 1 "b getenv" "Breakpoint 1 at" "gdbserver b getenv" +gdb_command 1 "b getenv" "Breakpoint 1 at" "b getenv" -gdb_command 1 "run" "Breakpoint 1," "gdbserver hit b getenv" +gdb_command 1 "run" "Breakpoint 1," "hit b getenv" set target_pid [get_target_pid wrapper] -# Now start a second client that attaches to the first client set gdb_client2_spawn_id [start_client 2 "-iex \"attach $target_pid\""] set gdb_client3_spawn_id [start_client 3 "-iex \"attach $target_pid\""] -gdb_command 2 "b marker" "Breakpoint 1 at" "gdbserver b marker" +gdb_command 2 "b marker" "Breakpoint 1 at" "b marker" -gdb_command 2 "continue" "Continuing" "gdbserver continue client2" +gdb_command 2 "continue" "Continuing" "continue client2" -gdb_command 3 "b wrapper.c:33" "Breakpoint 1 at" "gdbserver b exit" +gdb_command 3 "b wrapper.c:33" "Breakpoint 1 at" "b exit" -gdb_command 3 "continue" "Continuing" "gdbserver continue client3" +gdb_command 3 "continue" "Continuing" "continue client3" # Second client waits while we continue first client -gdb_command 1 "dis 1" "" "gdbserver disable breakpoint" +gdb_command 1 "dis 1" "" "disable breakpoint" -gdb_command 1 "continue" "Continuing" "gdbserver continue client1" +gdb_command 1 "continue" "Continuing" "continue client1" # The second client is back @@ -206,42 +211,97 @@ expect { -i $gdb_client2_spawn_id "Breakpoint 1, marker" { incr ok; } } if { $ok == 1 } { - pass "$test gdbserver hit b marker" + pass "$test hit b marker" } else { hooks/post-receive -- Repository for Project Archer.