Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 194741 Details for
Bug 289411
Failure to attach to a pthread
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
Reproducer code
test_threads.cxx (text/x-c++src), 22.37 KB, created by
Seppo Sahrakorpi
on 2007-09-13 16:18:08 UTC
(
hide
)
Description:
Reproducer code
Filename:
MIME Type:
Creator:
Seppo Sahrakorpi
Created:
2007-09-13 16:18:08 UTC
Size:
22.37 KB
patch
obsolete
>/* Linux sys_clone test program */ >/* > >/* Arguments be passed to this program: */ > >/* Set 1: Just clone the VM; result is a new thread group ID (tgid = lwpid) > and the parent pid is the "real pid" > */ >/* CMD: set tx_args_simple_vm "-quiet" */ > >/* Set 2: Set all the flags David Addison says the Elan software sets in June 2006. > (See the tr totalview/9230 for a bit more information.) > The "clone_thread" flag, included here, causes the thread group ID to be > inherited (tgid = real process ID) and the ppid is the grandparent (typically > TotalView). We need to recognize both cases and get the associations right > either way. > */ >/* CMD: set tx_args_threadlike "-quiet -fs -files -sighand -thread -detached" */ > > >/**********************************************************************/ >/* WHAT THIS DOES > > This provides several tests of our clone handling. > > It should be built two different ways, to produce two executables: > > g++ -g -o tx_threads_and_clones ../tests/src/tx_threads_and_clones.cxx > g++ -DPTHREADS_TOO -g -o tx_threads_and_clones_pt ../tests/src/tx_threads_and_clones.cxx -lpthread > > The first, "tx_threads_and_clones", just uses clone() calls to produce threads. > Since it's linked without pthreads, and (obviously) never starts pthreads, TV never > starts user threads; this is our only test of kernel-level threads in Linux. > > The second, "tx_threads_and_clones_pt", is linked with pthreads, and it creates > both pthreads and clones. It provides a test of our ability to pick up and > manipulate both at once, as well as a test of the proper functioning of the > follow_clone state variable, which controls exactly when we follow clone calls. > > Ideally the tests should be run more than once with various sets of flags passed to > clone() since there are some subtle differences in how we pick up the clones in various > cases. At least, one subtest should be chosen to run with several sets of clone flags. > > The tests should be structured as follows: > > (A) tx_threads_and_clones tests (no pthreads): > > Load the executable, and then run make_actions on the source file. > Set the arguments to be passed to the target to $tx_args_simple_vm; > leave them that way for tests A-1 and A-2. > > Test A-1: No clone following, clone_vm flag only: > > a) Set TV::follow_clone to 0. > b) Disable the TV barrier: ddisable $tx_barr > c) Disable the second breakpiont: ddisable $tx_pt_joined > d) Run to first breakpoint, list threads (should be just 1) > e) Run to final breakpoint, list threads (should be just 1) > f) Run target to exit > > Test A-2: Clone following, clone_vm flag only: > > a) Set TV::follow_clone to 1 > b) Enable the TV barrier: denable $tx_barr (leave tx_bp2 disabled, though) > c) Run to first breakpoint, list threads (should be 5, 1.1 through 1.5, all are workers) > d) Run to TV barrier, show status > e) Run to final breakpoint, list threads (should be just 1) > f) Kill target > > Test A-3: Clone following, threadlike arguments to clone() > > a) Set the target arguments to $tx_args_threadlike > b) Proceed as in A-2 > c) Leave the arguments set to $tx_args_threadlike for the remainder of the tests. > > (B) tx_threads_and_clones_pt tests (with pthreads, threadlike arguments to clone()): > > Load the executable, and then run make_actions on the source file. > We should TURN OFF the "threadlike" clone flags here to save execution time -- we have no > way to wait for the clones when they're threadlike so we sleep and hope for the best, > which is very slow and unreliable. > > Test B-1: No clone following: > Set arguments back to $tx_args_simple_vm > > a) Set TV::follow_clone to 0. > b) Disable the TV barrier: ddisable $tx_barr > c) Disable the second breakpiont: ddisable $tx_pt_joined > d) Run to first breakpoint, list threads (should be pthreads 1.1 through 1.5, nothing else) > e) Run to final breakpoint, list threads (should be just 1) > f) Kill target (or run to exit) > > Test B-2: Default clone following: > > a) Set TV::follow_clone to 1 (follow clones until first pthread is created) > b) Disable the TV barrier: ddisable $tx_barr > => NB -- The clones can't stop at the barrier because they're marked as "manager" > threads when we're running with pthreads! > c) Enable the intermediate breakpoint: denable $tx_pt_joined > d) Run to first breakpoint, list threads (should be pthreads 1.1 through 1.5 **AND** clones -1 through -4) > Verify that workers group contains pthreads but no clones. > [ DON'T: e) Add all clones to the workers group ] > [ DON'T: f) Run to TV barrier, show status ] > g) Run to breakpoint after pthread_join, list threads (clones should be there, but not pthreads) > e) Run to final breakpoint, list threads (should be just 1) > f) Kill target (or run to exit) > > Test B-3: Default clone following, with extra clones: > > a) Set TV::follow_clone to 1 (follow clones until first pthread is created) > b) Disable the TV barrier: ddisable $tx_barr > c) Enable the intermediate breakpoint: denable $tx_pt_joined > e) Pass argument "-more_clones" to target > f) Run to first breakpoint, list threads (should be pthreads 1.1 through 1.5 **AND** clones -1 through -4) > Verify that workers group contains pthreads but no clones. > g) Run to breakpoint after pthread_join, list threads (clones should be there, but not pthreads) > h) Run to final breakpoint, list threads (should be just 1) > i) Kill target (or run to exit) > > Test B-4: Full clone following, with extra clones: > Set the target arguments to $tx_args_threadlike for this last test > > a) Set TV::follow_clone to 2 (follow clones unconditionally) > b) Disable the TV barrier: denable $tx_barr > => NB -- The clones can't stop at the barrier because they're marked as "manager" > threads when we're running with pthreads! > c) Enable the intermediate breakpoint: denable $tx_pt_joined > e) Pass argument "-more_clones" to target > f) Run to first breakpoint, list threads (should be pthreads 1.1 through 1.5 **AND** clones -1 through -7) > Verify that workers group contains pthreads but no clones. > [ DON'T: g) Add all clones to the workers group ] > [ DON'T: h) Run to TV barrier, show status ] > i) Run to breakpoint after pthread_join, list threads (clones should be there, but not pthreads) > j) Run to final breakpoint, list threads (should be just 1) > k) Kill target (or run to exit) > > */ >/**********************************************************************/ > > >#include <unistd.h> >#include <stdlib.h> >#include <signal.h> >#include <syscall.h> >#include <stdio.h> >#include <errno.h> >#include <sched.h> >#include <time.h> >#include <string.h> >#include <sys/wait.h> > >#if defined(PTHREADS_TOO) > >#include <pthread.h> > >int pthread_count = 4; >int sleep_after_thread_create = 0; > >#else > >int pthread_count = 0; /* We need this value even when we're compiled without pthreads. */ > >#endif /* PTHREADS_TOO */ > >int total_clones = 0; >int more_clones = 0; >int use_locking = 1; >volatile long hack_locker = 0; >int clone_count = 4; >int extra_clone_count = 3; >int lock_timeout = 5; /* Seconds */ >int threadlike_clones = 0; /* Set => we can't use waitpid() to wait for them! */ >int clones_exit = 0; /* Set => they don't spin, they exit; only works on some systems. */ >volatile int ok_for_clones_to_exit = 0; /* Sloppy barrier to keep the clones from exiting too early */ > >int quiet = 0; > >struct hack_barr_t; >hack_barr_t *create_barr; /* Barrier all clones and pthreads hit after creation */ >hack_barr_t *clone_exit_barr; /* Barrier all clones hit just before they exit */ > >long printf_lock = 0; > >#define NS_USEC 1000 >#define NS_MSEC (NS_USEC * 1000) > >/**********************************************************************/ > >static int breakpointable (int ignored) >{ > int computed = ignored; > computed += 1; > computed = computed * computed + ignored * ignored; > if (computed < 0) /* Sum of two squares won't be negative. Compiler won't know that (we hope). */ > printf ("breakpointable got a negative result??\n"); > > if (!quiet) > printf ("breakpointable, call %d\n", ignored); > return (ignored + computed); >} /* breakpointable */ > >/**********************************************************************/ >/* This is just a place for TotalView to put a barrier point. > NB -- All clones should be added to the worker group before hitting this > or it may not work right. > */ > >static void tv_barrier (long me) >{ > if (!quiet) > printf ("Thread %ld in tv_barrier()\n", me); > > breakpointable (10); /* CMD: set tx_barr [dfocus pW dbarrier %LINENO% -stop_when_hit none -stop_when_done process] */ > > if (!quiet) > printf ("Thread %ld leaving tv_barrier()\n", me); >} /* tv_barrier */ > >/**********************************************************************/ >/* Sleep a while */ > >void sleep_seconds (int seconds) >{ > struct timespec sec_delay; > sec_delay.tv_sec = seconds; > sec_delay.tv_nsec = 0; > nanosleep (&sec_delay, 0); >} /* sleep_seconds */ > >void sleep_msec (int milliseconds) >{ > int seconds = milliseconds/1000; > milliseconds -= (seconds * 1000); > > struct timespec sec_delay; > sec_delay.tv_sec = seconds; > sec_delay.tv_nsec = milliseconds * NS_MSEC; > nanosleep (&sec_delay, 0); >} /* sleep_msec */ > >/**********************************************************************/ >/* Wait until someone passes us the lock */ > >void hack_lock (volatile long *lock, long me) >{ > if (!use_locking) > return; > > time_t then = time (0); > while (me != *lock) > { > time_t now = time(0); > if (now > then + lock_timeout) > { > fprintf (stderr, "OOPS -- tx_threads_and_clones thread %ld timed out waiting for the lock\n", > long(me)); > exit(1); > } > sleep_msec (100); /* 1/10 second */ > } /* while */ >} /* hack_lock */ > >/**********************************************************************/ >/* Pass the lock to the next thread */ > >void hack_give_lock_to (volatile long *lock, long him) >{ > *lock = him; /* We depend on write-byte being atomic, and we never change the high 3 bytes */ >} /* hack_give_lock_to */ > >/**********************************************************************/ >/* A barrier written using nanosleep and hack_lock. > The barrier must be initialized by the main thread by setting > bar_lock to the lowest thread which will hit the barrier. > > Barriers can be very simple _IF_ you don't care about performance. > The heart of a Posix barrier is a Posix condition variable, which > releases instantly and doesn't poll which is why it requires > require black magic in their implementation. > */ > >struct hack_barr_t { > volatile long lock; > volatile int arrived; > volatile int generation; > int start_thread; > int count; > > public: > hack_barr_t (long start_thread_, int count_) { > start_thread = start_thread_; > count = count_; > lock = start_thread; > arrived = 0; > generation = 0; > } > > void release () { > arrived = 0; > generation++; > lock = start_thread; /* Unlock at the end */ > } >}; > >void hack_barrier (long me, hack_barr_t *barr) >{ > if (!use_locking) /* If we're actually forking unshared objects we can't use a shared-memory barrier. */ > return; > > hack_lock (&(barr->lock), me); > /* We now have the barrier lock */ > //if (!quiet) /* This is sequenced, we can print it in the test, too. */ > printf ("Thread %ld in hack_barrier; generation=%d, arrived=%d, count=%d\n", > me, barr->generation, barr->arrived, barr->count); > int barr_oldgen = barr->generation; > barr->arrived ++; > if (barr->arrived == barr->count) > { > printf ("Thread %ld releasing the hack_barrier\n", me); > barr->release(); > } /* if */ > else > { > hack_give_lock_to (&(barr->lock), me+1); /* Pass the lock along */ > time_t then = time (0); > while (barr->generation == barr_oldgen) > { > time_t now = time (0); > if (now > then + lock_timeout) > { > fprintf (stderr, "OOPS -- tx_threads_and_clones thread %ld timed out waiting for barrier\n", > long(me)); > exit (1); > } > sleep_msec (100); > } > } >} /* hack_barrier */ > >/**********************************************************************/ > >int clone_fn(void *arg) >{ > unsigned long me = (unsigned long)arg; > hack_barrier (me, create_barr); > > hack_lock (&printf_lock, me); > //write (2, "clone hello\n", 12); > if (!quiet) > printf ("Hello from clone %ld, getpid=%d, getppid=%d\n", me, int(getpid()), int(getppid())); > else > printf ("Hello from clone %ld\n", me); > hack_give_lock_to (&printf_lock, me+1); > > tv_barrier (me); > > /* Now print the exit message */ > hack_lock (&printf_lock, me); > printf ("Goodbye from clone %ld\n", me); > hack_give_lock_to (&printf_lock, me+1); > //sleep_seconds (10); > hack_barrier (me, clone_exit_barr); > > if (!clones_exit) > while (!ok_for_clones_to_exit) > sleep_msec(100); > > return (0); /* Just return -- exit(0) takes down the whole process if clone_thread was passed */ >} > >/**********************************************************************/ >/* Get the next "me" index */ > >long next_clone_me_index () >{ > static long next_index = 1; > return (next_index++); >} /* next_clone_me_index */ > >/**********************************************************************/ >/* Create a clone, giving it the next clone ID for "me" */ > >#define STACKSIZE 64000 >#define STACKTOP_OFFSET (STACKSIZE - sizeof(int)) > >void make_clone (int clone_flags) >{ > long me_index = next_clone_me_index(); > char *new_stack = (char*)malloc (STACKSIZE); > int clone_pid = clone (clone_fn, (void*)(new_stack + STACKTOP_OFFSET), > clone_flags, > (void*)me_index); > if (clone_pid < 0) > { > perror("clone"); > exit(1); > } > else > { > if (!quiet) > printf ("%d: Created clone %ld: clone_pid == %d\n", getpid(), me_index, clone_pid); > else > printf ("Created clone %ld\n", me_index); > } >} /* make_clone */ > >/**********************************************************************/ >/* Join all the clones ... well, actually, just wait for them. */ > >void join_clones () >{ > if (!clones_exit) > { > if (!quiet) > printf ("join_clones: Not joining clones -- just returning\n"); > return; > } > > if (!quiet) > printf ("join_clones: Waiting for clones\n"); > pid_t wait_result; > int clones_waited_for = 0; > if (!threadlike_clones) > { > do { > do { > errno = 0; > wait_result = waitpid (-1, 0, __WCLONE); > } while (wait_result == (pid_t)(-1) && errno == EINTR); > > if (!quiet) > printf ("wait returned %d, errno=%d\n", > int(wait_result), int(errno)); > if (wait_result != (pid_t)(-1)) > clones_waited_for++; > } while (wait_result != (pid_t)(-1) || errno != ECHILD); > } > if (!clones_waited_for) > { /* Oops -- waited for none?? They must be threadlike. */ > if (!quiet) > { > if (!threadlike_clones) > printf ("join_clones: Got an instant ECHILD -- sleeping for a while and hoping they all exit\n"); > else > printf ("join_clones: Using threadlike clones; wait won't work -- sleeping for a while and hoping they all exit\n"); > } > sleep_seconds (5); /* We don't know how to wait for thread-clones, unfortunately. */ > } > if (!quiet) > printf ("join_clones: Done; waited on %d clones.\n", clones_waited_for); >} /* join_clones */ > >#if defined(PTHREADS_TOO) >/**********************************************************************/ >/* PTHREADS CODE -- Included only if PTHREADS_TOO is set */ >/**********************************************************************/ > >pthread_t thread_ptids[255]; > >/**********************************************************************/ >/* Action routine for the secondary threads. > They must: > > -- Wait at a barrier > -- Call the TV barrier routine, _if_ the global is set saying to do so > -- Wait at another pthread barrier > -- Exit > */ > >void *thread_action (void *arg) >{ > long me = (unsigned long)arg; > > hack_barrier (me, create_barr); /* Wait until _everybody_ is present before proceeding */ > > if (sleep_after_thread_create) > sleep_seconds (2); /* Give Linux systems time to settle down after the thread creation*/ > /* Break too soon after thread is created on certain Linux systems => > the target is destroyed > */ > hack_lock (&printf_lock, me); > printf ("Posix thread %d started up, entering TV barrier routine\n", int(me)); > hack_give_lock_to (&printf_lock, me+1); > > tv_barrier (me); > /* And that's all. */ > hack_lock (&printf_lock, me); > printf ("Posix thread %d done, leaving thread_action\n", int(me)); > hack_give_lock_to (&printf_lock, me+1); > > return ((void *)me); /* Keep "me" alive */ >} /* *thread_action */ > >/**********************************************************************/ > >void make_pthreads (long next_me_index) >{ > int parent_pid = getpid(); > > pthread_t my_ptid = pthread_self(); > pthread_t new_tid; > new_tid = 0; > > if (!quiet) > printf ("Process %d, ptid = %ld in make_pthreads\n", (int)(getpid()), (long)(my_ptid)); > else > printf ("Master thread in make_pthreads\n"); > > for (int i = 0; i < pthread_count; i++) > { > long me_index = next_me_index++; /* "me" starts after the count of clones */ > int whoops = 0; > pthread_attr_t attr; > pthread_attr_init (&attr); > //if (bind_threads) > //whoops = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); > > whoops = pthread_create (&new_tid, &attr, thread_action, (void*)(me_index)); > if (whoops) > { > printf("pthread_create failed; result=%d, errno=%d\n", whoops, errno); > exit(1); > } > thread_ptids[i] = new_tid; > if (!quiet) > printf ("%d: Created %ld, me_index=%ld.\n", (int)(getpid()), (long)new_tid, long(me_index)); > else > printf ("Created me_index=%ld\n", long(me_index)); > } >} /* make_pthreads */ > > >/**********************************************************************/ >/**********************************************************************/ >#endif /* PTHREADS_TOO */ > >/**********************************************************************/ > >/* Some flags which may be missing on some older versions (but we still > want to be able to build the test file there) > */ > >#ifndef CLONE_PARENT >#define CLONE_PARENT 0x00008000 >#endif >#ifndef CLONE_THREAD >#define CLONE_THREAD 0x00010000 >#endif >#ifndef CLONE_DETACHED >#define CLONE_DETACHED 0x00400000 >#endif > >/* Main thread is me=0, other threads are me=1...clone_count */ > >#define OPT_FLAG(_FLG_,_BIT_) \ > else if (!strcmp ("-" #_FLG_, arg)) \ > clone_flags |= CLONE_ ## _BIT_; \ > else if (!strcmp ("-no_" #_FLG_, arg)) \ > clone_flags &= ~(CLONE_ ## _BIT_) > >#define CHECK_FLAG(_BIT_) \ > do { \ > if (clone_flags & CLONE_ ## _BIT_) \ > { \ > if (*flags_str) /* Started already? */ \ > strcat (flags_str, " | "); \ > strcat (flags_str, "CLONE_" #_BIT_); \ > } \ > } while (0) > >/**********************************************************************/ > >main (int argc, char **argv) >{ > setbuf (stdout, 0); > int i; > >/* NB > The CLONE_THREAD flag is only legal with the CLONE_SIGHAND flag. > If CLONE_THREAD is not specified then the clones continue to exist > after the parent exits; otherwise they do not. > If _either_ CLONE_PARENT or CLONE_THREAD is set then the ppid > becomes the original ppid instead of the original pid. > The "getpid()" call seems to return the original pid > whether or not CLONE_THREAD was specified; it never seems > to return the lwpid, as one might have expected. > */ > int clone_flags = CLONE_VM; > > for (i = 1; i < argc; i++) > { > const char *arg = argv[i]; > if (!strcmp (arg, "-clone_count")) > { > arg = argv[++i]; > clone_count = atoi (arg); > } > else if (!strcmp (arg, "-quiet")) > { > quiet = 1; > } > else if (!strcmp (arg, "-thread")) /* Break out "-thread" specially so we can set our flag for it, too */ > { > clone_flags |= CLONE_THREAD; > threadlike_clones = 1; /* Note that using waitpid() won't work and may hang */ > } > else if (!strcmp (arg, "-no_thread")) > { > clone_flags &= ~CLONE_THREAD; > threadlike_clones = 0; /* Note that using waitpid() should work correctly */ > } > OPT_FLAG (detached,DETACHED); > OPT_FLAG (files,FILES); > OPT_FLAG (fs,FS); > OPT_FLAG (parent,PARENT); > OPT_FLAG (ptrace,PTRACE); > OPT_FLAG (sighand,SIGHAND); > OPT_FLAG (vfork,VFORK); > OPT_FLAG (vm,VM); >#if defined(CLONE_PID) > OPT_FLAG (pid,PID); >#endif >#if defined(PTHREADS_TOO) > else if (!strcmp (arg, "-pt_count")) > { > arg = argv[++i]; > pthread_count = atoi(arg); > } > else if (!strcmp (arg, "-more_clones")) > { > more_clones = 1; > } >#endif /* PTHREADS_TOO */ > else if (!strcmp (arg, "-signal")) > { > /* This isn't really useful. To really simulate > a fork() we need to set the stack arg to 0, which > requires also calling sys_clone instead of clone. > */ > arg = argv[++i]; > clone_flags |= atoi(arg); > } > else if (!strcmp (arg, "-no_signal")) > { > clone_flags &= ~CSIGNAL; > } > else if (!strcmp (arg, "-lock")) > { > use_locking = 1; > } > else if (!strcmp (arg, "-no_lock")) > { > use_locking = 0; > } > else if (!strcmp (arg, "-clones_exit")) > { > clones_exit = 1; > } > else > { > printf ("Argument %s not understood.\n", arg); > exit(1); > } > } /* for */ > > /* The master waits at the barriers, too, so count=secondary_count+1 */ > int expected_clones = clone_count+1; > if (more_clones) > expected_clones += extra_clone_count; > > int expected_threads = expected_clones+pthread_count; > > create_barr = new hack_barr_t (0, expected_threads); > clone_exit_barr = new hack_barr_t (0, expected_clones); > > char flags_str[1024]; > flags_str[0] = 0; > CHECK_FLAG (DETACHED); > CHECK_FLAG (FILES); > CHECK_FLAG (FS); > CHECK_FLAG (PARENT); > CHECK_FLAG (PTRACE); > CHECK_FLAG (SIGHAND); > CHECK_FLAG (THREAD); > CHECK_FLAG (VFORK); > CHECK_FLAG (VM); >#if defined(CLONE_PID) > CHECK_FLAG (PID); >#endif > if (!quiet) > printf ("Master threads_and_clones process %d, with parent %d\n", > int(getpid()), int(getppid())); > printf ("Flags to be passed to clone: '%s'\n", flags_str); > > for (i = 0; i < clone_count; i++) > { > make_clone (clone_flags); > } /* for */ > >#if defined(PTHREADS_TOO) > make_pthreads (expected_clones); >#endif /* PTHREADS_TOO */ > > > > printf ("Master thread returned from creation barrier\n"); > > hack_lock (&printf_lock, expected_threads); > printf ("All clones got past their greetings and the master got the lock back\n"); > > > > /* Check that clones are gone, too */ > breakpointable (3); /* STOP: */ > ok_for_clones_to_exit = 1; /* Let them go into their exit routines */ > exit(0); >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 289411
: 194741 |
203581
|
203591
|
203601
|
203611
|
203621