10 #include <sys/syscall.h>
13 static int loops
= 15; // each thread+main will do this amount of loop
14 static int sleepms
= 1000; // in each loop, will sleep "sleepms" milliseconds
15 static int burn
= 0; // after each sleep, will burn cpu in a tight 'burn' loop
16 static void setup_sigusr_handler(void); // sigusr1 and 2 sigaction setup.
18 static pid_t
gettid_sys()
21 return syscall(__NR_gettid
);
26 // will be invoked from gdb.
27 static void whoami(char *msg
) __attribute__((unused
));
28 static void whoami(char *msg
)
30 fprintf(stderr
, "pid %ld Thread %ld %s\n", (long) getpid(), (long) gettid_sys(),
36 static void do_burn ()
40 // one single line for the below, to ensure interrupt on this line.
41 for (i
= 0; i
< burn
; i
++) loopnr
++;
44 static int thread_ready
= 0;
45 static pthread_cond_t ready
= PTHREAD_COND_INITIALIZER
;
46 static pthread_mutex_t ready_mutex
= PTHREAD_MUTEX_INITIALIZER
;
47 static void signal_ready (void)
50 rc
= pthread_mutex_lock(&ready_mutex
);
52 fprintf(stderr
, "signal_ready lock error %d_n", rc
);
54 rc
= pthread_cond_signal(&ready
);
56 fprintf(stderr
, "signal_ready signal error %d_n", rc
);
57 rc
= pthread_mutex_unlock(&ready_mutex
);
59 fprintf(stderr
, "signal_ready unlock error %d_n", rc
);
68 static struct timeval t
[4];
69 static int nr_sleeper_or_burner
= 0;
70 static volatile int report_finished
= 1;
71 // set to 0 to have no finish msg (as order is non-deterministic)
72 static void *sleeper_or_burner(void *v
)
75 struct spec
* s
= (struct spec
*)v
;
77 fprintf(stderr
, "%s ready to sleep and/or burn\n", s
->name
);
80 nr_sleeper_or_burner
++;
82 for (i
= 0; i
< loops
; i
++) {
83 if (sleepms
> 0 && s
->sleep
) {
84 t
[s
->t
].tv_sec
= sleepms
/ 1000;
85 t
[s
->t
].tv_usec
= (sleepms
% 1000) * 1000;
86 ret
= select (0, NULL
, NULL
, NULL
, &t
[s
->t
]);
87 /* We only expect a timeout result or EINTR from the above. */
88 if (ret
!= 0 && errno
!= EINTR
)
89 perror("unexpected result from select");
91 if (burn
> 0 && s
->burn
)
94 if (report_finished
) {
95 fprintf(stderr
, "%s finished to sleep and/or burn\n", s
->name
);
101 // wait till a thread signals it is ready
102 static void wait_ready(void)
105 rc
= pthread_mutex_lock(&ready_mutex
);
107 fprintf(stderr
, "wait_ready lock error %d_n", rc
);
108 while (! thread_ready
&& rc
== 0) {
109 rc
= pthread_cond_wait(&ready
, &ready_mutex
);
111 fprintf(stderr
, "wait_ready wait error %d_n", rc
);
114 rc
= pthread_mutex_unlock(&ready_mutex
);
116 fprintf(stderr
, "wait_ready unlock error %d_n", rc
);
119 // We will lock ourselves on one single cpu.
120 // This bypasses the unfairness of the Valgrind scheduler
121 // when a multi-cpu machine has enough cpu to run all the
122 // threads wanting to burn cpu.
123 static void setaffinity(void)
126 cpu_set_t single_cpu
;
127 CPU_ZERO(&single_cpu
);
128 CPU_SET(1, &single_cpu
);
129 (void) sched_setaffinity(0, sizeof(single_cpu
), &single_cpu
);
131 // GDBTD: equivalent for Darwin ?
134 int main (int argc
, char *argv
[])
137 pthread_t ebbr
, egll
, zzzz
;
138 struct spec b
, l
, p
, m
;
139 char *some_mem
__attribute__((unused
)) = malloc(100);
140 if (argc
> 5 && atoi(argv
[5])) setaffinity();
141 setup_sigusr_handler();
143 loops
= atoi(argv
[1]);
146 sleepms
= atoi(argv
[2]);
149 burn
= atoll(argv
[3]);
152 threads_spec
= argv
[4];
154 threads_spec
= "BSBSBSBS";
156 fprintf(stderr
, "loops/sleep_ms/burn/threads_spec/affinity: %d %d %d %s %d\n",
157 loops
, sleepms
, burn
, threads_spec
, argc
> 5 && atoi(argv
[5]));
161 b
.burn
= *threads_spec
++ == 'B';
162 b
.sleep
= *threads_spec
++ == 'S';
164 if (b
.burn
|| b
.sleep
) {
166 pthread_create(&ebbr
, NULL
, sleeper_or_burner
, &b
);
171 l
.burn
= *threads_spec
++ == 'B';
172 l
.sleep
= *threads_spec
++ == 'S';
174 if (l
.burn
|| l
.sleep
) {
176 pthread_create(&egll
, NULL
, sleeper_or_burner
, &l
);
180 p
.name
= "Petaouchnok";
181 p
.burn
= *threads_spec
++ == 'B';
182 p
.sleep
= *threads_spec
++ == 'S';
184 if (p
.burn
|| p
.sleep
) {
186 pthread_create(&zzzz
, NULL
, sleeper_or_burner
, &p
);
191 m
.burn
= *threads_spec
++ == 'B';
192 m
.sleep
= *threads_spec
++ == 'S';
194 sleeper_or_burner(&m
);
196 if (b
.t
!= -1) pthread_join(ebbr
, NULL
);
197 if (l
.t
!= -1) pthread_join(egll
, NULL
);
198 if (p
.t
!= -1) pthread_join(zzzz
, NULL
);
203 static int sigusr1_received
= 0;
204 static void sigusr1_handler(int signr
)
208 static void setup_sigusr_handler(void)
211 sa
.sa_handler
= sigusr1_handler
;
212 sigemptyset(&sa
.sa_mask
);
215 if (sigaction (SIGUSR1
, &sa
, NULL
) != 0)
216 perror("sigaction SIGUSR1");
218 sa
.sa_handler
= SIG_IGN
;
219 if (sigaction (SIGUSR2
, &sa
, NULL
) != 0)
220 perror("sigaction SIGUSR2");