2 * @brief Thread functions.
10 #include "threads-model.h"
13 /* global "model" object */
15 #include "execution.h"
18 uintptr_t get_tls_addr() {
20 asm ("mov %%fs:0, %0" : "=r" (addr));
24 #include <asm/prctl.h>
25 #include <sys/prctl.h>
27 int arch_prctl(int code, unsigned long addr);
29 static void set_tls_addr(uintptr_t addr) {
30 arch_prctl(ARCH_SET_FS, addr);
31 asm ("mov %0, %%fs:0" : : "r" (addr) : "memory");
35 /** Allocate a stack for a new thread. */
36 static void * stack_allocate(size_t size)
38 return Thread_malloc(size);
41 /** Free a stack for a terminated thread. */
42 static void stack_free(void *stack)
48 * @brief Get the current Thread
50 * Must be called from a user context
52 * @return The currently executing thread
54 Thread * thread_current(void)
57 return model->get_current_thread();
61 * Provides a startup wrapper for each thread, allowing some initial
62 * model-checking data to be recorded. This method also gets around makecontext
63 * not being 64-bit clean
67 Thread * curr_thread = thread_current();
69 /* Add dummy "start" action, just to create a first clock vector */
70 model->switch_to_master(new ModelAction(THREAD_START, std::memory_order_seq_cst, curr_thread));
73 if (curr_thread->tls == NULL) {
74 uintptr_t tlssize = model->get_execution()->getTLSSize();
75 uintptr_t thddesc = model->get_execution()->getThdDescSize();
76 curr_thread->tls = (char*) Thread_malloc(tlssize);
77 memcpy(curr_thread->tls, model->get_execution()->getTLSBase(), tlssize);
78 curr_thread->tls += tlssize - thddesc;
79 set_tls_addr((uintptr_t)curr_thread->tls);
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);
91 /* Finish thread properly */
92 model->switch_to_master(new ModelAction(THREAD_FINISH, std::memory_order_seq_cst, curr_thread));
96 * Create a thread context for a new thread so we can use
97 * setcontext/getcontext/swapcontext to swap it out.
98 * @return 0 on success; otherwise, non-zero error condition
100 int Thread::create_context()
104 ret = getcontext(&context);
108 /* Initialize new managed context */
109 stack = stack_allocate(STACK_SIZE);
110 context.uc_stack.ss_sp = stack;
111 context.uc_stack.ss_size = STACK_SIZE;
112 context.uc_stack.ss_flags = 0;
113 context.uc_link = model->get_system_context();
114 makecontext(&context, thread_startup, 0);
120 * Swaps the current context to another thread of execution. This form switches
121 * from a user Thread to a system context.
122 * @param t Thread representing the currently-running thread. The current
123 * context is saved here.
124 * @param ctxt Context to which we will swap. Must hold a valid system context.
125 * @return Does not return, unless we return to Thread t's context. See
126 * swapcontext(3) (returns 0 for success, -1 for failure).
128 int Thread::swap(Thread *t, ucontext_t *ctxt)
130 t->set_state(THREAD_READY);
132 set_tls_addr((uintptr_t)model->getInitThread()->tls);
134 return model_swapcontext(&t->context, ctxt);
138 * Swaps the current context to another thread of execution. This form switches
139 * from a system context to a user Thread.
140 * @param ctxt System context variable to which to save the current context.
141 * @param t Thread to which we will swap. Must hold a valid user context.
142 * @return Does not return, unless we return to the system context (ctxt). See
143 * swapcontext(3) (returns 0 for success, -1 for failure).
145 int Thread::swap(ucontext_t *ctxt, Thread *t)
147 t->set_state(THREAD_RUNNING);
150 set_tls_addr((uintptr_t)t->tls);
152 return model_swapcontext(ctxt, &t->context);
156 /** Terminate a thread and free its stack. */
157 void Thread::complete()
159 ASSERT(!is_complete());
160 DEBUG("completed thread %d\n", id_to_int(get_id()));
161 state = THREAD_COMPLETED;
165 if (tls && get_id() != 1)
166 tls += model->get_execution()->getTLSSize() - model->get_execution()->getThdDescSize();
172 * @brief Construct a new model-checker Thread
174 * A model-checker Thread is used for accounting purposes only. It will never
175 * have its own stack, and it should never be inserted into the Scheduler.
177 * @param tid The thread ID to assign
179 Thread::Thread(thread_id_t tid) :
191 state(THREAD_READY), /* Thread is always ready? */
195 memset(&context, 0, sizeof(context));
199 * Construct a new thread.
200 * @param t The thread identifier of the newly created thread.
201 * @param func The function that the thread will call.
202 * @param a The parameter to pass to this function.
204 Thread::Thread(thread_id_t tid, thrd_t *t, void (*func)(void *), void *a, Thread *parent) :
209 pstart_routine(NULL),
216 state(THREAD_CREATED),
217 last_action_val(VALUE_NONE),
222 /* Initialize state */
223 ret = create_context();
225 model_print("Error in create_context\n");
227 user_thread->priv = this; // WL
231 * Construct a new thread for pthread.
232 * @param t The thread identifier of the newly created thread.
233 * @param func The function that the thread will call.
234 * @param a The parameter to pass to this function.
236 Thread::Thread(thread_id_t tid, thrd_t *t, void *(*func)(void *), void *a, Thread *parent) :
241 pstart_routine(func),
248 state(THREAD_CREATED),
249 last_action_val(VALUE_NONE),
254 /* Initialize state */
255 ret = create_context();
257 model_print("Error in create_context\n");
268 /** @return The thread_id_t corresponding to this Thread object. */
269 thread_id_t Thread::get_id() const
275 * Set a thread's THREAD_* state (@see thread_state)
276 * @param s The state to enter
278 void Thread::set_state(thread_state s)
280 ASSERT(s == THREAD_COMPLETED || state != THREAD_COMPLETED);
285 * Get the Thread that this Thread is immediately waiting on
286 * @return The thread we are waiting on, if any; otherwise NULL
288 Thread * Thread::waiting_on() const
293 if (pending->get_type() == THREAD_JOIN)
294 return pending->get_thread_operand();
295 else if (pending->get_type() == PTHREAD_JOIN)
296 return pending->get_thread_operand();
297 else if (pending->is_lock())
298 return (Thread *)pending->get_mutex()->get_state()->locked;
303 * Check if this Thread is waiting (blocking) on a given Thread, directly or
304 * indirectly (via a chain of waiting threads)
306 * @param t The Thread on which we may be waiting
307 * @return True if we are waiting on Thread t; false otherwise
309 bool Thread::is_waiting_on(const Thread *t) const
312 for (wait = waiting_on();wait != NULL;wait = wait->waiting_on())