X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;f=testsuite.c;h=76a3d09b3058eaaa648115c0ad9bba61e11ae31d;hb=80f57936cda3f7d4511b1926b424b769017aa35d;hp=bcf81d1e913c57129eb34f969162263928ee5106;hpb=09b9a96accc9255c859100e5009b0d6de274e14e;p=debugger.git diff --git a/testsuite.c b/testsuite.c index bcf81d1..76a3d09 100644 --- a/testsuite.c +++ b/testsuite.c @@ -20,28 +20,13 @@ #include "debugger.c" -#define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig)) +#define TIMEOUT_SECS 4 +#undef LOOPS_MIN +#define LOOPS_MIN 1000 -static volatile int spawned_threads_count; /* Set for the specific spawner. */ +#define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig)) -static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect) -{ - struct attach_state_struct *attach_state; - - STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED)); - attach_state = attach (pid); - if (redelivered_expect != attach_state_redelivered_get (attach_state)) - { - fprintf (stderr, "Expecting redelivery of %d but found %d\n", - redelivered_expect, attach_state_redelivered_get (attach_state)); - abort (); - } - assert (spawned_threads_count == attach_state_threads_count_get (attach_state)); - /* FIXME: Why also STATE_STOPPED? */ - STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED)); - return attach_state; -} static void detach_checked (struct attach_state_struct *attach_state) { @@ -61,6 +46,46 @@ static void detach_checked (struct attach_state_struct *attach_state) } } +static volatile int spawned_threads_count; /* Set for the specific spawner. */ + +static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect) +{ + struct attach_state_struct *attach_state; + time_t timeout = time (NULL) + TIMEOUT_SECS; + unsigned loops = 0; + + STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED)); + do + { + attach_state = attach (pid); + if (redelivered_expect != attach_state_redelivered_get (attach_state)) + { + fprintf (stderr, "Expecting redelivery of %d but found %d\n", + redelivered_expect, + attach_state_redelivered_get (attach_state)); + abort (); + } + /* During the inferior's initialization we may catch less threads. */ + assert (attach_state_threads_count_get (attach_state) + <= spawned_threads_count); + if (attach_state_threads_count_get (attach_state) + == spawned_threads_count + /* Inferior may got stopped before it could initialize. */ + || attach_state_stopped_get (attach_state) == 1) + { + /* FIXME: Why also STATE_STOPPED? */ + STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED)); + return attach_state; + } + /* WARNING: Currently we never use REDELIVERED_EXPECT but we would have to + probably reset it back to 0 otherwise. */ + assert (redelivered_expect == 0); + detach_checked (attach_state); + } + while (loops++ < LOOPS_MIN || time (NULL) < timeout); + abort (); +} + struct registry { struct registry *next; @@ -138,7 +163,7 @@ static void registry_handler (int signo) raise (signo); } -static void child_pause (void) +static __attribute__((__noreturn__)) void child_pause (void) { for (;;) pause (); @@ -152,16 +177,14 @@ static void child_alrm_handler (int signo) raise (SIGALRM); } -static void child_alrm (void) +static __attribute__((__noreturn__)) void child_alrm (void) { - void (*handler_orig) (int signo); #if 0 int i; sigset_t oldset; #endif - handler_orig = signal (SIGALRM, child_alrm_handler); - assert (handler_orig == SIG_DFL); + /* Assumed already setup SIGALRM for CHILD_ALRM_HANDLER. */ #if 0 i = sigprocmask (SIG_BLOCK, NULL, &oldset); @@ -243,7 +266,7 @@ struct child_spawner int fd; }; -static void *child_spawner (void *param_voidpointer, void *input) +static __attribute__((__noreturn__)) void *child_spawner (void *param_voidpointer, void *input) { struct child_spawner *param = param_voidpointer; pid_t inferior; @@ -318,6 +341,7 @@ static void body_spawner (void *(*child) (void *data, void *input), void *data, pid_t inferior; struct attach_state_struct *attach_state; int i; + void (*handler_orig) (int signo); assert (input == NULL); @@ -351,7 +375,12 @@ static void body_spawner (void *(*child) (void *data, void *input), void *data, murder (inferior); /* Attach to a stopped process with already pending SIGALRM. */ + /* Setup the handler already in the parent to avoid the child race. */ + handler_orig = signal (SIGALRM, child_alrm_handler); + assert (handler_orig == SIG_DFL); inferior = (unsigned long) (*child) (data, child_alrm); + handler_orig = signal (SIGALRM, handler_orig); + assert (handler_orig == child_alrm_handler); STATE (inferior, 1 << STATE_SLEEPING); delay (); i = tkill (inferior, SIGSTOP); @@ -413,7 +442,7 @@ static void *spawn_singlethreaded (void *data, void *input) return pass (data, input); } -static void *spawn_threaded_parent_start (void *arg) +static __attribute__((__noreturn__)) void *spawn_threaded_parent_start (void *arg) { for (;;) pause (); @@ -421,81 +450,82 @@ static void *spawn_threaded_parent_start (void *arg) abort (); } +static void *libpthread_handle; +static int (*libpthread_create_pointer) (pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), + void *arg); +static int (*libpthread_join_pointer) (pthread_t thread, void **value_ptr); + +static void libpthread_open (void) +{ + assert (libpthread_handle == NULL); + + libpthread_handle = dlopen ("libpthread.so.0", RTLD_LAZY); + assert (libpthread_handle != NULL); + + libpthread_create_pointer = dlsym (libpthread_handle, "pthread_create"); + assert (libpthread_create_pointer != NULL); + libpthread_join_pointer = dlsym (libpthread_handle, "pthread_join"); + assert (libpthread_join_pointer != NULL); + +} + +static void libpthread_close (void) +{ + int i; + + assert (libpthread_handle != NULL); + + i = dlclose (libpthread_handle); + assert (i == 0); + libpthread_handle = NULL; +} + static void *spawn_threaded_parent (void *data, void *input) { pthread_t thread; int i; - void *handle; - void *retval; - int (*pthread_create_pointer) (pthread_t *thread, - const pthread_attr_t *attr, - void *(*start_routine) (void *), - void *arg); - - handle = dlopen ("libpthread.so.0", RTLD_LAZY); - assert (handle != NULL); - pthread_create_pointer = dlsym (handle, "pthread_create"); - assert (pthread_create_pointer != NULL); - - i = (*pthread_create_pointer) (&thread, NULL, spawn_threaded_parent_start, - NULL); - assert (i == 0); - retval = pass (data, input); - i = dlclose (handle); + assert (libpthread_create_pointer != NULL); + i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_parent_start, + NULL); assert (i == 0); - - return retval; + return pass (data, input); } struct spawn_threaded_child_start { void *data; void *input; - void *lib_handle; }; static void *spawn_threaded_child_start (void *arg_voidpointer) { struct spawn_threaded_child_start *arg = arg_voidpointer; - void *retval; - int i; - - retval = pass (arg->data, arg->input); - i = dlclose (arg->lib_handle); - assert (i == 0); - - return retval; + return pass (arg->data, arg->input); } -static void *spawn_threaded_child (void *data, void *input) +static __attribute__((__noreturn__)) void *spawn_threaded_child (void *data, void *input) { pthread_t thread; int i; struct spawn_threaded_child_start arg_local; - int (*pthread_create_pointer) (pthread_t *thread, - const pthread_attr_t *attr, - void *(*start_routine) (void *), - void *arg); - int (*pthread_join_pointer) (pthread_t thread, void **value_ptr); - - arg_local.lib_handle = dlopen ("libpthread.so.0", RTLD_LAZY); - assert (arg_local.lib_handle != NULL); - pthread_create_pointer = dlsym (arg_local.lib_handle, "pthread_create"); - assert (pthread_create_pointer != NULL); - pthread_join_pointer = dlsym (arg_local.lib_handle, "pthread_join"); - assert (pthread_join_pointer != NULL); arg_local.data = data; arg_local.input = input; - i = (*pthread_create_pointer) (&thread, NULL, spawn_threaded_child_start, - &arg_local); + assert (libpthread_create_pointer != NULL); + i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_child_start, + &arg_local); assert (i == 0); - i = (*pthread_join_pointer) (thread, NULL); + assert (libpthread_join_pointer != NULL); + i = (*libpthread_join_pointer) (thread, NULL); assert (i == 0); _exit (EXIT_SUCCESS); + /* NOTREACHED */ + abort (); } static void body_maywaiter (void *(*child) (void *data, void *input), @@ -519,6 +549,24 @@ static void handler_sigusr1 (int signo) loops_print++; } +static __attribute__((__noreturn__)) void *tests_threaded (void *data, void *input) +{ + libpthread_open (); + + spawned_threads_count = 2; + body_maywaiter (spawn_threaded_parent, NULL, NULL); + + spawned_threads_count = 2; + body_maywaiter (spawn_threaded_child, NULL, NULL); + + libpthread_close (); + + registry_cleanup (); + _exit (EXIT_SUCCESS); + /* NOTREACHED */ + abort (); +} + int main (int argc, char **argv) { int loop = 0; @@ -547,6 +595,9 @@ int main (int argc, char **argv) do { + pid_t pid_threaded, pid_threaded_got; + int status; + while (loops_print > 0) { printf ("%lu\n", loops); @@ -556,16 +607,24 @@ int main (int argc, char **argv) spawned_threads_count = 0; body_maywaiter (spawn_singlethreaded, NULL, NULL); - spawned_threads_count = 2; - body_maywaiter (spawn_threaded_parent, NULL, NULL); - - spawned_threads_count = 2; - body_maywaiter (spawn_threaded_child, NULL, NULL); + /* We cannot rely on LIBPTHREAD_CLOSE as libpthread would be still loaded + with ATTACH_STATE_REDELIVERED_GET () reporting 1 for + SPAWN_SINGLETHREADED. */ + pid_threaded = spawn (tests_threaded, NULL, NULL, -1); + pid_threaded_got = waitpid (pid_threaded, &status, 0); + assert (pid_threaded_got == pid_threaded); + assert (!WIFSIGNALED (status)); /* Improve readability in the failed case. */ + assert (!WIFSTOPPED (status)); /* Improve readability in the failed case. */ + assert (WIFEXITED (status)); + assert (WEXITSTATUS (status) == 0); + STATE (pid_threaded, 1 << STATE_ENOENT); + registry_remove (pid_threaded); registry_cleanup (); loops++; } - while (loop != 0); + /* Run at least twice to test libpthread_close (). */ + while (loop != 0 || loops == 1); return EXIT_SUCCESS; }