Check in a README file
[satcheck.git] / threads.cc
1 /*      Copyright (c) 2015 Regents of the University of California
2  *
3  *      Author: Brian Demsky <bdemsky@uci.edu>
4  *
5  *      This program is free software; you can redistribute it and/or
6  *      modify it under the terms of the GNU General Public License
7  *      version 2 as published by the Free Software Foundation.
8  */
9
10 /** @file threads.cc
11  *  @brief Thread functions.
12  */
13
14 #include <string.h>
15
16 #include <threads.h>
17 #include <mutex>
18 #include "common.h"
19 #include "threads-model.h"
20 #include "mcschedule.h"
21 /* global "model" object */
22 #include "model.h"
23
24 /** Allocate a stack for a new thread. */
25 static void * stack_allocate(size_t size)
26 {
27         return snapshot_malloc(size);
28 }
29
30 /** Free a stack for a terminated thread. */
31 static void stack_free(void *stack)
32 {
33         snapshot_free(stack);
34 }
35
36 /**
37  * @brief Get the current Thread
38  *
39  * Must be called from a user context
40  *
41  * @return The currently executing thread
42  */
43 Thread * thread_current(void)
44 {
45         ASSERT(model);
46         return model->get_execution()->get_current_thread();
47 }
48
49 /**
50  * Provides a startup wrapper for each thread, allowing some initial
51  * model-checking data to be recorded. This method also gets around makecontext
52  * not being 64-bit clean
53  */
54 void thread_startup()
55 {
56         Thread * curr_thread = thread_current();
57         model->get_execution()->threadStart(curr_thread->getParentRecord());
58         /* Call the actual thread function */
59         curr_thread->start_routine(curr_thread->arg);
60         model->get_execution()->threadFinish();
61 }
62
63 /**
64  * Create a thread context for a new thread so we can use
65  * setcontext/getcontext/swapcontext to swap it out.
66  * @return 0 on success; otherwise, non-zero error condition
67  */
68 int Thread::create_context()
69 {
70         int ret;
71
72         ret = getcontext(&context);
73         if (ret)
74                 return ret;
75
76         /* Initialize new managed context */
77         stack = stack_allocate(STACK_SIZE);
78         context.uc_stack.ss_sp = stack;
79         context.uc_stack.ss_size = STACK_SIZE;
80         context.uc_stack.ss_flags = 0;
81         context.uc_link = model->get_scheduler()->get_system_context();
82         makecontext(&context, thread_startup, 0);
83
84         return 0;
85 }
86
87
88 /** Terminate a thread and free its stack. */
89 void Thread::complete()
90 {
91         ASSERT(!is_complete());
92         DEBUG("completed thread %d\n", id_to_int(get_id()));
93         state = THREAD_COMPLETED;
94 }
95
96 /**
97  * @brief Construct a new model-checker Thread
98  *
99  * A model-checker Thread is used for accounting purposes only. It will never
100  * have its own stack, and it should never be inserted into the Scheduler.
101  *
102  * @param tid The thread ID to assign
103  */
104 Thread::Thread(thread_id_t tid) :
105         parent(NULL),
106         start_routine(NULL),
107         arg(NULL),
108         stack(NULL),
109         user_thread(NULL),
110         waiting(NULL),
111         id(tid),
112         state(THREAD_READY),                    /* Thread is always ready? */
113         model_thread(true)
114 {
115         memset(&context, 0, sizeof(context));
116 }
117
118 /**
119  * Construct a new thread.
120  * @param t The thread identifier of the newly created thread.
121  * @param func The function that the thread will call.
122  * @param a The parameter to pass to this function.
123  */
124 Thread::Thread(thread_id_t tid, thrd_t *t, void (*func)(void *), void *a, Thread *parent, EPRecord *record) :
125         parent(parent),
126         parentrecord(record),
127         start_routine(func),
128         arg(a),
129         user_thread(t),
130         waiting(NULL),
131         id(tid),
132         state(THREAD_CREATED),
133         model_thread(false)
134 {
135         int ret;
136
137         /* Initialize state */
138         ret = create_context();
139         if (ret)
140                 model_print("Error in create_context\n");
141
142         user_thread->priv = this;
143 }
144
145 /** Destructor */
146 Thread::~Thread()
147 {
148         if (!is_complete())
149                 complete();
150         if (stack)
151                 stack_free(stack);
152 }
153
154 /** @return The thread_id_t corresponding to this Thread object. */
155 thread_id_t Thread::get_id() const
156 {
157         return id;
158 }
159
160 /**
161  * Set a thread's THREAD_* state (@see thread_state)
162  * @param s The state to enter
163  */
164 void Thread::set_state(thread_state s)
165 {
166         ASSERT(s == THREAD_COMPLETED || state != THREAD_COMPLETED);
167         state = s;
168 }
169
170 /**
171  * Get the Thread that this Thread is immediately waiting on
172  * @return The thread we are waiting on, if any; otherwise NULL
173  */
174 Thread * Thread::waiting_on()
175 {
176         return waiting;
177 }
178
179 void Thread::set_waiting(Thread *th) {
180         waiting=th;
181 }
182
183 /**
184  * Check if this Thread is waiting (blocking) on a given Thread, directly or
185  * indirectly (via a chain of waiting threads)
186  *
187  * @param t The Thread on which we may be waiting
188  * @return True if we are waiting on Thread t; false otherwise
189  */
190 bool Thread::is_waiting_on(const Thread *t) {
191         Thread *wait;
192         for (wait = waiting_on();wait != NULL;wait = wait->waiting_on())
193                 if (wait == t)
194                         return true;
195         return false;
196 }