2 * @brief Thread functions.
10 #include "threads-model.h"
13 /* global "model" object */
15 #include "execution.h"
17 #include "clockvector.h"
22 uintptr_t get_tls_addr() {
24 asm ("mov %%fs:0, %0" : "=r" (addr));
28 #include <asm/prctl.h>
29 #include <sys/prctl.h>
31 int arch_prctl(int code, unsigned long addr);
33 static void set_tls_addr(uintptr_t addr) {
34 arch_prctl(ARCH_SET_FS, addr);
35 asm ("mov %0, %%fs:0" : : "r" (addr) : "memory");
39 /** Allocate a stack for a new thread. */
40 static void * stack_allocate(size_t size)
42 return Thread_malloc(size);
45 /** Free a stack for a terminated thread. */
46 static void stack_free(void *stack)
52 * @brief Get the current Thread
54 * Must be called from a user context
56 * @return The currently executing thread
58 Thread * thread_current(void)
61 return model->get_current_thread();
65 * @brief Get the current Thread id
67 * Must be called from a user context
69 * @return The id of the currently executing thread
71 thread_id_t thread_current_id(void)
74 return model->get_current_thread_id();
78 model->switch_thread(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, thread_current()));
81 void initMainThread() {
83 Thread * curr_thread = thread_current();
84 model->switch_thread(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
88 * Provides a startup wrapper for each thread, allowing some initial
89 * model-checking data to be recorded. This method also gets around makecontext
90 * not being 64-bit clean
94 Thread * curr_thread = thread_current();
96 /* Add dummy "start" action, just to create a first clock vector */
97 model->switch_thread(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
100 /* Call the actual thread function */
101 if (curr_thread->start_routine != NULL) {
102 curr_thread->start_routine(curr_thread->arg);
103 } else if (curr_thread->pstart_routine != NULL) {
104 // set pthread return value
105 void *retval = curr_thread->pstart_routine(curr_thread->arg);
106 curr_thread->set_pthread_return(retval);
109 /* Finish thread properly */
110 model->switch_thread(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, curr_thread));
115 static int (*real_epoll_wait_p)(int epfd, struct epoll_event *events, int maxevents, int timeout) = NULL;
117 int real_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) {
118 return real_epoll_wait_p(epfd, events, maxevents, timeout);
121 static int (*pthread_mutex_init_p)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) = NULL;
123 int real_pthread_mutex_init(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) {
124 return pthread_mutex_init_p(__mutex, __mutexattr);
127 static int (*pthread_mutex_lock_p) (pthread_mutex_t *__mutex) = NULL;
129 int real_pthread_mutex_lock (pthread_mutex_t *__mutex) {
130 return pthread_mutex_lock_p(__mutex);
133 static int (*pthread_mutex_unlock_p) (pthread_mutex_t *__mutex) = NULL;
135 int real_pthread_mutex_unlock (pthread_mutex_t *__mutex) {
136 return pthread_mutex_unlock_p(__mutex);
139 static int (*pthread_create_p) (pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void * __restrict) = NULL;
141 int real_pthread_create (pthread_t *__restrict __newthread, const pthread_attr_t *__restrict __attr, void *(*__start_routine)(void *), void *__restrict __arg) {
142 return pthread_create_p(__newthread, __attr, __start_routine, __arg);
145 static int (*pthread_join_p) (pthread_t __th, void ** __thread_return) = NULL;
147 int real_pthread_join (pthread_t __th, void ** __thread_return) {
148 return pthread_join_p(__th, __thread_return);
151 static void (*pthread_exit_p)(void *) __attribute__((noreturn))= NULL;
153 void real_pthread_exit (void * value_ptr) {
154 pthread_exit_p(value_ptr);
157 void real_init_all() {
159 if (!real_epoll_wait_p) {
160 real_epoll_wait_p = (int (*)(int epfd, struct epoll_event *events, int maxevents, int timeout))dlsym(RTLD_NEXT, "epoll_wait");
161 if ((error = dlerror()) != NULL) {
162 fputs(error, stderr);
166 if (!pthread_mutex_init_p) {
167 pthread_mutex_init_p = (int (*)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr))dlsym(RTLD_NEXT, "pthread_mutex_init");
168 if ((error = dlerror()) != NULL) {
169 fputs(error, stderr);
173 if (!pthread_mutex_lock_p) {
174 pthread_mutex_lock_p = (int (*)(pthread_mutex_t *__mutex))dlsym(RTLD_NEXT, "pthread_mutex_lock");
175 if ((error = dlerror()) != NULL) {
176 fputs(error, stderr);
180 if (!pthread_mutex_unlock_p) {
181 pthread_mutex_unlock_p = (int (*)(pthread_mutex_t *__mutex))dlsym(RTLD_NEXT, "pthread_mutex_unlock");
182 if ((error = dlerror()) != NULL) {
183 fputs(error, stderr);
187 if (!pthread_create_p) {
188 pthread_create_p = (int (*)(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict))dlsym(RTLD_NEXT, "pthread_create");
189 if ((error = dlerror()) != NULL) {
190 fputs(error, stderr);
194 if (!pthread_join_p) {
195 pthread_join_p = (int (*)(pthread_t __th, void ** __thread_return))dlsym(RTLD_NEXT, "pthread_join");
196 if ((error = dlerror()) != NULL) {
197 fputs(error, stderr);
202 if (!pthread_exit_p) {
203 *((void (**)(void *)) &pthread_exit_p) = (void (*)(void *))dlsym(RTLD_NEXT, "pthread_exit");
204 if ((error = dlerror()) != NULL) {
205 fputs(error, stderr);
212 void finalize_helper_thread() {
213 Thread * curr_thread = thread_current();
214 real_pthread_mutex_lock(&curr_thread->mutex);
215 curr_thread->tls = (char *) get_tls_addr();
216 real_pthread_mutex_unlock(&curr_thread->mutex);
217 //Wait in the kernel until it is time for us to finish
218 real_pthread_mutex_lock(&curr_thread->mutex2);
219 real_pthread_mutex_unlock(&curr_thread->mutex2);
220 //return to helper thread function
221 setcontext(&curr_thread->context);
224 void * helper_thread(void * ptr) {
225 Thread * curr_thread = thread_current();
227 //build a context for this real thread so we can take it's context
228 int ret = getcontext(&curr_thread->helpercontext);
232 if (pthread_setspecific(model->get_execution()->getPthreadKey(), (const void *)4)) {
233 printf("Destructor setup failed\n");
238 /* Initialize new managed context */
239 curr_thread->helper_stack = stack_allocate(STACK_SIZE);
240 curr_thread->helpercontext.uc_stack.ss_sp = curr_thread->helper_stack;
241 curr_thread->helpercontext.uc_stack.ss_size = STACK_SIZE;
242 curr_thread->helpercontext.uc_stack.ss_flags = 0;
243 curr_thread->helpercontext.uc_link = NULL;
244 makecontext(&curr_thread->helpercontext, finalize_helper_thread, 0);
246 model_swapcontext(&curr_thread->context, &curr_thread->helpercontext);
249 //start the real thread
256 void tlsdestructor(void *v) {
257 uintptr_t count = (uintptr_t) v;
259 if (pthread_setspecific(model->get_execution()->getPthreadKey(), (const void *)(count - 1))) {
260 printf("Destructor setup failed\n");
265 /* Finish thread properly */
266 model->switch_thread(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, thread_current()));
270 void setup_context() {
271 Thread * curr_thread = thread_current();
273 /* Add dummy "start" action, just to create a first clock vector */
274 model->switch_thread(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
278 /* Initialize our lock */
279 real_pthread_mutex_init(&curr_thread->mutex, NULL);
280 real_pthread_mutex_init(&curr_thread->mutex2, NULL);
281 real_pthread_mutex_lock(&curr_thread->mutex2);
283 /* Create the real thread */
284 real_pthread_create(&curr_thread->thread, NULL, helper_thread, NULL);
287 real_pthread_mutex_lock(&curr_thread->mutex);
288 if (curr_thread->tls != NULL)
290 real_pthread_mutex_unlock(&curr_thread->mutex);
293 set_tls_addr((uintptr_t)curr_thread->tls);
294 setcontext(&curr_thread->context);
299 * Create a thread context for a new thread so we can use
300 * setcontext/getcontext/swapcontext to swap it out.
301 * @return 0 on success; otherwise, non-zero error condition
303 int Thread::create_context()
307 ret = getcontext(&context);
311 /* Initialize new managed context */
312 stack = stack_allocate(STACK_SIZE);
313 context.uc_stack.ss_sp = stack;
314 context.uc_stack.ss_size = STACK_SIZE;
315 context.uc_stack.ss_flags = 0;
316 context.uc_link = NULL;
318 makecontext(&context, setup_context, 0);
320 makecontext(&context, thread_startup, 0);
327 * Swaps the current context to another thread of execution. This form switches
328 * from a user Thread to a system context.
329 * @param t Thread representing the currently-running thread. The current
330 * context is saved here.
331 * @param ctxt Context to which we will swap. Must hold a valid system context.
332 * @return Does not return, unless we return to Thread t's context. See
333 * swapcontext(3) (returns 0 for success, -1 for failure).
335 int Thread::swap(Thread *t, ucontext_t *ctxt)
337 t->set_state(THREAD_READY);
339 set_tls_addr((uintptr_t)model->getInitThread()->tls);
341 return model_swapcontext(&t->context, ctxt);
345 * Swaps the current context to another thread of execution. This form switches
346 * from a system context to a user Thread.
347 * @param ctxt System context variable to which to save the current context.
348 * @param t Thread to which we will swap. Must hold a valid user context.
349 * @return Does not return, unless we return to the system context (ctxt). See
350 * swapcontext(3) (returns 0 for success, -1 for failure).
352 int Thread::swap(ucontext_t *ctxt, Thread *t)
354 t->set_state(THREAD_RUNNING);
357 set_tls_addr((uintptr_t)t->tls);
359 return model_swapcontext(ctxt, &t->context);
362 int Thread::swap(Thread *t, Thread *t2)
364 t2->set_state(THREAD_RUNNING);
370 set_tls_addr((uintptr_t)t2->tls);
372 return model_swapcontext(&t->context, &t2->context);
375 /** Terminate a thread. */
376 void Thread::complete()
378 ASSERT(!is_complete());
379 DEBUG("completed thread %d\n", id_to_int(get_id()));
380 state = THREAD_COMPLETED;
383 void Thread::freeResources() {
387 if (this != model->getInitThread()) {
388 real_pthread_mutex_unlock(&mutex2);
389 real_pthread_join(thread, NULL);
390 stack_free(helper_stack);
393 state = THREAD_FREED;
397 * @brief Construct a new model-checker Thread
399 * A model-checker Thread is used for accounting purposes only. It will never
400 * have its own stack, and it should never be inserted into the Scheduler.
402 * @param tid The thread ID to assign
404 Thread::Thread(thread_id_t tid) :
406 acq_fence_cv(new ClockVector()),
418 state(THREAD_READY), /* Thread is always ready? */
422 // real_memset is not defined when
423 // the model thread is constructed
424 memset(&context, 0, sizeof(context));
428 * Construct a new thread.
429 * @param t The thread identifier of the newly created thread.
430 * @param func The function that the thread will call.
431 * @param a The parameter to pass to this function.
433 Thread::Thread(thread_id_t tid, thrd_t *t, void (*func)(void *), void *a, Thread *parent) :
435 acq_fence_cv(new ClockVector()),
440 pstart_routine(NULL),
447 state(THREAD_CREATED),
448 last_action_val(VALUE_NONE),
453 /* Initialize state */
454 ret = create_context();
456 model_print("Error in create_context\n");
458 user_thread->priv = this; // WL
462 * Construct a new thread for pthread.
463 * @param t The thread identifier of the newly created thread.
464 * @param func The function that the thread will call.
465 * @param a The parameter to pass to this function.
467 Thread::Thread(thread_id_t tid, thrd_t *t, void *(*func)(void *), void *a, Thread *parent) :
469 acq_fence_cv(new ClockVector()),
474 pstart_routine(func),
481 state(THREAD_CREATED),
482 last_action_val(VALUE_NONE),
487 /* Initialize state */
488 ret = create_context();
490 model_print("Error in create_context\n");
503 /** @return The thread_id_t corresponding to this Thread object. */
504 thread_id_t Thread::get_id() const
510 * Set a thread's THREAD_* state (@see thread_state)
511 * @param s The state to enter
513 void Thread::set_state(thread_state s)
515 ASSERT(s == THREAD_COMPLETED || state != THREAD_COMPLETED);
520 * Get the Thread that this Thread is immediately waiting on
521 * @return The thread we are waiting on, if any; otherwise NULL
523 Thread * Thread::waiting_on() const
528 switch (pending->get_type()) {
531 return pending->get_thread_operand();
533 return (Thread *)pending->get_mutex()->get_state()->locked;
540 * Check if this Thread is waiting (blocking) on a given Thread, directly or
541 * indirectly (via a chain of waiting threads)
543 * @param t The Thread on which we may be waiting
544 * @return True if we are waiting on Thread t; false otherwise
546 bool Thread::is_waiting_on(const Thread *t) const
550 // One thread relocks a recursive mutex
551 if (waiting_on() == t && pending->is_lock()) {
552 int mutex_type = pending->get_mutex()->get_state()->type;
553 if (mutex_type == PTHREAD_MUTEX_RECURSIVE)
557 for (wait = waiting_on();wait != NULL;wait = wait->waiting_on())