You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.2 KiB
151 lines
3.2 KiB
#ifndef _DEFAULT_SOURCE
|
|
#define _DEFAULT_SOURCE
|
|
#endif
|
|
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/psx_syscall.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
typedef union tp {
|
|
long long unsigned raw;
|
|
pthread_t pt;
|
|
} thread_ptr;
|
|
|
|
static void say_hello_expecting(const char *title, int n, int kept) {
|
|
int keeper = prctl(PR_GET_KEEPCAPS);
|
|
thread_ptr tp;
|
|
tp.pt = pthread_self();
|
|
|
|
printf("hello [%d], %s<%d> %llx (keepcaps=%d vs. want=%d)\n",
|
|
getpid(), title, n, tp.raw, keeper, kept);
|
|
if (keeper != kept) {
|
|
printf("--> FAILURE %s thread=%llx has wrong keepcaps: got=%d want=%d\n",
|
|
title, tp.raw, keeper, kept);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
pthread_mutex_t mu;
|
|
pthread_cond_t cond;
|
|
|
|
int global_kept = 0;
|
|
int step = 0;
|
|
int replies = 0;
|
|
int launched = 0;
|
|
int started = 0;
|
|
|
|
static void *say_hello(void *args) {
|
|
int count = 0;
|
|
|
|
pthread_mutex_lock(&mu);
|
|
started++;
|
|
int this_step = step+1;
|
|
pthread_cond_broadcast(&cond);
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
pthread_mutex_lock(&mu);
|
|
do {
|
|
while (this_step > step) {
|
|
pthread_cond_wait(&cond, &mu);
|
|
}
|
|
say_hello_expecting("thread", count, global_kept);
|
|
|
|
replies++;
|
|
pthread_cond_broadcast(&cond);
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
this_step++;
|
|
pthread_mutex_lock(&mu);
|
|
} while (++count != 3);
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
pthread_t tid[3];
|
|
int i;
|
|
pid_t child = 0;
|
|
char * const stop_argv[3] = { argv[0], strdup("stop"), NULL };
|
|
|
|
if (argc != 1) {
|
|
printf("child %d starting\n", getpid());
|
|
usleep(2000);
|
|
printf("child %d exiting\n", getpid());
|
|
exit(0);
|
|
}
|
|
|
|
for (i = 0; i<10; i++) {
|
|
printf("iteration [%d]: %d\n", getpid(), i);
|
|
|
|
pthread_mutex_lock(&mu);
|
|
global_kept = !global_kept;
|
|
replies = 0;
|
|
step = i;
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
psx_syscall(SYS_prctl, PR_SET_KEEPCAPS, global_kept);
|
|
|
|
pthread_mutex_lock(&mu);
|
|
step++;
|
|
pthread_cond_broadcast(&cond);
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
say_hello_expecting("main", i, global_kept);
|
|
|
|
pthread_mutex_lock(&mu);
|
|
while (replies < launched) {
|
|
pthread_cond_wait(&cond, &mu);
|
|
}
|
|
pthread_mutex_unlock(&mu);
|
|
|
|
if (i < 3) {
|
|
if (!child) {
|
|
child = fork();
|
|
if (!child) {
|
|
usleep(2000);
|
|
execve(argv[0], stop_argv, NULL);
|
|
perror("failed to exec");
|
|
exit(1);
|
|
} else {
|
|
printf("pid=%d forked -> %d\n", getpid(), child);
|
|
}
|
|
}
|
|
launched++;
|
|
pthread_create(&tid[i], NULL, say_hello, NULL);
|
|
/* Confirm that the thread is started. */
|
|
pthread_mutex_lock(&mu);
|
|
while (started < launched) {
|
|
printf("[%d] started=%d vs %d\n", getpid(), started, launched);
|
|
pthread_cond_wait(&cond, &mu);
|
|
}
|
|
printf("[%d] started=%d vs %d\n", getpid(), started, launched);
|
|
pthread_cond_broadcast(&cond);
|
|
pthread_mutex_unlock(&mu);
|
|
} else if (i < 6) {
|
|
/* Confirm one thread has finished. */
|
|
pthread_join(tid[i-3], NULL);
|
|
launched--;
|
|
}
|
|
}
|
|
|
|
if (child) {
|
|
int status;
|
|
waitpid(child, &status, 0);
|
|
if (status) {
|
|
printf("child %d FAILED: %d\n", child, status);
|
|
exit(1);
|
|
}
|
|
}
|
|
printf("%s PASSED\n", argv[0]);
|
|
exit(0);
|
|
}
|