Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Michael Snyder <msnyder@redhat.com>
To: Daniel Jacobowitz <drow@mvista.com>
Cc: gdb-patches@sources.redhat.com
Subject: Re: Daniel, thread vs. fork question.
Date: Fri, 19 Mar 2004 00:09:00 -0000	[thread overview]
Message-ID: <404FCD75.4080606@redhat.com> (raw)
In-Reply-To: <20040311015126.GA17829@nevyn.them.org>

[-- Attachment #1: Type: text/plain, Size: 1560 bytes --]

Daniel Jacobowitz wrote:
> On Thu, Mar 11, 2004 at 01:08:40AM +0000, Michael Snyder wrote:
> 
>>Hey Daniel,
>>
>>Got a question concerning the code in 
>>linux-nat.c::linux_handle_extended_wait.
>>
>>You've got a PTRACE_EVENT_FORK event, and now you're going to call 
>>waitpid.  You pull a pid out of a list of stopped pids, and wait for
>>it using waitpid.  In your comment, you explain that you don't have to
>>worry about the pid being a clone, because you didn't ask for pids in
>>the event mask.
>>
>>But how is this affected by threads, especially NPTL threads?
>>I've got a fairly simple test-case (modified from pthreads.c,
>>I'll attach it), in which a child thread calls fork -- but gdb
>>apparently tries to wait on the main thread (or perhaps the most
>>recent event thread).  Since that's not the thread that called
>>fork, waitpid returns -1 with "no child".  Gdb reports:
>>	waiting for new child: No child processes.
>>
>>FWIW, I've tried this on both a single-processor and an SMP machine.
> 
> 
> No attachment? 

Argh.  Inevitable, isn't it?  See currently attached.

 > Also, what glibc/nptl version are you using.

Well, it's RHEL3, so I believe it's glibc 2.3 and nptl
(not sure what version of nptl).

> It's entirely possible that I didn't handle some threaded case.  But we
> save the PID that we plan to wait on, which should be the child thread,
> so I don't see how what you're describing can happn.

It's repeatable, on at least 3 machines.  Let me know (now that I've
actually provided the test case) if you can't reproduce it.


[-- Attachment #2: pthreads.c --]
[-- Type: text/plain, Size: 4410 bytes --]

/* Pthreads test program.
   Copyright 1996, 2002, 2003
   Free Software Foundation, Inc.

   Written by Fred Fish of Cygnus Support
   Contributed by Cygnus Support

   This file is part of GDB.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#include <stdio.h>
#include <pthread.h>

/* Under OSF 2.0 & 3.0 and HPUX 10, the second arg of pthread_create
   is prototyped to be just a "pthread_attr_t", while under Solaris it
   is a "pthread_attr_t *".  Arg! */

#if defined (__osf__) || defined (__hpux__)
#define PTHREAD_CREATE_ARG2(arg) arg
#define PTHREAD_CREATE_NULL_ARG2 null_attr
static pthread_attr_t null_attr;
#else
#define PTHREAD_CREATE_ARG2(arg) &arg
#define PTHREAD_CREATE_NULL_ARG2 NULL
#endif

static int verbose = 0;

static void
common_routine (arg)
     int arg;
{
  static int from_thread1;
  static int from_thread2;
  static int from_main;
  static int hits;
  static int full_coverage;

  if (verbose) printf("common_routine (%d)\n", arg);
  hits++;
  switch (arg)
    {
    case 0:
      from_main++;
      break;
    case 1:
      from_thread1++;
      break;
    case 2:
      from_thread2++;
      break;
    }
  if (from_main && from_thread1 && from_thread2)
    full_coverage = 1;
}

static void *
thread1 (void *arg)
{
  int i;
  int z = 0;

  if (verbose) printf ("thread1 (%0x) ; pid = %d\n", arg, getpid ());
  for (i=1; i <= 10000000; i++)
    {
      if (verbose) printf("thread1 %d\n", pthread_self ());
      z += i;
      common_routine (1);
      sleep(1);
    }
  return (void *) 0;
}

static void *
thread2 (void * arg)
{
  int i;
  int k = 0;

  if (verbose) printf ("thread2 (%0x) ; pid = %d\n", arg, getpid ());
  for (i=1; i <= 10000000; i++)
    {
      if (verbose) printf("thread2 %d\n", pthread_self ());
      k += i;
      common_routine (2);
      sleep(1);
    }
  sleep(100);
  return (void *) 0;
}

static void *
forkthread (void *arg)
{
  int pid = fork ();
  int ret = 0, status = 0;

  switch (pid) {
  case 0:	/* child */
    printf ("I'm the child, my pid = %d\n", getpid ());
    break;
  case -1:	/* Parent, failed to create child */
  default:	/* Parent, fork succeeded.  */
    printf ("I'm the parent, mypid = %d, fork returned %d\n",
	    getpid (), pid);
    if (pid == -1)
      perror ("fork failed: ");
    else
      waitpid (pid, &status, 0);
  }
}

void
foo (a, b, c)
     int a, b, c;
{
  int d, e, f;

  if (verbose) printf("a=%d\n", a);
}

main(argc, argv)
     int argc;
     char **argv;
{
  pthread_t tid1, tid2, forktid;
  int j;
  int t = 0;
  void (*xxx) ();
  pthread_attr_t attr;

  if (verbose) printf ("pid = %d\n", getpid());

  foo (1, 2, 3);

#ifndef __osf__
  if (pthread_attr_init (&attr))
    {
      perror ("pthread_attr_init 1");
      exit (1);
    }
#endif

#ifdef PTHREAD_SCOPE_SYSTEM
  if (pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM))
    {
      perror ("pthread_attr_setscope 1");
      exit (1);
    }
#endif

  if (pthread_create (&tid1, PTHREAD_CREATE_ARG2(attr), thread1, (void *) 0xfeedface))
    {
      perror ("pthread_create 1");
      exit (1);
    }
  if (verbose) printf ("Made thread %d\n", tid1);
  sleep (1);

  if (pthread_create (&tid2, PTHREAD_CREATE_NULL_ARG2, thread2, (void *) 0xdeadbeef))
    {
      perror ("pthread_create 2");
      exit (1);
    }
  if (verbose) printf("Made thread %d\n", tid2);
  sleep (1);

  if (pthread_create (&forktid, PTHREAD_CREATE_NULL_ARG2, forkthread, (void *) 0xdeadbeef))
    {
      perror ("pthread_create 3 (fork)");
      exit (1);
    }
  if (verbose) printf("Made thread %d\n", tid2);

  for (j = 1; j <= 10000000; j++)
    {
      if (verbose) printf("top %d\n", pthread_self ());
      common_routine (0);
      sleep(1);
      t += j;
    }
  
  exit(0);
}


