Skip to content

Commit e676eae

Browse files
committed
Account for spurious wakeups when using pthread_cond
1 parent 5d0be28 commit e676eae

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <sched.h>
4+
#include <stdbool.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
8+
int shared_global;
9+
pthread_mutex_t signal_mutex;
10+
pthread_cond_t condition;
11+
bool signal_sent;
12+
13+
void initialise_condition(void)
14+
{
15+
pthread_mutexattr_t *mutex_attributes = NULL;
16+
int pthread_mutex_init_error =
17+
pthread_mutex_init(&signal_mutex, mutex_attributes);
18+
assert(!pthread_mutex_init_error);
19+
20+
pthread_condattr_t *condition_attributes = NULL;
21+
int condition_init_error =
22+
pthread_cond_init(&condition, condition_attributes);
23+
assert(!condition_init_error);
24+
}
25+
26+
// Wait for signal. Note that pthreads requires us to lock and unlock the mutex
27+
// around the call to `pthread_cond_wait`.
28+
void wait(void)
29+
{
30+
const int lock_error = pthread_mutex_lock(&signal_mutex);
31+
assert(!lock_error);
32+
const int wait_error = pthread_cond_wait(&condition, &signal_mutex);
33+
assert(!wait_error);
34+
const int unlock_error = pthread_mutex_unlock(&signal_mutex);
35+
assert(!unlock_error);
36+
}
37+
38+
void signal(void)
39+
{
40+
const int lock_error = pthread_mutex_lock(&signal_mutex);
41+
assert(!lock_error);
42+
int signal_error = pthread_cond_signal(&condition);
43+
assert(!signal_error);
44+
const int unlock_error = pthread_mutex_unlock(&signal_mutex);
45+
assert(!unlock_error);
46+
}
47+
48+
void *worker(void *arguments)
49+
{
50+
shared_global = 42;
51+
signal_sent = true;
52+
signal();
53+
pthread_exit(NULL);
54+
}
55+
56+
pthread_t start_worker_thread(void)
57+
{
58+
pthread_t worker_thread;
59+
const pthread_attr_t *const attributes = NULL;
60+
void *const worker_argument = NULL;
61+
const int create_status =
62+
pthread_create(&worker_thread, attributes, &worker, worker_argument);
63+
assert(create_status == 0);
64+
return worker_thread;
65+
}
66+
67+
void join_thread(const pthread_t thread)
68+
{
69+
const int join_status = pthread_join(thread, NULL);
70+
assert(join_status == 0);
71+
}
72+
73+
int main(void)
74+
{
75+
shared_global = 0;
76+
signal_sent = false;
77+
const pthread_t worker_thread1 = start_worker_thread();
78+
while(!signal_sent)
79+
{
80+
wait();
81+
}
82+
assert(shared_global == 42);
83+
join_thread(worker_thread1);
84+
85+
pthread_mutex_destroy(&signal_mutex);
86+
pthread_cond_destroy(&condition);
87+
return EXIT_SUCCESS;
88+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FUTURE requires_posix_only_headers
2+
spurious_wakeup.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring
9+
pointer handling for concurrency is unsound
10+
--
11+
Test that spurious wake ups in code employing signals can violate conditions
12+
which we would other wise expect to hold.

0 commit comments

Comments
 (0)