/* Copyright 2007, Red Hat Inc. */
+#define _GNU_SOURCE 1
+
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
#include <sys/syscall.h>
+#include <dlfcn.h>
#include "debugger.h"
#define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
-static int attach_checked (pid_t pid, int redelivered_expect)
+static volatile int spawned_threads_count; /* Set for the specific spawner. */
+
+static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect)
{
- int stopped;
+ struct attach_state_struct *attach_state;
STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
- stopped = attach (pid);
- if (attach_redelivered != redelivered_expect)
+ 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_redelivered);
+ 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 stopped;
+ return attach_state;
}
-static void detach_checked (pid_t pid, int stopped)
+static void detach_checked (struct attach_state_struct *attach_state)
{
+ pid_t pid = attach_state_pid_get (attach_state);
+ int stopped = attach_state_stopped_get (attach_state);
+
/* FIXME: Why STATE_STOPPED? */
STATE (pid, (stopped ? 1 << STATE_STOPPED : 1 << STATE_PTRACED));
- detach (pid, stopped);
+ detach (attach_state);
STATE (pid, (stopped ? 1 << STATE_STOPPED : (1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
}
if (!(pid_got == -1 && errno == ECHILD))
{
assert (pid_got == pid);
- assert ((WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)
+ assert ((WIFSIGNALED (status) && (WTERMSIG (status) == SIGKILL
+ || WTERMSIG (status) == SIGUSR2))
|| (WIFEXITED (status) && WEXITSTATUS (status) == 0));
STATE (pid, 1 << STATE_ENOENT);
}
void *input)
{
pid_t inferior;
- int stopped;
+ struct attach_state_struct *attach_state;
int i;
assert (input == NULL);
/* Plain attach/detach. */
inferior = (unsigned long) (*child) (data, child_pause);
- stopped = attach_checked (inferior, 0);
- assert (stopped == 0);
- detach_checked (inferior, stopped);
+ attach_state = attach_checked (inferior, 0);
+ assert (attach_state_stopped_get (attach_state) == 0);
+ detach_checked (attach_state);
murder (inferior);
/* Attach to a process stopped by standard kill(2). */
i = kill (inferior, SIGSTOP);
assert (i == 0);
STATE (inferior, 1 << STATE_STOPPED);
- stopped = attach_checked (inferior, 0);
- assert (stopped == 1);
- detach_checked (inferior, stopped);
+ attach_state = attach_checked (inferior, 0);
+ assert (attach_state_stopped_get (attach_state) == 1);
+ detach_checked (attach_state);
murder (inferior);
/* Attach to a process stopped by Linux specific tkill(2). */
i = tkill (inferior, SIGSTOP);
assert (i == 0);
STATE (inferior, 1 << STATE_STOPPED);
- stopped = attach_checked (inferior, 0);
- assert (stopped == 1);
- detach_checked (inferior, stopped);
+ attach_state = attach_checked (inferior, 0);
+ assert (attach_state_stopped_get (attach_state) == 1);
+ detach_checked (attach_state);
murder (inferior);
/* Attach to a stopped process with already pending SIGALRM. */
STATE (inferior, 1 << STATE_STOPPED);
/* FIXME: SIGALRM did not get redelivered? */
#if 0
- stopped = attach_checked (inferior, SIGALRM);
+ attach_state = attach_checked (inferior, SIGALRM);
#else
- stopped = attach_checked (inferior, 0);
+ attach_state = attach_checked (inferior, 0);
#endif
- assert (stopped == 1);
- detach_checked (inferior, stopped);
+ assert (attach_state_stopped_get (attach_state) == 1);
+ detach_checked (attach_state);
STATE (inferior, 1 << STATE_STOPPED);
delay ();
i = tkill (inferior, SIGCONT);
assert (i == 0);
- /* This is a race, we may not prove the successful SIGALRM delivery by it. */
+ /* This is a race, we may not prove the successful SIGALRM delivery by it.
+ Rather recheck it below. */
STATE (inferior, 1 << STATE_RUNNING);
- murder (inferior);
+ delay ();
+ i = tkill (inferior, SIGSTOP);
+ assert (i == 0);
+ /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
+ STATE (inferior, 1 << STATE_STOPPED);
+ delay ();
+ i = tkill (inferior, SIGUSR2);
+ assert (i == 0);
+ STATE (inferior, 1 << STATE_STOPPED);
+ delay ();
+ i = tkill (inferior, SIGCONT);
+ assert (i == 0);
+ /* Not just STATE_ZOMBIE as we can get spawn with waiter. FIXME. */
+ STATE (inferior, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE) | (1 << STATE_DEAD));
+ /* We would fail on: murder (inferior); */
}
static void *pass (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 = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
+ i = dlclose (handle);
assert (i == 0);
- return pass (data, input);
+
+ return retval;
}
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;
- return pass (arg->data, arg->input);
- /* NOTREACHED */
+ retval = pass (arg->data, arg->input);
+
+ i = dlclose (arg->lib_handle);
+ assert (i == 0);
+
+ return retval;
}
static 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 (&thread, NULL, spawn_threaded_child_start, &arg_local);
+ i = (*pthread_create_pointer) (&thread, NULL, spawn_threaded_child_start,
+ &arg_local);
assert (i == 0);
- i = pthread_join (thread, NULL);
+ i = (*pthread_join_pointer) (thread, NULL);
assert (i == 0);
_exit (EXIT_SUCCESS);
int loop = 0;
int i;
+#ifdef MEASURE_STATE_PERFORMANCE
+ STATE (1, 1 << STATE_ZOMBIE);
+ return 0;
+#endif /* MEASURE_STATE_PERFORMANCE */
+
if (argc == 1)
;
else if (argc == 2 && strcmp (argv[1], "-l") == 0)
printf ("%lu\n", loops);
loops_print--;
}
+
+ 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);
registry_cleanup ();