WARNING: multiple messages have this Message-ID
From: Michael Snyder <msnyder@redhat.com>
To: Daniel Jacobowitz <drow@mvista.com>
Cc: gdb-patches@sources.redhat.com
Subject: Re: Daniel, thread vs. fork question.
Date: Thu, 11 Mar 2004 02:22:00 -0000	[thread overview]
Message-ID: <404FCD75.4080606@redhat.com> (raw)
Message-ID: <20040311022200.4KhkZChPUajV91Ga-WWztWtYxsBqqiKbseyrdKmCM4o@z> (raw)
In-Reply-To: <20040311015126.GA17829@nevyn.them.org>

[-- Attachment #1: Type: text/plain, Size: 1560 bytes --]

Daniel Jacobowitz wrote:
> On Thu, Mar 11, 2004 at 01:08:40AM +0000, Michael Snyder wrote:
> 
>>Hey Daniel,
>>
>>Got a question concerning the code in 
>>linux-nat.c::linux_handle_extended_wait.
>>
>>You've got a PTRACE_EVENT_FORK event, and now you're going to call 
>>waitpid.  You pull a pid out of a list of stopped pids, and wait for
>>it using waitpid.  In your comment, you explain that you don't have to
>>worry about the pid being a clone, because you didn't ask for pids in
>>the event mask.
>>
>>But how is this affected by threads, especially NPTL threads?
>>I've got a fairly simple test-case (modified from pthreads.c,
>>I'll attach it), in which a child thread calls fork -- but gdb
>>apparently tries to wait on the main thread (or perhaps the most
>>recent event thread).  Since that's not the thread that called
>>fork, waitpid returns -1 with "no child".  Gdb reports:
>>	waiting for new child: No child processes.
>>
>>FWIW, I've tried this on both a single-processor and an SMP machine.
> 
> 
> No attachment? 

Argh.  Inevitable, isn't it?  See currently attached.

 > Also, what glibc/nptl version are you using.

Well, it's RHEL3, so I believe it's glibc 2.3 and nptl
(not sure what version of nptl).

> It's entirely possible that I didn't handle some threaded case.  But we
> save the PID that we plan to wait on, which should be the child thread,
> so I don't see how what you're describing can happn.

It's repeatable, on at least 3 machines.  Let me know (now that I've
actually provided the test case) if you can't reproduce it.


