Skip to content

Commit 9ac232b

Browse files
Merge pull request #5521 from thomasspriggs/tas/pthread_examples
Add concurrency examples to regression tests
2 parents 1b78b1c + 52c0a80 commit 9ac232b

25 files changed

+994
-0
lines changed

regression/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ add_subdirectory(linking-goto-binaries)
6161
add_subdirectory(symtab2gb)
6262
add_subdirectory(validate-trace-xml-schema)
6363
add_subdirectory(cbmc-primitives)
64+
add_subdirectory(cbmc-sequentialization)
6465

6566
if(WITH_MEMORY_ANALYZER)
6667
add_subdirectory(snapshot-harness)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
if(NOT WIN32)
2+
add_test_pl_tests(
3+
"$<TARGET_FILE:cbmc> --validate-goto-model --validate-ssa-equation"
4+
)
5+
else()
6+
add_test_pl_tests(
7+
"$<TARGET_FILE:cbmc> --validate-goto-model --validate-ssa-equation"
8+
-X requires_posix_only_headers
9+
)
10+
endif()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
default: test
2+
3+
include ../../src/config.inc
4+
include ../../src/common
5+
6+
ifeq ($(BUILD_ENV_),MSVC)
7+
GCC_ONLY = -X gcc-only
8+
else
9+
GCC_ONLY =
10+
endif
11+
12+
test:
13+
@../test.pl -e -p -c "../../../src/cbmc/cbmc --validate-goto-model --validate-ssa-equation" -X smt-backend $(GCC_ONLY)
14+
15+
test-cprover-smt2:
16+
@../test.pl -e -p -c "../../../src/cbmc/cbmc --cprover-smt2" -X broken-smt-backend $(GCC_ONLY)
17+
18+
test-paths-lifo:
19+
@../test.pl -e -p -c "../../../src/cbmc/cbmc --paths lifo" -X thorough-paths -X smt-backend -X paths-lifo-expected-failure $(GCC_ONLY)
20+
21+
tests.log: ../test.pl test
22+
23+
show:
24+
@for dir in *; do \
25+
if [ -d "$$dir" ]; then \
26+
vim -o "$$dir/*.c" "$$dir/*.out"; \
27+
fi; \
28+
done;
29+
30+
clean:
31+
find -name '*.out' -execdir $(RM) '{}' \;
32+
find -name '*.smt2' -execdir $(RM) '{}' \;
33+
$(RM) tests.log
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <semaphore.h>
4+
#include <stdbool.h>
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
8+
pthread_t start_worker_thread(void *(*start_routine)(void *))
9+
{
10+
pthread_t worker_thread;
11+
const pthread_attr_t *const attributes = NULL;
12+
void *const worker_argument = NULL;
13+
const int create_status =
14+
pthread_create(&worker_thread, attributes, start_routine, worker_argument);
15+
assert(create_status == 0);
16+
return worker_thread;
17+
}
18+
19+
void join_thread(const pthread_t thread)
20+
{
21+
const int join_status = pthread_join(thread, NULL);
22+
assert(join_status == 0);
23+
}
24+
25+
sem_t create_semaphore(int initial_value)
26+
{
27+
const int shared_between_processes = false;
28+
sem_t semaphore;
29+
const int init_error =
30+
sem_init(&semaphore, shared_between_processes, initial_value);
31+
assert(init_error == false);
32+
return semaphore;
33+
}
34+
35+
void destroy_semaphore(sem_t *const semaphore)
36+
{
37+
int destroy_error = sem_destroy(semaphore);
38+
assert(destroy_error == false);
39+
}
40+
41+
// This blocking queue structure supports waiting for free space before
42+
// enqueuing and waiting for data before dequeuing, using a pair of semaphores.
43+
// These functions do not employ a mutex, so a data race may occur if multiple
44+
// threads attempt to enqueue at the same time or multiple threads attempt to
45+
// dequeue at the same time. The expected valid use case is with two threads,
46+
// where one of the two enqueues and the other thread dequeues.
47+
struct blocking_queuet
48+
{
49+
size_t size;
50+
int *elements;
51+
size_t begin;
52+
size_t end;
53+
sem_t free_space;
54+
sem_t data_waiting;
55+
};
56+
57+
struct blocking_queuet initialise_blocking_queue(const size_t size)
58+
{
59+
printf("init queue begin\n");
60+
struct blocking_queuet queue;
61+
queue.size = size;
62+
queue.elements = calloc(size, sizeof(int));
63+
queue.begin = 0;
64+
queue.end = 0;
65+
queue.free_space = create_semaphore(size);
66+
queue.data_waiting = create_semaphore(0);
67+
printf("init queue end\n");
68+
return queue;
69+
}
70+
71+
void free_blocking_queue(struct blocking_queuet *queue)
72+
{
73+
free(queue->elements);
74+
queue->elements = NULL;
75+
destroy_semaphore(&queue->free_space);
76+
destroy_semaphore(&queue->data_waiting);
77+
}
78+
79+
void enqueue(struct blocking_queuet *queue, const int data)
80+
{
81+
printf(
82+
"enqueue begin:%lu end:%lu data:%d \n", queue->begin, queue->end, data);
83+
const int free_wait_error = sem_wait(&queue->free_space);
84+
assert(free_wait_error == false);
85+
queue->elements[queue->end] = data;
86+
if(++queue->end == queue->size)
87+
{
88+
queue->end = 0;
89+
}
90+
const int post_error = sem_post(&queue->data_waiting);
91+
assert(post_error == false);
92+
printf("enqueue done\n");
93+
}
94+
95+
int dequeue(struct blocking_queuet *queue)
96+
{
97+
printf("dequeue begin:%lu end:%lu\n", queue->begin, queue->end);
98+
const int data_wait_error = sem_wait(&queue->data_waiting);
99+
assert(data_wait_error == false);
100+
int result = queue->elements[queue->begin];
101+
if(++queue->begin == queue->size)
102+
{
103+
queue->begin = 0;
104+
}
105+
const int free_error = sem_post(&queue->free_space);
106+
assert(free_error == false);
107+
printf("dequeue done. data:%d \n", result);
108+
return result;
109+
}
110+
111+
struct blocking_queuet input_queue;
112+
struct blocking_queuet output_queue;
113+
114+
void *worker(void *arguments)
115+
{
116+
int data;
117+
while(data = dequeue(&input_queue))
118+
{
119+
enqueue(&output_queue, data * data);
120+
}
121+
pthread_exit(NULL);
122+
}
123+
124+
int main(void)
125+
{
126+
input_queue = initialise_blocking_queue(3);
127+
output_queue = initialise_blocking_queue(10);
128+
const pthread_t worker_thread1 = start_worker_thread(&worker);
129+
printf("worker_started\n");
130+
enqueue(&input_queue, 1);
131+
enqueue(&input_queue, 2);
132+
enqueue(&input_queue, 3);
133+
enqueue(&input_queue, 4);
134+
enqueue(&input_queue, 5);
135+
enqueue(&input_queue, 6);
136+
enqueue(&input_queue, 7);
137+
enqueue(&input_queue, 8);
138+
enqueue(&input_queue, 9);
139+
enqueue(&input_queue, 0);
140+
join_thread(worker_thread1);
141+
free_blocking_queue(&input_queue);
142+
assert(dequeue(&output_queue) == 1);
143+
assert(dequeue(&output_queue) == 4);
144+
assert(dequeue(&output_queue) == 9);
145+
assert(dequeue(&output_queue) == 16);
146+
assert(dequeue(&output_queue) == 25);
147+
assert(dequeue(&output_queue) == 36);
148+
assert(dequeue(&output_queue) == 49);
149+
assert(dequeue(&output_queue) == 64);
150+
assert(dequeue(&output_queue) == 81);
151+
free_blocking_queue(&output_queue);
152+
return EXIT_SUCCESS;
153+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FUTURE requires_posix_only_headers
2+
blocking_queue.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
pointer handling for concurrency is unsound
10+
--
11+
Test using an example simplistic implementation of a blocking queue.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <semaphore.h>
4+
#include <stdbool.h>
5+
#include <stdlib.h>
6+
7+
pthread_t start_worker_thread(void *(*start_routine)(void *))
8+
{
9+
pthread_t worker_thread;
10+
const pthread_attr_t *const attributes = NULL;
11+
void *const worker_argument = NULL;
12+
const int create_status =
13+
pthread_create(&worker_thread, attributes, start_routine, worker_argument);
14+
assert(create_status == 0);
15+
return worker_thread;
16+
}
17+
18+
void join_thread(const pthread_t thread)
19+
{
20+
const int join_status = pthread_join(thread, NULL);
21+
assert(join_status == 0);
22+
}
23+
24+
sem_t create_semaphore(int initial_value)
25+
{
26+
const int shared_between_processes = false;
27+
sem_t semaphore;
28+
const int init_error =
29+
sem_init(&semaphore, shared_between_processes, initial_value);
30+
assert(init_error == false);
31+
return semaphore;
32+
}
33+
34+
void destroy_semaphore(sem_t *const semaphore)
35+
{
36+
int destroy_error = sem_destroy(semaphore);
37+
assert(destroy_error == false);
38+
}
39+
40+
sem_t global_semaphore;
41+
int global_value;
42+
43+
void *worker(void *arguments)
44+
{
45+
const int wait_error = sem_wait(&global_semaphore);
46+
assert(wait_error == false);
47+
assert(global_value == 42);
48+
pthread_exit(NULL);
49+
}
50+
51+
int main(void)
52+
{
53+
global_semaphore = create_semaphore(0);
54+
global_value = 0;
55+
56+
const pthread_t worker_thread1 = start_worker_thread(&worker);
57+
global_value = 42;
58+
const int post_error = sem_post(&global_semaphore);
59+
assert(post_error == false);
60+
join_thread(worker_thread1);
61+
62+
destroy_semaphore(&global_semaphore);
63+
return EXIT_SUCCESS;
64+
}
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+
blocking_wait.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
pointer handling for concurrency is unsound
10+
--
11+
Test that sem_wait will block when the value of a semaphore is 0, until it is
12+
increased via sem_post.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <semaphore.h>
4+
#include <stdbool.h>
5+
#include <stdlib.h>
6+
7+
sem_t create_semaphore(int initial_value)
8+
{
9+
const int shared_between_processes = false;
10+
sem_t semaphore;
11+
const int init_error =
12+
sem_init(&semaphore, shared_between_processes, initial_value);
13+
assert(init_error == false);
14+
return semaphore;
15+
}
16+
17+
void destroy_semaphore(sem_t *const semaphore)
18+
{
19+
int destroy_error = sem_destroy(semaphore);
20+
assert(destroy_error == false);
21+
}
22+
23+
sem_t global_semaphore;
24+
25+
int main(void)
26+
{
27+
global_semaphore = create_semaphore(0);
28+
destroy_semaphore(&global_semaphore);
29+
return EXIT_SUCCESS;
30+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE requires_posix_only_headers
2+
create_destroy.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
pointer handling for concurrency is unsound
10+
--
11+
Sanity check that cbmc can deal with creation and destruction of semaphores.

0 commit comments

Comments
 (0)