Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Pedro Alves <palves@redhat.com>
To: Don Breazeal <donb@codesourcery.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH v7 6/7] Remote fork catch
Date: Wed, 15 Apr 2015 15:39:00 -0000	[thread overview]
Message-ID: <552E8630.7060103@redhat.com> (raw)
In-Reply-To: <1428685786-18094-7-git-send-email-donb@codesourcery.com>

On 04/10/2015 06:09 PM, Don Breazeal wrote:
> Hi Pedro,
> This version of the patch incorporates changes based on your comments on
> the previous version, as outlined below.
> 
> On 3/24/2015 5:47 AM, Pedro Alves wrote:
>> On 03/17/2015 08:56 PM, Don Breazeal wrote:
>>
>>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>>> index 8fa6f8a..346f2c4 100644
>>> --- a/gdb/gdbserver/server.c
>>> +++ b/gdb/gdbserver/server.c
>>> @@ -1356,6 +1356,15 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
>>>    int core = target_core_of_thread (ptid);
>>>    char core_s[21];
>>>  
>>> +  /* Skip new threads created as the result of a fork if we are not done
>>> +     handling that fork event.  We won't know whether to tell GDB about
>>> +     the new thread until we are done following the fork.  */
>>> +  if ((last_status.kind == TARGET_WAITKIND_FORKED
>>> +       || last_status.kind == TARGET_WAITKIND_VFORKED)
>>> +      && (ptid_get_pid (last_status.value.related_pid)
>>> +	  == ptid_get_pid (ptid)))
>>> +    return;
>>
>> This use of last_status here is really just as bad as
>> get_last_target_status, for the same reasons.  What if a thread
>> forks at the same time another thread hits a breakpoint, and
>> we end up reporting the breakpoint first, leaving the fork
>> pending?  Sounds like we'll end up listing the child fork
>> thread then.
> 
> I moved this operation (removing the new, unreported thread from the list
> reported by the target) to the host side in remote.c:remove_new_fork_child,
> called from remote.c:remote_update_thread_list.

Agreed, I think that's the right thing to do.  This gives us the
most flexibility to change the follow-fork model in core gdb.

Also, if you disconnect while stopped at an unfollowed fork, and then
reconnect, it's not clear to me whether the child should be
hidden from the user until the next continue then.  Again, leaving it
up to the client gives us the flexibility either way.

>>> diff --git a/gdb/testsuite/gdb.threads/fork-thread-pending.exp b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
>>> index d229232..594f376 100644
>>> --- a/gdb/testsuite/gdb.threads/fork-thread-pending.exp
>>> +++ b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
>>> @@ -31,6 +31,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab
>>>      return -1
>>>  }
>>>  
>>> +# Find a thread that did not fork and is not the main thread and
>>> +# return its thread number.  We can't just hard-code the thread
>>> +# number since we have no guarantee as to the ordering of the threads
>>> +# in gdb.  
>>
>> I don't understand this -- the test runs to main first, so the main
>> thread should always be thread 1, no?
>>
> 
> I can no longer reproduce the thread ordering problem that I was seeing
> when I implemented this.  Not sure why...my notes imply it might have
> something to do with 'target remote', but I'm unsure at this point.  

Maybe it was necessary before:

  https://sourceware.org/ml/gdb-patches/2014-09/msg00734.html

> At any rate this test doesn't need to be changed for this patch, so
> I've removed it from the patch.


> 
> BTW, I still intend to submit a patch that removes the need to use 
> get_last_target_status in linux-nat.c:linux_nat_kill, along with a test
> for that scenario.

That'd be great!


