-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpu_memory_consistency_race.c
127 lines (112 loc) · 3.06 KB
/
cpu_memory_consistency_race.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Dekker's algorithm, implemented on pthreads
*
* To use as a test to see if/when we can make
* memory consistency play games with us in
* practice.
*
* Compile: gcc -O2 -o dekker dekker.c -lpthread
* Source: http://jakob.engbloms.se/archives/65
*/
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#undef PRINT_PROGRESS
static volatile int flag1 = 0;
static volatile int flag2 = 0;
static volatile int turn = 1;
static volatile int gSharedCounter = 0;
int gLoopCount;
int gOnePercent;
void dekker1( ) {
flag1 = 1;
turn = 2;
while((flag2 == 1) && (turn == 2)) ;
/* Critical section */
gSharedCounter++;
/* Let the other task run */
flag1 = 0;
}
void dekker2(void) {
flag2 = 1;
turn = 1;
while((flag1 == 1) && (turn == 1)) ;
/* critical section */
gSharedCounter++;
/* leave critical section */
flag2 = 0;
}
/* Tasks, as a level of indirection
*/
void *task1(void *arg) {
int i,j;
printf("Starting task1\n");
/* Do the dekker very many times */
#ifdef PRINT_PROGRESS
for(i=0;i<100;i++) {
printf("[One] at %d%%\n",i);
for(j=gOnePercent;j>0;j--) {
dekker1();
}
}
#else
/* Simple basic loop */
for(i=gLoopCount;i>0;i--) {
dekker1();
}
#endif
}
void *task2(void *arg) {
int i,j;
printf("Starting task2\n");
#ifdef PRINT_PROGRESS
for(i=0;i<100;i++) {
printf("[Two] at %d%%\n",i);
for(j=gOnePercent;j>0;j--) {
dekker2();
}
}
#else
for(i=gLoopCount;i>0;i--) {
dekker2();
}
#endif
}
int
main(int argc, char ** argv)
{
int loopCount = 0;
pthread_t dekker_thread_1;
pthread_t dekker_thread_2;
void * returnCode;
int result;
int expected_sum;
/* Check arguments to program*/
if(argc != 2)
{
fprintf(stderr, "USAGE: %s <loopcount>\n", argv[0]);
exit(1);
}
/* Parse argument */
loopCount = atoi(argv[1]); /* Don't bother with format checking */
gLoopCount = loopCount;
gOnePercent = loopCount/100;
expected_sum = 2*loopCount;
/* Start the threads */
result = pthread_create(&dekker_thread_1, NULL, task1, NULL);
result = pthread_create(&dekker_thread_2, NULL, task2, NULL);
/* Wait for the threads to end */
result = pthread_join(dekker_thread_1,&returnCode);
result = pthread_join(dekker_thread_2,&returnCode);
printf("Both threads terminated\n");
/* Check result */
if( gSharedCounter != expected_sum ) {
printf("[-] Dekker did not work, sum %d rather than %d.\n", gSharedCounter, expected_sum);
printf(" %d missed updates due to memory consistency races.\n", (expected_sum-gSharedCounter));
return 1;
} else {
printf("[+] Dekker worked.\n");
return 0;
}
}