e5bc9018477a469288cb60235a8661ad31012d28
[c11tester.git] / pthread.cc
1 #include "common.h"
2 #include "threads-model.h"
3 #include "action.h"
4 #include "pthread.h"
5
6 #include "snapshot-interface.h"
7 #include "datarace.h"
8
9 #include "mutex.h"
10 #include <condition_variable>
11 #include <assert.h>
12
13 /* global "model" object */
14 #include "model.h"
15 #include "execution.h"
16
17 static void param_defaults(struct model_params *params)
18 {
19         params->maxreads = 0;
20         params->fairwindow = 0;
21         params->yieldon = false;
22         params->yieldblock = false;
23         params->enabledcount = 1;
24         params->bound = 0;
25         params->verbose = !!DBG_ENABLED();
26         params->uninitvalue = 0;
27         params->maxexecutions = 0;
28 }
29
30 static void model_main()
31 {
32         struct model_params params;
33
34         param_defaults(&params);
35
36         //parse_options(&params, main_argc, main_argv);
37
38         //Initialize race detector
39         initRaceDetector();
40
41         snapshot_stack_init();
42
43         model = new ModelChecker(params);       // L: Model thread is created
44 //      install_trace_analyses(model->get_execution());         L: disable plugin
45
46         snapshot_record(0);
47         model->run();
48         delete model;
49
50         DEBUG("Exiting\n");
51 }
52
53 int pthread_create(pthread_t *t, const pthread_attr_t * attr,
54           pthread_start_t start_routine, void * arg) {
55         struct pthread_params params = { start_routine, arg };
56
57         ModelAction *act = new ModelAction(PTHREAD_CREATE, std::memory_order_seq_cst, t, (uint64_t)&params);
58
59         /* seq_cst is just a 'don't care' parameter */
60         model->switch_to_master(act);
61
62         return 0;
63 }
64
65 int pthread_join(pthread_t t, void **value_ptr) {
66 //      Thread *th = model->get_pthread(t);
67         ModelExecution *execution = model->get_execution();
68         Thread *th = execution->get_pthread(t);
69
70         model->switch_to_master(new ModelAction(PTHREAD_JOIN, std::memory_order_seq_cst, th, id_to_int(th->get_id())));
71
72         if ( value_ptr ) {
73                 // store return value
74                 void *rtval = th->get_pthread_return();
75                 *value_ptr = rtval;
76         } 
77         return 0;
78 }
79
80 void pthread_exit(void *value_ptr) {
81         Thread * th = thread_current();
82         model->switch_to_master(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, th));
83 }
84
85 int pthread_mutex_init(pthread_mutex_t *p_mutex, const pthread_mutexattr_t *) {
86         if (!model) {
87                 snapshot_system_init(10000, 1024, 1024, 40000, &model_main);
88         }
89
90         cdsc::mutex *m = new cdsc::mutex();
91
92         ModelExecution *execution = model->get_execution();
93         execution->getMutexMap()->put(p_mutex, m);
94         return 0;
95 }
96
97 int pthread_mutex_lock(pthread_mutex_t *p_mutex) {
98         ModelExecution *execution = model->get_execution();
99
100         /* to protect the case where PTHREAD_MUTEX_INITIALIZER is used 
101            instead of pthread_mutex_init, or where *p_mutex is not stored
102            in the execution->mutex_map for some reason. */
103         if (!execution->getMutexMap()->contains(p_mutex)) {     
104                 pthread_mutex_init(p_mutex, NULL);
105         }
106
107         cdsc::mutex *m = execution->getMutexMap()->get(p_mutex);
108
109         if (m != NULL) {
110                 m->lock();
111         } else {
112                 printf("ah\n");
113         }
114
115         return 0;
116 }
117
118 int pthread_mutex_trylock(pthread_mutex_t *p_mutex) {
119         ModelExecution *execution = model->get_execution();
120         cdsc::mutex *m = execution->getMutexMap()->get(p_mutex);
121         return m->try_lock();
122 }
123 int pthread_mutex_unlock(pthread_mutex_t *p_mutex) {    
124         ModelExecution *execution = model->get_execution();
125         cdsc::mutex *m = execution->getMutexMap()->get(p_mutex);
126
127         if (m != NULL) {
128                 m->unlock();
129         } else {
130                 printf("try to unlock an untracked pthread_mutex\n");
131         }
132
133         return 0;
134 }
135
136 int pthread_mutex_timedlock (pthread_mutex_t *__restrict p_mutex,
137                                 const struct timespec *__restrict abstime) {
138 // timedlock just gives the option of giving up the lock, so return and let the scheduler decide which thread goes next
139
140 /*
141         ModelExecution *execution = model->get_execution();
142         if (!execution->mutex_map.contains(p_mutex)) {  
143                 pthread_mutex_init(p_mutex, NULL);
144         }
145         cdsc::mutex *m = execution->mutex_map.get(p_mutex);
146
147         if (m != NULL) {
148                 m->lock();
149         } else {
150                 printf("something is wrong with pthread_mutex_timedlock\n");
151         }
152
153         printf("pthread_mutex_timedlock is called. It is currently implemented as a normal lock operation without no timeout\n");
154 */
155         return 0;
156 }
157
158 pthread_t pthread_self() {
159         Thread* th = model->get_current_thread();
160         return th->get_id();
161 }
162
163 int pthread_key_delete(pthread_key_t) {
164         model_print("key_delete is called\n");
165         return 0;
166 }
167
168 int pthread_cond_init(pthread_cond_t *p_cond, const pthread_condattr_t *attr) {
169         cdsc::condition_variable *v = new cdsc::condition_variable();
170
171         ModelExecution *execution = model->get_execution();
172         execution->getCondMap()->put(p_cond, v);
173         return 0;
174 }
175
176 int pthread_cond_wait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex) {
177         ModelExecution *execution = model->get_execution();
178         if ( !execution->getCondMap()->contains(p_cond) )
179                 pthread_cond_init(p_cond, NULL);
180
181         cdsc::condition_variable *v = execution->getCondMap()->get(p_cond);
182         cdsc::mutex *m = execution->getMutexMap()->get(p_mutex);
183
184         v->wait(*m);
185         return 0;
186 }
187
188 int pthread_cond_timedwait(pthread_cond_t *p_cond, 
189     pthread_mutex_t *p_mutex, const struct timespec *abstime) {
190 // implement cond_timedwait as a noop and let the scheduler decide which thread goes next
191         ModelExecution *execution = model->get_execution();
192
193         if ( !execution->getCondMap()->contains(p_cond) )
194                 pthread_cond_init(p_cond, NULL);
195         if ( !execution->getMutexMap()->contains(p_mutex) )
196                 pthread_mutex_init(p_mutex, NULL);
197
198         cdsc::condition_variable *v = execution->getCondMap()->get(p_cond);
199         cdsc::mutex *m = execution->getMutexMap()->get(p_mutex);
200
201         model->switch_to_master(new ModelAction(NOOP, std::memory_order_seq_cst, v, NULL));
202 //      v->wait(*m);
203 //      printf("timed_wait called\n");
204         return 0;
205 }
206
207 int pthread_cond_signal(pthread_cond_t *p_cond) {
208         // notify only one blocked thread
209         ModelExecution *execution = model->get_execution();
210         if ( !execution->getCondMap()->contains(p_cond) )
211                 pthread_cond_init(p_cond, NULL);
212
213         cdsc::condition_variable *v = execution->getCondMap()->get(p_cond);
214
215         v->notify_one();
216         return 0;
217 }