> +/* Determine if THREAD is a pending fork parent thread.  ARG contains
> +   the pid of the process who's threads we want to check, or -1 if
> +   we want to check all threads.  */
> +
> +static int
> +pending_fork_parent_callback (struct thread_info *thread, void *arg)
> +{
> +  int pid = *(int *) arg;
> +
> +  if (thread->pending_follow.kind == TARGET_WAITKIND_FORKED
> +      || thread->pending_follow.kind == TARGET_WAITKIND_VFORKED)
> +    {
> +      if ((pid == -1) || (pid == ptid_get_pid (thread->ptid)))

Unnecessary parens:

      if (pid == -1 || pid == ptid_get_pid (thread->ptid))


> +	return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +/* If CONTEXT contains any fork child threads that have not been
> +   reported yet, remove them from the CONTEXT list.  If such a
> +   thread exists it is because we are stopped at a fork catchpoint
> +   and have not yet called follow_fork, which will set up the
> +   host-side data structures for the new process.  */
> +
> +static void
> +remove_new_fork_child (struct threads_listing_context *context)
> +{
> +  struct thread_info * thread;
> +  int pid = -1;
> +
> +  /* Check to see if there is an in-progress fork parent.  */
> +  thread = iterate_over_threads (pending_fork_parent_callback, &pid);
> +  if (thread != NULL)

In non-stop mode, if you're debugging multiple process, multiple
processes can fork at the same, and then we end up with multiple
threads with an in-progress fork parent.  So this needs to walk
the whole thread list, not just stop at the first.  Either
use ALL_NON_EXITED_THREADS, or move the loop below to
pending_fork_parent_callback (or to a helper function called
by that).

> +    {
> +      ptid_t child_ptid = thread->pending_follow.value.related_pid;
> +      struct thread_item *item;
> +      int i;
> +
> +      for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
> +	{
> +	  if (ptid_equal (item->ptid, child_ptid))
> +	    {
> +	      VEC_ordered_remove (thread_item_t, context->items, i);
> +	      break;
> +	    }
> +	}
> +    }
> +}
> +
>  /* Implement the to_update_thread_list function for the remote
>     targets.  */
>  
> @@ -2874,6 +2964,10 @@ remote_update_thread_list (struct target_ops *ops)
>  	    }
>          }
>  
> +      /* Remove any unreported fork child from CONTEXT so that
> +	 we don't interfere with follow fork.  */
> +      remove_new_fork_child (&context);

I think there's a race here, in non-stop mode.  Consider:

 #1 - process forks just before gdb starts fetching the remote thread
      list.
 #2 - gdbserver adds the fork child  its thread list.
 #3 - gdbserver queues the fork event, sends vStopped notification
 #4 - gdb/remote_update_thread_list pulls the thread list
 #5 - we're now in remove_new_fork_child, but we don't know
      about the fork event yet.  It's still pending in the vStopped
      queue.

So I think that we need to make remote_update_thread_list do,
in this order:

 #1 - fetch the remote thread list
 #2 - fetch the pending vStopped notifications
        (remote_notif_get_pending_events)
 #3 - call remove_new_fork_child
 #4 - add threads we don't know about yet to our list.

and make remove_new_fork_child also peek at the
pending vStopped events queue (and in the future at
any other layers of pending events in the core side.)

> +      child_pid = ptid_get_pid (thread->pending_follow.value.related_pid);
> +      res = remote_vkill (child_pid, rs);
> +      if (res != 0)
> +	error (_("Can't kill fork child process"));

It'll probably be good to include the PID in the error message.

> +    }

Thanks,
Pedro Alves


      reply	other threads:[~2015-04-15 15:39 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-10 17:09 [PATCH v7 0/7] Remote fork events Don Breazeal
2015-04-10 17:10 ` [PATCH v7 3/7] Extended-remote Linux follow fork Don Breazeal
2015-04-15 15:38   ` Pedro Alves
2015-04-10 17:10 ` [PATCH v7 1/7] Identify remote fork event support Don Breazeal
2015-04-15 15:37   ` Pedro Alves
2015-04-10 17:10 ` [PATCH v7 4/7] Arch-specific remote follow fork Don Breazeal
2015-04-10 17:10 ` [PATCH v7 2/7] Clone remote breakpoints Don Breazeal
2015-04-10 17:11 ` [PATCH v7 7/7] Extended-remote follow fork documentation Don Breazeal
2015-04-10 17:56   ` Eli Zaretskii
2015-04-10 18:15     ` Breazeal, Don
2015-04-10 18:29       ` Eli Zaretskii
2015-04-10 20:43         ` Don Breazeal
2015-04-15 15:47           ` Pedro Alves
2015-04-10 17:11 ` [PATCH v7 5/7] Remote follow vfork Don Breazeal
2015-04-15 15:38   ` Pedro Alves
2015-04-15 15:41     ` Pedro Alves
2015-04-10 17:11 ` [PATCH v7 6/7] Remote fork catch Don Breazeal
2015-04-15 15:39   ` Pedro Alves [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=552E8630.7060103@redhat.com \
    --to=palves@redhat.com \
    --cc=donb@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox