merge
[c11tester.git] / threads.cc
1 /** @file threads.cc
2  *  @brief Thread functions.
3  */
4
5 #include <string.h>
6
7 #include <threads.h>
8 #include "mutex.h"
9 #include "common.h"
10 #include "threads-model.h"
11 #include "action.h"
12
13 /* global "model" object */
14 #include "model.h"
15 #include "execution.h"
16
17 #ifdef TLS
18 #include <dlfcn.h>
19 uintptr_t get_tls_addr() {
20         uintptr_t addr;
21         asm ("mov %%fs:0, %0" : "=r" (addr));
22         return addr;
23 }
24
25 #include <asm/prctl.h>
26 #include <sys/prctl.h>
27 extern "C" {
28 int arch_prctl(int code, unsigned long addr);
29 }
30 static void set_tls_addr(uintptr_t addr) {
31         arch_prctl(ARCH_SET_FS, addr);
32         asm ("mov %0, %%fs:0" : : "r" (addr) : "memory");
33 }
34 #endif
35
36 /** Allocate a stack for a new thread. */
37 static void * stack_allocate(size_t size)
38 {
39         return Thread_malloc(size);
40 }
41
42 /** Free a stack for a terminated thread. */
43 static void stack_free(void *stack)
44 {
45         Thread_free(stack);
46 }
47
48 /**
49  * @brief Get the current Thread
50  *
51  * Must be called from a user context
52  *
53  * @return The currently executing thread
54  */
55 Thread * thread_current(void)
56 {
57         ASSERT(model);
58         return model->get_current_thread();
59 }
60
61 void main_thread_startup() {
62 #ifdef TLS
63         Thread * curr_thread = thread_current();
64         /* Add dummy "start" action, just to create a first clock vector */
65         model->switch_to_master(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
66 #endif
67         thread_startup();
68 }
69
70 /**
71  * Provides a startup wrapper for each thread, allowing some initial
72  * model-checking data to be recorded. This method also gets around makecontext
73  * not being 64-bit clean
74  */
75 void thread_startup()
76 {
77         Thread * curr_thread = thread_current();
78 #ifndef TLS
79         /* Add dummy "start" action, just to create a first clock vector */
80         model->switch_to_master(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
81 #endif
82
83         /* Call the actual thread function */
84         if (curr_thread->start_routine != NULL) {
85                 curr_thread->start_routine(curr_thread->arg);
86         } else if (curr_thread->pstart_routine != NULL) {
87                 // set pthread return value
88                 void *retval = curr_thread->pstart_routine(curr_thread->arg);
89                 curr_thread->set_pthread_return(retval);
90         }
91         /* Finish thread properly */
92         model->switch_to_master(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, curr_thread));
93 }
94
95 static int (*pthread_mutex_init_p)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) = NULL;
96
97 int real_pthread_mutex_init(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) {
98         return pthread_mutex_init_p(__mutex, __mutexattr);
99 }
100
101 static int (*pthread_mutex_lock_p) (pthread_mutex_t *__mutex) = NULL;
102
103 int real_pthread_mutex_lock (pthread_mutex_t *__mutex) {
104         return pthread_mutex_lock_p(__mutex);
105 }
106
107 static int (*pthread_mutex_unlock_p) (pthread_mutex_t *__mutex) = NULL;
108
109 int real_pthread_mutex_unlock (pthread_mutex_t *__mutex) {
110         return pthread_mutex_unlock_p(__mutex);
111 }
112
113 static int (*pthread_create_p) (pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void * __restrict) = NULL;
114
115 int real_pthread_create (pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine)(void *), void *__restrict __arg) {
116         return pthread_create_p(__newthread, __attr, __start_routine, __arg);
117 }
118
119 static int (*pthread_join_p) (pthread_t __th, void ** __thread_return) = NULL;
120
121 int real_pthread_join (pthread_t __th, void ** __thread_return) {
122         return pthread_join_p(__th, __thread_return);
123 }
124
125 static void (*pthread_exit_p)(void *) __attribute__((noreturn))= NULL;
126
127 void real_pthread_exit (void * value_ptr) {
128         pthread_exit_p(value_ptr);
129 }
130
131 void real_init_all() {
132         char * error;
133         if (!pthread_mutex_init_p) {
134                 pthread_mutex_init_p = (int (*)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr))dlsym(RTLD_NEXT, "pthread_mutex_init");
135                 if ((error = dlerror()) != NULL) {
136                         fputs(error, stderr);
137                         exit(EXIT_FAILURE);
138                 }
139         }
140         if (!pthread_mutex_lock_p) {
141                 pthread_mutex_lock_p = (int (*)(pthread_mutex_t *__mutex))dlsym(RTLD_NEXT, "pthread_mutex_lock");
142                 if ((error = dlerror()) != NULL) {
143                         fputs(error, stderr);
144                         exit(EXIT_FAILURE);
145                 }
146         }
147         if (!pthread_mutex_unlock_p) {
148                 pthread_mutex_unlock_p = (int (*)(pthread_mutex_t *__mutex))dlsym(RTLD_NEXT, "pthread_mutex_unlock");
149                 if ((error = dlerror()) != NULL) {
150                         fputs(error, stderr);
151                         exit(EXIT_FAILURE);
152                 }
153         }
154         if (!pthread_create_p) {
155                 pthread_create_p = (int (*)(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict))dlsym(RTLD_NEXT, "pthread_create");
156                 if ((error = dlerror()) != NULL) {
157                         fputs(error, stderr);
158                         exit(EXIT_FAILURE);
159                 }
160         }
161         if (!pthread_join_p) {
162                 pthread_join_p = (int (*)(pthread_t __th, void ** __thread_return))dlsym(RTLD_NEXT, "pthread_join");
163                 if ((error = dlerror()) != NULL) {
164                         fputs(error, stderr);
165                         exit(EXIT_FAILURE);
166                 }
167         }
168
169         if (!pthread_exit_p) {
170                 pthread_exit_p = (void (*)(void *))dlsym(RTLD_NEXT, "pthread_exit");
171                 if ((error = dlerror()) != NULL) {
172                         fputs(error, stderr);
173                         exit(EXIT_FAILURE);
174                 }
175         }
176 }
177
178 #ifdef TLS
179 void finalize_helper_thread() {
180         Thread * curr_thread = thread_current();
181         real_pthread_mutex_lock(&curr_thread->mutex);
182         curr_thread->tls = (char *) get_tls_addr();
183         real_pthread_mutex_unlock(&curr_thread->mutex);
184         //Wait in the kernel until it is time for us to finish
185         real_pthread_mutex_lock(&curr_thread->mutex2);
186         real_pthread_mutex_unlock(&curr_thread->mutex2);
187         //return to helper thread function
188         setcontext(&curr_thread->context);
189 }
190
191 void * helper_thread(void * ptr) {
192         Thread * curr_thread = thread_current();
193
194         //build a context for this real thread so we can take it's context
195         int ret = getcontext(&curr_thread->helpercontext);
196         ASSERT(!ret);
197
198         /* Initialize new managed context */
199         void *helperstack = stack_allocate(STACK_SIZE);
200         curr_thread->helpercontext.uc_stack.ss_sp = helperstack;
201         curr_thread->helpercontext.uc_stack.ss_size = STACK_SIZE;
202         curr_thread->helpercontext.uc_stack.ss_flags = 0;
203         curr_thread->helpercontext.uc_link = model->get_system_context();
204         makecontext(&curr_thread->helpercontext, finalize_helper_thread, 0);
205
206         model_swapcontext(&curr_thread->context, &curr_thread->helpercontext);
207
208         //start the real thread
209         thread_startup();
210
211         //now the real thread has control again
212         stack_free(helperstack);
213
214         return NULL;
215 }
216
217 void setup_context() {
218         Thread * curr_thread = thread_current();
219
220         /* Add dummy "start" action, just to create a first clock vector */
221         model->switch_to_master(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
222
223         real_init_all();
224
225         /* Initialize our lock */
226         real_pthread_mutex_init(&curr_thread->mutex, NULL);
227         real_pthread_mutex_init(&curr_thread->mutex2, NULL);
228         real_pthread_mutex_lock(&curr_thread->mutex2);
229
230         /* Create the real thread */
231         real_pthread_create(&curr_thread->thread, NULL, helper_thread, NULL);
232         bool notdone = true;
233         while(notdone) {
234                 real_pthread_mutex_lock(&curr_thread->mutex);
235                 if (curr_thread->tls != NULL)
236                         notdone = false;
237                 real_pthread_mutex_unlock(&curr_thread->mutex);
238         }
239
240         set_tls_addr((uintptr_t)curr_thread->tls);
241         setcontext(&curr_thread->context);
242 }
243 #endif
244
245 /**
246  * Create a thread context for a new thread so we can use
247  * setcontext/getcontext/swapcontext to swap it out.
248  * @return 0 on success; otherwise, non-zero error condition
249  */
250 int Thread::create_context()
251 {
252         int ret;
253
254         ret = getcontext(&context);
255         if (ret)
256                 return ret;
257
258         /* Initialize new managed context */
259         stack = stack_allocate(STACK_SIZE);
260         context.uc_stack.ss_sp = stack;
261         context.uc_stack.ss_size = STACK_SIZE;
262         context.uc_stack.ss_flags = 0;
263         context.uc_link = model->get_system_context();
264 #ifdef TLS
265         if (model != NULL)
266                 makecontext(&context, setup_context, 0);
267         else
268                 makecontext(&context, main_thread_startup, 0);
269 #else
270         makecontext(&context, thread_startup, 0);
271 #endif
272
273         return 0;
274 }
275
276 /**
277  * Swaps the current context to another thread of execution. This form switches
278  * from a user Thread to a system context.
279  * @param t Thread representing the currently-running thread. The current
280  * context is saved here.
281  * @param ctxt Context to which we will swap. Must hold a valid system context.
282  * @return Does not return, unless we return to Thread t's context. See
283  * swapcontext(3) (returns 0 for success, -1 for failure).
284  */
285 int Thread::swap(Thread *t, ucontext_t *ctxt)
286 {
287         t->set_state(THREAD_READY);
288 #ifdef TLS
289         set_tls_addr((uintptr_t)model->getInitThread()->tls);
290 #endif
291         return model_swapcontext(&t->context, ctxt);
292 }
293
294 /**
295  * Swaps the current context to another thread of execution. This form switches
296  * from a system context to a user Thread.
297  * @param ctxt System context variable to which to save the current context.
298  * @param t Thread to which we will swap. Must hold a valid user context.
299  * @return Does not return, unless we return to the system context (ctxt). See
300  * swapcontext(3) (returns 0 for success, -1 for failure).
301  */
302 int Thread::swap(ucontext_t *ctxt, Thread *t)
303 {
304         t->set_state(THREAD_RUNNING);
305 #ifdef TLS
306         if (t->tls != NULL)
307                 set_tls_addr((uintptr_t)t->tls);
308 #endif
309         return model_swapcontext(ctxt, &t->context);
310 }
311
312
313 /** Terminate a thread and free its stack. */
314 void Thread::complete()
315 {
316         ASSERT(!is_complete());
317         DEBUG("completed thread %d\n", id_to_int(get_id()));
318         state = THREAD_COMPLETED;
319         if (stack)
320                 stack_free(stack);
321 #ifdef TLS
322         if (this != model->getInitThread()) {
323                 modellock = 1;
324                 real_pthread_mutex_unlock(&mutex2);
325                 real_pthread_join(thread, NULL);
326                 modellock = 0;
327         }
328 #endif
329 }
330
331 /**
332  * @brief Construct a new model-checker Thread
333  *
334  * A model-checker Thread is used for accounting purposes only. It will never
335  * have its own stack, and it should never be inserted into the Scheduler.
336  *
337  * @param tid The thread ID to assign
338  */
339 Thread::Thread(thread_id_t tid) :
340         parent(NULL),
341         creation(NULL),
342         pending(NULL),
343         start_routine(NULL),
344         arg(NULL),
345         stack(NULL),
346 #ifdef TLS
347         tls(NULL),
348 #endif
349         user_thread(NULL),
350         id(tid),
351         state(THREAD_READY),    /* Thread is always ready? */
352         last_action_val(0),
353         model_thread(true)
354 {
355         memset(&context, 0, sizeof(context));
356 }
357
358 /**
359  * Construct a new thread.
360  * @param t The thread identifier of the newly created thread.
361  * @param func The function that the thread will call.
362  * @param a The parameter to pass to this function.
363  */
364 Thread::Thread(thread_id_t tid, thrd_t *t, void (*func)(void *), void *a, Thread *parent) :
365         parent(parent),
366         creation(NULL),
367         pending(NULL),
368         start_routine(func),
369         pstart_routine(NULL),
370         arg(a),
371 #ifdef TLS
372         tls(NULL),
373 #endif
374         user_thread(t),
375         id(tid),
376         state(THREAD_CREATED),
377         last_action_val(VALUE_NONE),
378         model_thread(false)
379 {
380         int ret;
381
382         /* Initialize state */
383         ret = create_context();
384         if (ret)
385                 model_print("Error in create_context\n");
386
387         user_thread->priv = this;       // WL
388 }
389
390 /**
391  * Construct a new thread for pthread.
392  * @param t The thread identifier of the newly created thread.
393  * @param func The function that the thread will call.
394  * @param a The parameter to pass to this function.
395  */
396 Thread::Thread(thread_id_t tid, thrd_t *t, void *(*func)(void *), void *a, Thread *parent) :
397         parent(parent),
398         creation(NULL),
399         pending(NULL),
400         start_routine(NULL),
401         pstart_routine(func),
402         arg(a),
403 #ifdef TLS
404         tls(NULL),
405 #endif
406         user_thread(t),
407         id(tid),
408         state(THREAD_CREATED),
409         last_action_val(VALUE_NONE),
410         model_thread(false)
411 {
412         int ret;
413
414         /* Initialize state */
415         ret = create_context();
416         if (ret)
417                 model_print("Error in create_context\n");
418 }
419
420
421 /** Destructor */
422 Thread::~Thread()
423 {
424         if (!is_complete())
425                 complete();
426 }
427
428 /** @return The thread_id_t corresponding to this Thread object. */
429 thread_id_t Thread::get_id() const
430 {
431         return id;
432 }
433
434 /**
435  * Set a thread's THREAD_* state (@see thread_state)
436  * @param s The state to enter
437  */
438 void Thread::set_state(thread_state s)
439 {
440         ASSERT(s == THREAD_COMPLETED || state != THREAD_COMPLETED);
441         state = s;
442 }
443
444 /**
445  * Get the Thread that this Thread is immediately waiting on
446  * @return The thread we are waiting on, if any; otherwise NULL
447  */
448 Thread * Thread::waiting_on() const
449 {
450         if (!pending)
451                 return NULL;
452
453         if (pending->get_type() == THREAD_JOIN)
454                 return pending->get_thread_operand();
455         else if (pending->get_type() == PTHREAD_JOIN)
456                 return pending->get_thread_operand();
457         else if (pending->is_lock())
458                 return (Thread *)pending->get_mutex()->get_state()->locked;
459         return NULL;
460 }
461
462 /**
463  * Check if this Thread is waiting (blocking) on a given Thread, directly or
464  * indirectly (via a chain of waiting threads)
465  *
466  * @param t The Thread on which we may be waiting
467  * @return True if we are waiting on Thread t; false otherwise
468  */
469 bool Thread::is_waiting_on(const Thread *t) const
470 {
471         Thread *wait;
472         for (wait = waiting_on();wait != NULL;wait = wait->waiting_on())
473                 if (wait == t)
474                         return true;
475         return false;
476 }