[-- Attachment #2: pthreads.c --]
[-- Type: text/plain, Size: 4410 bytes --]

/* Pthreads test program.
   Copyright 1996, 2002, 2003
   Free Software Foundation, Inc.

   Written by Fred Fish of Cygnus Support
   Contributed by Cygnus Support

   This file is part of GDB.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#include <stdio.h>
#include <pthread.h>

/* Under OSF 2.0 & 3.0 and HPUX 10, the second arg of pthread_create
   is prototyped to be just a "pthread_attr_t", while under Solaris it
   is a "pthread_attr_t *".  Arg! */

#if defined (__osf__) || defined (__hpux__)
#define PTHREAD_CREATE_ARG2(arg) arg
#define PTHREAD_CREATE_NULL_ARG2 null_attr
static pthread_attr_t null_attr;
#else
#define PTHREAD_CREATE_ARG2(arg) &arg
#define PTHREAD_CREATE_NULL_ARG2 NULL
#endif

static int verbose = 0;

static void
common_routine (arg)
     int arg;
{
  static int from_thread1;
  static int from_thread2;
  static int from_main;
  static int hits;
  static int full_coverage;

  if (verbose) printf("common_routine (%d)\n", arg);
  hits++;
  switch (arg)
    {
    case 0:
      from_main++;
      break;
    case 1:
      from_thread1++;
      break;
    case 2:
      from_thread2++;
      break;
    }
  if (from_main && from_thread1 && from_thread2)
    full_coverage = 1;
}

static void *
thread1 (void *arg)
{
  int i;
  int z = 0;

  if (verbose) printf ("thread1 (%0x) ; pid = %d\n", arg, getpid ());
  for (i=1; i <= 10000000; i++)
    {
      if (verbose) printf("thread1 %d\n", pthread_self ());
      z += i;
      common_routine (1);
      sleep(1);
    }
  return (void *) 0;
}

static void *
thread2 (void * arg)
{
  int i;
  int k = 0;

  if (verbose) printf ("thread2 (%0x) ; pid = %d\n", arg, getpid ());
  for (i=1; i <= 10000000; i++)
    {
      if (verbose) printf("thread2 %d\n", pthread_self ());
      k += i;
      common_routine (2);
      sleep(1);
    }
  sleep(100);
  return (void *) 0;
}

static void *
forkthread (void *arg)
{
  int pid = fork ();
  int ret = 0, status = 0;

  switch (pid) {
  case 0:	/* child */
    printf ("I'm the child, my pid = %d\n", getpid ());
    break;
  case -1:	/* Parent, failed to create child */
  default:	/* Parent, fork succeeded.  */
    printf ("I'm the parent, mypid = %d, fork returned %d\n",
	    getpid (), pid);
    if (pid == -1)
      perror ("fork failed: ");
    else
      waitpid (pid, &status, 0);
  }
}

void
foo (a, b, c)
     int a, b, c;
{
  int d, e, f;

  if (verbose) printf("a=%d\n", a);
}

main(argc, argv)
     int argc;
     char **argv;
{
  pthread_t tid1, tid2, forktid;
  int j;
  int t = 0;
  void (*xxx) ();
  pthread_attr_t attr;

  if (verbose) printf ("pid = %d\n", getpid());

  foo (1, 2, 3);

#ifndef __osf__
  if (pthread_attr_init (&attr))
    {
      perror ("pthread_attr_init 1");
      exit (1);
    }
#endif

#ifdef PTHREAD_SCOPE_SYSTEM
  if (pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM))
    {
      perror ("pthread_attr_setscope 1");
      exit (1);
    }
#endif

  if (pthread_create (&tid1, PTHREAD_CREATE_ARG2(attr), thread1, (void *) 0xfeedface))
    {
      perror ("pthread_create 1");
      exit (1);
    }
  if (verbose) printf ("Made thread %d\n", tid1);
  sleep (1);

  if (pthread_create (&tid2, PTHREAD_CREATE_NULL_ARG2, thread2, (void *) 0xdeadbeef))
    {
      perror ("pthread_create 2");
      exit (1);
    }
  if (verbose) printf("Made thread %d\n", tid2);
  sleep (1);

  if (pthread_create (&forktid, PTHREAD_CREATE_NULL_ARG2, forkthread, (void *) 0xdeadbeef))
    {
      perror ("pthread_create 3 (fork)");
      exit (1);
    }
  if (verbose) printf("Made thread %d\n", tid2);

  for (j = 1; j <= 10000000; j++)
    {
      if (verbose) printf("top %d\n", pthread_self ());
      common_routine (0);
      sleep(1);
      t += j;
    }
  
  exit(0);
}


  parent reply	other threads:[~2004-03-11  2:22 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-03-11  1:08 Michael Snyder
2004-03-19  0:09 ` Michael Snyder
2004-03-19  0:09 ` Daniel Jacobowitz
2004-03-11  1:51   ` Daniel Jacobowitz
2004-03-19  0:09   ` Michael Snyder [this message]
2004-03-11  2:22     ` Michael Snyder
2004-03-19 19:29     ` Michael Snyder
2004-03-19 19:39       ` Daniel Jacobowitz
2004-03-22 17:12 ` Daniel Jacobowitz
2004-03-22 20:20   ` [patch] Fix threads vs. fork following Daniel Jacobowitz
2004-03-23 20:17     ` Michael Snyder

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=404FCD75.4080606@redhat.com \
    --to=msnyder@redhat.com \
    --cc=drow@mvista.com \
    --cc=gdb-patches@sources.redhat.com \
    /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