Avoid using a HashTable to associate FuncInsts with ModelActions; a slight improvemen...
[c11tester.git] / pthread.cc
1 #include "common.h"
2 #include "threads-model.h"
3 #include "action.h"
4 #include "mypthread.h"
5
6 #include "snapshot-interface.h"
7 #include "datarace.h"
8
9 #include "mutex.h"
10 #include <condition_variable>
11
12 /* global "model" object */
13 #include "model.h"
14 #include "execution.h"
15 extern "C" {
16 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
17 }
18
19 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) {
20         if (model) {
21                 uint64_t time = rqtp->tv_sec * 1000000000 + rqtp->tv_nsec;
22                 struct timespec currtime;
23                 clock_gettime(CLOCK_MONOTONIC, &currtime);
24                 uint64_t lcurrtime = currtime.tv_sec * 1000000000 + currtime.tv_nsec;
25                 model->switch_to_master(new ModelAction(THREAD_SLEEP, std::memory_order_seq_cst, time, lcurrtime));
26                 if (rmtp != NULL) {
27                         clock_gettime(CLOCK_MONOTONIC, &currtime);
28                         uint64_t lendtime = currtime.tv_sec * 1000000000 + currtime.tv_nsec;
29                         uint64_t elapsed = lendtime - lcurrtime;
30                         rmtp->tv_sec = elapsed / 1000000000;
31                         rmtp->tv_nsec = elapsed - rmtp->tv_sec * 1000000000;
32                 }
33         }
34         return 0;
35 }
36
37 int pthread_create(pthread_t *t, const pthread_attr_t * attr,
38          pthread_start_t start_routine, void * arg) {
39         if (!model) {
40                 snapshot_system_init(10000, 1024, 1024, 40000);
41                 model = new ModelChecker();
42                 model->startChecker();
43         }
44
45         struct pthread_params params = { start_routine, arg };
46
47         ModelAction *act = new ModelAction(PTHREAD_CREATE, std::memory_order_seq_cst, t, (uint64_t)&params);
48
49         /* seq_cst is just a 'don't care' parameter */
50         model->switch_to_master(act);
51
52         return 0;
53 }
54
55 int pthread_join(pthread_t t, void **value_ptr) {
56         ModelExecution *execution = model->get_execution();
57         Thread *th = execution->get_pthread(t);
58
59         model->switch_to_master(new ModelAction(PTHREAD_JOIN, std::memory_order_seq_cst, th, id_to_int(th->get_id())));
60
61         if ( value_ptr ) {
62                 // store return value
63                 void *rtval = th->get_pthread_return();
64                 *value_ptr = rtval;
65         }
66         return 0;
67 }
68
69 int pthread_detach(pthread_t t) {
70         //Doesn't do anything
71         //Return success
72         return 0;
73 }
74
75 void pthread_exit(void *value_ptr) {
76         Thread * th = thread_current();
77         th->set_pthread_return(value_ptr);
78         model->switch_to_master(new ModelAction(THREADONLY_FINISH, std::memory_order_seq_cst, th));
79         //Need to exit so we don't return to the program
80         real_pthread_exit(NULL);
81 }
82
83 int pthread_mutex_init(pthread_mutex_t *p_mutex, const pthread_mutexattr_t *) {
84         if (!model) {
85                 snapshot_system_init(10000, 1024, 1024, 40000);
86                 model = new ModelChecker();
87                 model->startChecker();
88         }
89         cdsc::snapmutex *m = new cdsc::snapmutex();
90
91         ModelExecution *execution = model->get_execution();
92         execution->getMutexMap()->put(p_mutex, m);
93
94         return 0;
95 }
96
97 int pthread_mutex_lock(pthread_mutex_t *p_mutex) {
98         if (!model) {
99                 snapshot_system_init(10000, 1024, 1024, 40000);
100                 model = new ModelChecker();
101                 model->startChecker();
102         }
103
104         ModelExecution *execution = model->get_execution();
105
106         /* to protect the case where PTHREAD_MUTEX_INITIALIZER is used
107            instead of pthread_mutex_init, or where *p_mutex is not stored
108            in the execution->mutex_map for some reason. */
109         if (!execution->getMutexMap()->contains(p_mutex)) {
110                 pthread_mutex_init(p_mutex, NULL);
111         }
112
113         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
114
115         if (m != NULL) {
116                 m->lock();
117         } else {
118                 return 1;
119         }
120
121         return 0;
122 }
123
124 int pthread_mutex_trylock(pthread_mutex_t *p_mutex) {
125         if (!model) {
126                 snapshot_system_init(10000, 1024, 1024, 40000);
127                 model = new ModelChecker();
128                 model->startChecker();
129         }
130
131         ModelExecution *execution = model->get_execution();
132         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
133         return m->try_lock();
134 }
135 int pthread_mutex_unlock(pthread_mutex_t *p_mutex) {
136         ModelExecution *execution = model->get_execution();
137         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
138
139         if (m != NULL) {
140                 m->unlock();
141         } else {
142                 printf("try to unlock an untracked pthread_mutex\n");
143                 return 1;
144         }
145
146         return 0;
147 }
148
149 int pthread_mutex_timedlock (pthread_mutex_t *__restrict p_mutex,
150          const struct timespec *__restrict abstime) {
151 // timedlock just gives the option of giving up the lock, so return and let the scheduler decide which thread goes next
152
153         if (!model) {
154                 snapshot_system_init(10000, 1024, 1024, 40000);
155                 model = new ModelChecker();
156                 model->startChecker();
157         }
158
159         ModelExecution *execution = model->get_execution();
160
161         /* to protect the case where PTHREAD_MUTEX_INITIALIZER is used
162            instead of pthread_mutex_init, or where *p_mutex is not stored
163            in the execution->mutex_map for some reason. */
164         if (!execution->getMutexMap()->contains(p_mutex)) {
165                 pthread_mutex_init(p_mutex, NULL);
166         }
167
168         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
169
170         if (m != NULL) {
171                 m->lock();
172         } else {
173                 return 1;
174         }
175
176         return 0;
177 }
178
179 pthread_t pthread_self() {
180         Thread* th = model->get_current_thread();
181         return (pthread_t)th->get_id();
182 }
183
184 int pthread_key_delete(pthread_key_t) {
185         model_print("key_delete is called\n");
186         return 0;
187 }
188
189 int pthread_cond_init(pthread_cond_t *p_cond, const pthread_condattr_t *attr) {
190         cdsc::snapcondition_variable *v = new cdsc::snapcondition_variable();
191
192         ModelExecution *execution = model->get_execution();
193         execution->getCondMap()->put(p_cond, v);
194         return 0;
195 }
196
197 int pthread_cond_wait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex) {
198         ModelExecution *execution = model->get_execution();
199         if ( !execution->getCondMap()->contains(p_cond) )
200                 pthread_cond_init(p_cond, NULL);
201         if ( !execution->getMutexMap()->contains(p_mutex) )
202                 pthread_mutex_init(p_mutex, NULL);
203
204         cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
205         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
206
207         v->wait(*m);
208         return 0;
209 }
210
211 int pthread_cond_timedwait(pthread_cond_t *p_cond,
212         pthread_mutex_t *p_mutex, const struct timespec *abstime) {
213         ModelExecution *execution = model->get_execution();
214
215         if ( !execution->getCondMap()->contains(p_cond) )
216                 pthread_cond_init(p_cond, NULL);
217         if ( !execution->getMutexMap()->contains(p_mutex) )
218                 pthread_mutex_init(p_mutex, NULL);
219
220         cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
221         cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex);
222
223         model->switch_to_master(new ModelAction(ATOMIC_TIMEDWAIT, std::memory_order_seq_cst, v, (uint64_t) m));
224         m->lock();
225
226         // model_print("Timed_wait is called\n");
227         return 0;
228 }
229
230 int pthread_cond_signal(pthread_cond_t *p_cond) {
231         // notify only one blocked thread
232         ModelExecution *execution = model->get_execution();
233         if ( !execution->getCondMap()->contains(p_cond) )
234                 pthread_cond_init(p_cond, NULL);
235
236         cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
237
238         v->notify_one();
239         return 0;
240 }
241
242 int pthread_cond_broadcast(pthread_cond_t *p_cond) {
243         // notify all blocked threads
244         ModelExecution *execution = model->get_execution();
245         if ( !execution->getCondMap()->contains(p_cond) )
246                 pthread_cond_init(p_cond, NULL);
247
248         cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
249
250         v->notify_all();
251         return 0;
252 }
253
254 int pthread_cond_destroy(pthread_cond_t *p_cond) {
255         ModelExecution *execution = model->get_execution();
256
257         if (execution->getCondMap()->contains(p_cond)) {
258                 cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
259                 delete v;
260                 execution->getCondMap()->remove(p_cond);
261         }
262         return 0;
263 }