9 #include <sys/syscall.h>
12 static int loops
= 15; // each thread+main will do this amount of loop
13 static int sleepms
= 1000; // in each loop, will sleep "sleepms" milliseconds
14 static int burn
= 0; // after each sleep, will burn cpu in a tight 'burn' loop
20 return syscall(__NR_gettid
);
25 // will be invoked from gdb.
26 static void whoami(char *msg
) __attribute__((unused
));
27 static void whoami(char *msg
)
29 fprintf(stderr
, "pid %d Thread %d %s\n", getpid(), gettid(), msg
);
34 static void do_burn ()
38 // one single line for the below, to ensure interrupt on this line.
39 for (i
= 0; i
< burn
; i
++) loopnr
++;
42 static int thread_ready
= 0;
43 static pthread_cond_t ready
= PTHREAD_COND_INITIALIZER
;
44 static pthread_mutex_t ready_mutex
= PTHREAD_MUTEX_INITIALIZER
;
45 static void signal_ready (void)
48 rc
= pthread_mutex_lock(&ready_mutex
);
50 fprintf(stderr
, "signal_ready lock error %d_n", rc
);
52 rc
= pthread_cond_signal(&ready
);
54 fprintf(stderr
, "signal_ready signal error %d_n", rc
);
55 rc
= pthread_mutex_unlock(&ready_mutex
);
57 fprintf(stderr
, "signal_ready unlock error %d_n", rc
);
66 static struct timeval t
[4];
67 static int nr_sleeper_or_burner
= 0;
68 static volatile int report_finished
= 1;
69 // set to 0 to have no finish msg (as order is non-deterministic)
70 static void *sleeper_or_burner(void *v
)
73 struct spec
* s
= (struct spec
*)v
;
75 fprintf(stderr
, "%s ready to sleep and/or burn\n", s
->name
);
78 nr_sleeper_or_burner
++;
80 for (i
= 0; i
< loops
; i
++) {
81 if (sleepms
> 0 && s
->sleep
) {
82 t
[s
->t
].tv_sec
= sleepms
/ 1000;
83 t
[s
->t
].tv_usec
= (sleepms
% 1000) * 1000;
84 select (0, NULL
, NULL
, NULL
, &t
[s
->t
]);
86 if (burn
> 0 && s
->burn
)
89 if (report_finished
) {
90 fprintf(stderr
, "%s finished to sleep and/or burn\n", s
->name
);
96 // wait till a thread signals it is ready
97 static void wait_ready(void)
100 rc
= pthread_mutex_lock(&ready_mutex
);
102 fprintf(stderr
, "wait_ready lock error %d_n", rc
);
103 while (! thread_ready
&& rc
== 0) {
104 rc
= pthread_cond_wait(&ready
, &ready_mutex
);
106 fprintf(stderr
, "wait_ready wait error %d_n", rc
);
109 rc
= pthread_mutex_unlock(&ready_mutex
);
111 fprintf(stderr
, "wait_ready unlock error %d_n", rc
);
114 // We will lock ourselves on one single cpu.
115 // This bypasses the unfairness of the Valgrind scheduler
116 // when a multi-cpu machine has enough cpu to run all the
117 // threads wanting to burn cpu.
118 static void setaffinity(void)
121 cpu_set_t single_cpu
;
122 CPU_ZERO(&single_cpu
);
123 CPU_SET(1, &single_cpu
);
124 (void) sched_setaffinity(0, sizeof(single_cpu
), &single_cpu
);
126 // GDBTD: equivalent for Darwin ?
129 int main (int argc
, char *argv
[])
132 pthread_t ebbr
, egll
, zzzz
;
133 struct spec b
, l
, p
, m
;
134 char *some_mem
__attribute__((unused
)) = malloc(100);
138 loops
= atoi(argv
[1]);
141 sleepms
= atoi(argv
[2]);
144 burn
= atoll(argv
[3]);
147 threads_spec
= argv
[4];
149 threads_spec
= "BSBSBSBS";
151 fprintf(stderr
, "loops/sleep_ms/burn/threads_spec: %d %d %d %s\n",
152 loops
, sleepms
, burn
, threads_spec
);
156 b
.burn
= *threads_spec
++ == 'B';
157 b
.sleep
= *threads_spec
++ == 'S';
159 if (b
.burn
|| b
.sleep
) {
161 pthread_create(&ebbr
, NULL
, sleeper_or_burner
, &b
);
166 l
.burn
= *threads_spec
++ == 'B';
167 l
.sleep
= *threads_spec
++ == 'S';
169 if (l
.burn
|| l
.sleep
) {
171 pthread_create(&egll
, NULL
, sleeper_or_burner
, &l
);
175 p
.name
= "Petaouchnok";
176 p
.burn
= *threads_spec
++ == 'B';
177 p
.sleep
= *threads_spec
++ == 'S';
179 if (p
.burn
|| p
.sleep
) {
181 pthread_create(&zzzz
, NULL
, sleeper_or_burner
, &p
);
186 m
.burn
= *threads_spec
++ == 'B';
187 m
.sleep
= *threads_spec
++ == 'S';
189 sleeper_or_burner(&m
);
191 if (b
.t
!= -1) pthread_join(ebbr
, NULL
);
192 if (l
.t
!= -1) pthread_join(egll
, NULL
);
193 if (p
.t
!= -1) pthread_join(zzzz
, NULL
);