From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2924 invoked by alias); 10 Aug 2008 21:04:34 -0000 Received: (qmail 2908 invoked by uid 22791); 10 Aug 2008 21:04:31 -0000 X-Spam-Check-By: sourceware.org Received: from hiauly1.hia.nrc.ca (HELO hiauly1.hia.nrc.ca) (132.246.100.193) by sourceware.org (qpsmtpd/0.31) with ESMTP; Sun, 10 Aug 2008 21:03:57 +0000 Received: by hiauly1.hia.nrc.ca (Postfix, from userid 1000) id DF5BE431A; Sun, 10 Aug 2008 17:03:54 -0400 (EDT) Subject: Re: [4/7] Adjust the ttrace target (HP-UX) to always register the To: drow@false.org (Daniel Jacobowitz) Date: Sun, 10 Aug 2008 21:04:00 -0000 From: "John David Anglin" Cc: pedro@codesourcery.com, gdb-patches@sourceware.org In-Reply-To: <20080810001447.GB22119@caradoc.them.org> from "Daniel Jacobowitz" at Aug 9, 2008 08:14:47 pm X-Mailer: ELM [version 2.4 PL25] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-Id: <20080810210354.DF5BE431A@hiauly1.hia.nrc.ca> Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-08/txt/msg00286.txt.bz2 > Just FYI, I've completely lost track of this thread - so when there's > anything you need approval for, please let me know. For the record, I have consolidated Pedro's three changes below. This might make it easier to review the changes. Dave -- J. David Anglin dave.anglin@nrc-cnrc.gc.ca National Research Council of Canada (613) 990-0752 (FAX: 952-6602) Index: inf-ttrace.c =================================================================== RCS file: /cvs/src/src/gdb/inf-ttrace.c,v retrieving revision 1.30 diff -u -3 -p -r1.30 inf-ttrace.c --- inf-ttrace.c 9 Jul 2008 22:23:05 -0000 1.30 +++ inf-ttrace.c 10 Aug 2008 20:41:29 -0000 @@ -33,6 +33,7 @@ #include "gdb_string.h" #include #include +#include #include "inf-child.h" #include "inf-ttrace.h" @@ -513,10 +514,22 @@ Detaching after fork from child process if (follow_child) { + struct thread_info *ti; + /* The child will start out single-threaded. */ - inf_ttrace_num_lwps = 0; + inf_ttrace_num_lwps = 1; inf_ttrace_num_lwps_in_syscall = 0; + /* Delete parent. */ + delete_thread_silent (ptid_build (pid, lwpid, 0)); + + /* Add child. inferior_ptid was already set above. */ + ti = add_thread_silent (inferior_ptid); + ti->private = + xmalloc (sizeof (struct inf_ttrace_private_thread_info)); + memset (ti->private, 0, + sizeof (struct inf_ttrace_private_thread_info)); + /* Reset breakpoints in the child as appropriate. */ follow_inferior_reset_breakpoints (); } @@ -721,8 +734,13 @@ inf_ttrace_attach (char *args, int from_ (uintptr_t)&tte, sizeof tte, 0) == -1) perror_with_name (("ttrace")); - inferior_ptid = pid_to_ptid (pid); push_target (ttrace_ops_hack); + + /* We'll bump inf_ttrace_num_lwps up and add the private data to the + thread as soon as we get to inf_ttrace_wait. At this point, we + don't have lwpid info yet. */ + inferior_ptid = pid_to_ptid (pid); + add_thread_silent (inferior_ptid); } static void @@ -784,52 +802,85 @@ inf_ttrace_kill (void) target_mourn_inferior (); } +/* Check is a dying thread is dead by now, and delete it from GDBs + thread list if so. */ static int -inf_ttrace_resume_callback (struct thread_info *info, void *arg) +inf_ttrace_delete_dead_threads_callback (struct thread_info *info, void *arg) { - if (!ptid_equal (info->ptid, inferior_ptid)) - { - pid_t pid = ptid_get_pid (info->ptid); - lwpid_t lwpid = ptid_get_lwp (info->ptid); + lwpid_t lwpid; + struct inf_ttrace_private_thread_info *p; - if (ttrace (TT_LWP_CONTINUE, pid, lwpid, TT_NOPC, 0, 0) == -1) - perror_with_name (("ttrace")); - } + if (is_exited (info->ptid)) + return 0; + + lwpid = ptid_get_lwp (info->ptid); + p = (struct inf_ttrace_private_thread_info *) info->private; + + /* Check if an lwp that was dying is still there or not. */ + if (p->dying && (kill (lwpid, 0) == -1)) + /* It's gone now. */ + delete_thread (info->ptid); return 0; } +/* Resume the lwp pointed to by INFO, with REQUEST, and pass it signal + SIG. */ + +static void +inf_ttrace_resume_lwp (struct thread_info *info, ttreq_t request, int sig) +{ + pid_t pid = ptid_get_pid (info->ptid); + lwpid_t lwpid = ptid_get_lwp (info->ptid); + + if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1) + { + struct inf_ttrace_private_thread_info *p + = (struct inf_ttrace_private_thread_info *) info->private; + if (p->dying && errno == EPROTO) + /* This is expected, it means the dying lwp is really gone + by now. If ttrace had an event to inform the debugger + the lwp is really gone, this wouldn't be needed. */ + delete_thread (info->ptid); + else + /* This was really unexpected. */ + perror_with_name (("ttrace")); + } +} + +/* Callback for iterate_over_threads. */ + static int -inf_ttrace_delete_dying_threads_callback (struct thread_info *info, void *arg) +inf_ttrace_resume_callback (struct thread_info *info, void *arg) { - if (((struct inf_ttrace_private_thread_info *)info->private)->dying == 1) - delete_thread (info->ptid); + if (!ptid_equal (info->ptid, inferior_ptid) && !is_exited (info->ptid)) + inf_ttrace_resume_lwp (info, TT_LWP_CONTINUE, 0); + return 0; } static void inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal) { - pid_t pid = ptid_get_pid (ptid); - lwpid_t lwpid = ptid_get_lwp (ptid); + int resume_all; ttreq_t request = step ? TT_LWP_SINGLE : TT_LWP_CONTINUE; int sig = target_signal_to_host (signal); + struct thread_info *info; - if (pid == -1) - { - pid = ptid_get_pid (inferior_ptid); - lwpid = ptid_get_lwp (inferior_ptid); - } + /* A specific PTID means `step only this process id'. */ + resume_all = (ptid_equal (ptid, minus_one_ptid)); - if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1) - perror_with_name (("ttrace")); - - if (ptid_equal (ptid, minus_one_ptid) && inf_ttrace_num_lwps > 0) - { - /* Let all the other threads run too. */ - iterate_over_threads (inf_ttrace_resume_callback, NULL); - iterate_over_threads (inf_ttrace_delete_dying_threads_callback, NULL); - } + /* If resuming all threads, it's the current thread that should be + handled specially. */ + if (resume_all) + ptid = inferior_ptid; + + info = find_thread_pid (ptid); + inf_ttrace_resume_lwp (info, request, sig); + + if (resume_all) + /* Let all the other threads run too. */ + iterate_over_threads (inf_ttrace_resume_callback, NULL); } static ptid_t @@ -886,6 +937,30 @@ inf_ttrace_wait (ptid_t ptid, struct tar ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); + if (inf_ttrace_num_lwps == 0) + { + struct thread_info *ti; + + inf_ttrace_num_lwps = 1; + + /* This is the earliest we hear about the lwp member of + INFERIOR_PTID, after an attach or fork_inferior. */ + gdb_assert (ptid_get_lwp (inferior_ptid) == 0); + + /* We haven't set the private member on the main thread yet. Do + it now. */ + ti = find_thread_pid (inferior_ptid); + gdb_assert (ti != NULL && ti->private == NULL); + ti->private = + xmalloc (sizeof (struct inf_ttrace_private_thread_info)); + memset (ti->private, 0, + sizeof (struct inf_ttrace_private_thread_info)); + + /* Notify the core that this ptid changed. This changes + inferior_ptid as well. */ + thread_change_ptid (inferior_ptid, ptid); + } + switch (tts.tts_event) { #ifdef TTEVT_BPT_SSTEP @@ -958,17 +1033,6 @@ inf_ttrace_wait (ptid_t ptid, struct tar case TTEVT_LWP_CREATE: lwpid = tts.tts_u.tts_thread.tts_target_lwpid; ptid = ptid_build (tts.tts_pid, lwpid, 0); - if (inf_ttrace_num_lwps == 0) - { - /* Now that we're going to be multi-threaded, add the - original thread to the list first. */ - ti = add_thread (ptid_build (tts.tts_pid, tts.tts_lwpid, 0)); - ti->private = - xmalloc (sizeof (struct inf_ttrace_private_thread_info)); - memset (ti->private, 0, - sizeof (struct inf_ttrace_private_thread_info)); - inf_ttrace_num_lwps++; - } ti = add_thread (ptid); ti->private = xmalloc (sizeof (struct inf_ttrace_private_thread_info)); @@ -976,7 +1040,12 @@ inf_ttrace_wait (ptid_t ptid, struct tar sizeof (struct inf_ttrace_private_thread_info)); inf_ttrace_num_lwps++; ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - break; + /* Let the lwp_create-caller thread continue. */ + ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), + ptid_get_lwp (ptid), TT_NOPC, 0, 0); + /* Return without stopping the whole process. */ + ourstatus->kind = TARGET_WAITKIND_IGNORE; + return ptid; case TTEVT_LWP_EXIT: if (print_thread_events) @@ -985,22 +1054,31 @@ inf_ttrace_wait (ptid_t ptid, struct tar gdb_assert (ti != NULL); ((struct inf_ttrace_private_thread_info *)ti->private)->dying = 1; inf_ttrace_num_lwps--; + /* Let the thread really exit. */ ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), ptid_get_lwp (ptid), TT_NOPC, 0, 0); - /* If we don't return -1 here, core GDB will re-add the thread. */ - ptid = minus_one_ptid; - break; + /* Return without stopping the whole process. */ + ourstatus->kind = TARGET_WAITKIND_IGNORE; + return ptid; case TTEVT_LWP_TERMINATE: lwpid = tts.tts_u.tts_thread.tts_target_lwpid; ptid = ptid_build (tts.tts_pid, lwpid, 0); - printf_filtered(_("[%s has been terminated]\n"), target_pid_to_str (ptid)); + if (print_thread_events) + printf_unfiltered(_("[%s has been terminated]\n"), + target_pid_to_str (ptid)); ti = find_thread_pid (ptid); gdb_assert (ti != NULL); ((struct inf_ttrace_private_thread_info *)ti->private)->dying = 1; inf_ttrace_num_lwps--; + + /* Resume the lwp_terminate-caller thread. */ ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0); - break; + ttrace (TT_LWP_CONTINUE, ptid_get_pid (ptid), + ptid_get_lwp (ptid), TT_NOPC, 0, 0); + /* Return without stopping the whole process. */ + ourstatus->kind = TARGET_WAITKIND_IGNORE; + return ptid; case TTEVT_SIGNAL: ourstatus->kind = TARGET_WAITKIND_STOPPED; @@ -1045,10 +1123,15 @@ inf_ttrace_wait (ptid_t ptid, struct tar if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1) perror_with_name (("ttrace")); - /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a - process isn't recognized as a new thread. */ - if (ptid_get_lwp (inferior_ptid) == 0) - inferior_ptid = ptid; + /* Now that the whole process is stopped, check if any dying thread + is really dead by now. If a dying thread is still alive, it will + be stopped too, and will still show up in `info threads', tagged + with "(Exiting)". We could make `info threads' prune dead + threads instead via inf_ttrace_thread_alive, but doing this here + has the advantage that a frontend is notificed sooner of thread + exits. Note that a dying lwp is still alive, it still has to be + resumed, like any other lwp. */ + iterate_over_threads (inf_ttrace_delete_dead_threads_callback, NULL); return ptid; } @@ -1120,26 +1203,38 @@ inf_ttrace_files_info (struct target_ops static int inf_ttrace_thread_alive (ptid_t ptid) { - struct thread_info *ti; - ti = find_thread_pid (ptid); - return !(((struct inf_ttrace_private_thread_info *)ti->private)->dying); + return 1; } +/* Return a string describing the state of the thread specified by + INFO. */ + static char * -inf_ttrace_pid_to_str (ptid_t ptid) +inf_ttrace_extra_thread_info (struct thread_info *info) { - if (inf_ttrace_num_lwps > 0) - { - pid_t pid = ptid_get_pid (ptid); - lwpid_t lwpid = ptid_get_lwp (ptid); - static char buf[128]; + struct inf_ttrace_private_thread_info* private = + (struct inf_ttrace_private_thread_info *) info->private; - xsnprintf (buf, sizeof buf, "process %ld, lwp %ld", - (long)pid, (long)lwpid); - return buf; - } + if (private != NULL && private->dying) + return "Exiting"; + + return NULL; +} + +static char * +inf_ttrace_pid_to_str (ptid_t ptid) +{ + pid_t pid = ptid_get_pid (ptid); + lwpid_t lwpid = ptid_get_lwp (ptid); + static char buf[128]; - return normal_pid_to_str (ptid); + if (lwpid == 0) + xsnprintf (buf, sizeof buf, "process %ld", + (long) pid); + else + xsnprintf (buf, sizeof buf, "process %ld, lwp %ld", + (long) pid, (long) lwpid); + return buf; } @@ -1164,6 +1259,7 @@ inf_ttrace_target (void) t->to_follow_fork = inf_ttrace_follow_fork; t->to_mourn_inferior = inf_ttrace_mourn_inferior; t->to_thread_alive = inf_ttrace_thread_alive; + t->to_extra_thread_info = inf_ttrace_extra_thread_info; t->to_pid_to_str = inf_ttrace_pid_to_str; t->to_xfer_partial = inf_ttrace_xfer_partial;