This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Daniel, thread vs. fork question.


Michael Snyder wrote:
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.

Hey Daniel, have you had a chance to try and reproduce this? I've now had a second (completely unrelated) person call it to my attention. New information -- I've got two fenceposts for you.

Apparently this did not happen as of 11/29/2002, but did happen
as of 1/6/2004.  These dates are from the internal Red Hat
repository, though, so they probably lag the dates in sourceware
somewhat.




------------------------------------------------------------------------

/* 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);
}





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]