-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mutex_lock.c
199 lines (158 loc) · 4.86 KB
/
mutex_lock.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include <libc.h>
int shared_vector[180];
int shared_index;
int shared_mutex;
void *modify_shared_vector(void *arg)
{
int ret = -1;
while (shared_index < 12)
{
ret = mutex_lock(shared_mutex);
if (ret < 0)
return (void *)0;
shared_vector[shared_index] = (int)arg;
shared_index++;
ret = mutex_unlock(shared_mutex);
if (ret < 0)
return (void *)0;
}
return (void *)0;
}
/*
What:
The current thread creates two more threads. Each one has a unique value 31, 21 and 11,
that must be written to the global shared vector by all of them in this order:
31, 21, 11, 31, 21, 11, 31, 21, 11... and so on. The ordering constraint is enforced by
a global shared mutex.
Notice that all the threads also access the shared vector using a shared index, which is
incremented by all of them in order.
Expected:
No errors appear when using the mutex "shared_mutex", locking and unlocking it. The resulting
vector "shared_vector" has the unique values of each thread in the order described before.
*/
int mutex_lock_unlock_success(void)
{
int ret = -1;
shared_mutex = mutex_init();
if (shared_mutex < 0)
return false;
int TID, TIDS[2];
ret = pthread_create(&TID, &modify_shared_vector, (void *)21);
if (ret < 0)
return false;
TIDS[0] = TID;
ret = pthread_create(&TID, &modify_shared_vector, (void *)11);
if (ret < 0)
return false;
TIDS[1] = TID;
int wait_for_threads = true;
while (shared_index < 12)
{
ret = mutex_lock(shared_mutex);
if (ret < 0)
return false;
shared_vector[shared_index] = 31;
shared_index++;
// Let enough time at first in order that the other threads start execution and get blocked at the mutex
if (wait_for_threads)
{
wait_for_threads = false;
delay(100);
}
ret = mutex_unlock(shared_mutex);
if (ret < 0)
return false;
}
for (int i = 0; i < 12; i++)
{
switch (i % 3)
{
case 0:
if (shared_vector[i] != 31)
return false;
break;
case 1:
if (shared_vector[i] != 21)
return false;
break;
case 2:
if (shared_vector[i] != 11)
return false;
break;
default:
break;
}
}
// Free all the created threads and mutexes in order to execute other tests correctly
pthread_join(TIDS[0], NULL);
pthread_join(TIDS[1], NULL);
mutex_unlock(shared_mutex);
mutex_destroy(shared_mutex);
return true;
}
/*
What:
The current thread tries to perform the mutex_lock syscall with wrong params,
one param wrong at a time.
Expected:
No mutex is locked when passing invalid parameters to the mutex_lock syscall.
The errno variable is set to EINVAL as we passed invalid parameters.
Notice that our system supports 20 mutexes and we are passing smaller or greater
mutex ids from the range 0-19. Also a mutex cannot be locked if it was not
initialized or was already destroyed before.
*/
int mutex_lock_EINVAL(void)
{
int ret = -1;
int mutex_id;
mutex_id = mutex_init();
if (mutex_id < 0)
return false;
ret = mutex_destroy(mutex_id);
if (ret < 0)
return false;
ret = mutex_lock(mutex_id);
if (ret >= 0 || errno != EINVAL)
return false;
ret = mutex_lock(11);
if (ret >= 0 || errno != EINVAL)
return false;
ret = mutex_lock(-31);
if (ret >= 0 || errno != EINVAL)
return false;
ret = mutex_lock(31);
if (ret >= 0 || errno != EINVAL)
return false;
// Unlock and destroy initialized mutex in order to execute other tests correctly
mutex_unlock(mutex_id);
mutex_destroy(mutex_id);
return true;
}
/*
What:
The current thread tries to lock a mutex that has been locked before by itself.
Expected:
The mutex_lock syscall returns error and sets the errno variable to EDEADLK as the
mutex has been already locked by the current thread but not unlocked. A mutex cannot
be locked by the same thread consecutively if the thread is the owner of the mutex,
as that would result in a deadlock. (Because the only thread that could unblock other
threads blocked at the mutex is also blocked)
*/
int mutex_lock_EDEADLK(void)
{
int ret = -1;
int mutex_id;
mutex_id = mutex_init();
if (mutex_id < 0)
return false;
ret = mutex_lock(mutex_id);
if (ret < 0)
return false;
ret = mutex_lock(mutex_id);
if (ret >= 0 || errno != EDEADLK)
return false;
// Unlock and destroy initialized mutex in order to execute other tests correctly
mutex_unlock(mutex_id);
mutex_destroy(mutex_id);
return true;
}