• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _DEFAULT_SOURCE
2 #define _DEFAULT_SOURCE
3 #endif
4 
5 #include <pthread.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/prctl.h>
10 #include <sys/psx_syscall.h>
11 #include <sys/syscall.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <time.h>
15 #include <unistd.h>
16 
17 typedef union tp {
18     long long unsigned raw;
19     pthread_t pt;
20 } thread_ptr;
21 
say_hello_expecting(const char * title,int n,int kept)22 static void say_hello_expecting(const char *title, int n, int kept) {
23     int keeper = prctl(PR_GET_KEEPCAPS);
24     thread_ptr tp;
25     tp.pt = pthread_self();
26 
27     printf("hello [%d], %s<%d> %llx (keepcaps=%d vs. want=%d)\n",
28 	   getpid(), title, n, tp.raw, keeper, kept);
29     if (keeper != kept) {
30 	printf("--> FAILURE %s thread=%llx has wrong keepcaps: got=%d want=%d\n",
31 	       title, tp.raw, keeper, kept);
32 	exit(1);
33     }
34 }
35 
36 pthread_mutex_t mu;
37 pthread_cond_t cond;
38 
39 int global_kept = 0;
40 int step = 0;
41 int replies = 0;
42 int launched = 0;
43 int started = 0;
44 
say_hello(void * args)45 static void *say_hello(void *args) {
46     int count = 0;
47 
48     pthread_mutex_lock(&mu);
49     started++;
50     int this_step = step+1;
51     pthread_cond_broadcast(&cond);
52     pthread_mutex_unlock(&mu);
53 
54     pthread_mutex_lock(&mu);
55     do {
56 	while (this_step > step) {
57 	    pthread_cond_wait(&cond, &mu);
58 	}
59 	say_hello_expecting("thread", count, global_kept);
60 
61 	replies++;
62 	pthread_cond_broadcast(&cond);
63 	pthread_mutex_unlock(&mu);
64 
65 	this_step++;
66 	pthread_mutex_lock(&mu);
67     } while (++count != 3);
68     pthread_mutex_unlock(&mu);
69 
70     return NULL;
71 }
72 
main(int argc,char ** argv)73 int main(int argc, char **argv) {
74     pthread_t tid[3];
75     int i;
76     pid_t child = 0;
77     char * const stop_argv[3] = { argv[0], strdup("stop"), NULL };
78 
79     if (argc != 1) {
80 	printf("child %d starting\n", getpid());
81 	usleep(2000);
82 	printf("child %d exiting\n", getpid());
83 	exit(0);
84     }
85 
86     for (i = 0; i<10; i++) {
87 	printf("iteration [%d]: %d\n", getpid(), i);
88 
89 	pthread_mutex_lock(&mu);
90 	global_kept = !global_kept;
91 	replies = 0;
92 	step = i;
93 	pthread_mutex_unlock(&mu);
94 
95 	psx_syscall(SYS_prctl, PR_SET_KEEPCAPS, global_kept);
96 
97 	pthread_mutex_lock(&mu);
98 	step++;
99 	pthread_cond_broadcast(&cond);
100 	pthread_mutex_unlock(&mu);
101 
102 	say_hello_expecting("main", i, global_kept);
103 
104 	pthread_mutex_lock(&mu);
105 	while (replies < launched) {
106 	    pthread_cond_wait(&cond, &mu);
107 	}
108 	pthread_mutex_unlock(&mu);
109 
110 	if (i < 3) {
111 	    if (!child) {
112 		child = fork();
113 		if (!child) {
114 		    usleep(2000);
115 		    execve(argv[0], stop_argv, NULL);
116 		    perror("failed to exec");
117 		    exit(1);
118 		} else {
119 		    printf("pid=%d forked -> %d\n", getpid(), child);
120 		}
121 	    }
122 	    launched++;
123 	    pthread_create(&tid[i], NULL, say_hello, NULL);
124 	    /* Confirm that the thread is started. */
125 	    pthread_mutex_lock(&mu);
126 	    while (started < launched) {
127 		printf("[%d] started=%d vs %d\n", getpid(), started, launched);
128 		pthread_cond_wait(&cond, &mu);
129 	    }
130 	    printf("[%d] started=%d vs %d\n", getpid(), started, launched);
131 	    pthread_cond_broadcast(&cond);
132 	    pthread_mutex_unlock(&mu);
133 	} else if (i < 6) {
134 	    /* Confirm one thread has finished. */
135 	    pthread_join(tid[i-3], NULL);
136 	    launched--;
137 	}
138     }
139 
140     if (child) {
141 	int status;
142 	waitpid(child, &status, 0);
143 	if (status) {
144 	    printf("child %d FAILED: %d\n", child, status);
145 	    exit(1);
146 	}
147     }
148     printf("%s PASSED\n", argv[0]);
149     exit(0);
150 }
151