threads: add parent info + get_parent() method
[cdsspec-compiler.git] / threads.cc
1 #include <stdlib.h>
2
3 #include "libthreads.h"
4 #include "schedule.h"
5 #include "common.h"
6 #include "threads.h"
7
8 /* global "model" object */
9 #include "model.h"
10
11 #define STACK_SIZE (1024 * 1024)
12
13 static void * stack_allocate(size_t size)
14 {
15         return userMalloc(size);
16 }
17
18 static void stack_free(void *stack)
19 {
20         userFree(stack);
21 }
22
23 Thread * thread_current(void)
24 {
25         return model->scheduler->get_current_thread();
26 }
27
28 int Thread::create_context()
29 {
30         int ret;
31
32         ret = getcontext(&context);
33         if (ret)
34                 return ret;
35
36         /* Initialize new managed context */
37         stack = stack_allocate(STACK_SIZE);
38         context.uc_stack.ss_sp = stack;
39         context.uc_stack.ss_size = STACK_SIZE;
40         context.uc_stack.ss_flags = 0;
41         context.uc_link = model->get_system_context();
42         makecontext(&context, start_routine, 1, arg);
43
44         return 0;
45 }
46
47 int Thread::swap(Thread *t, ucontext_t *ctxt)
48 {
49         return swapcontext(&t->context, ctxt);
50 }
51
52 int Thread::swap(ucontext_t *ctxt, Thread *t)
53 {
54         return swapcontext(ctxt, &t->context);
55 }
56
57 void Thread::complete()
58 {
59         if (state != THREAD_COMPLETED) {
60                 DEBUG("completed thread %d\n", get_id());
61                 state = THREAD_COMPLETED;
62                 if (stack)
63                         stack_free(stack);
64         }
65 }
66
67 void * Thread::operator new(size_t size) {
68         return userMalloc(size);
69 }
70
71 void Thread::operator delete(void *ptr) {
72         userFree(ptr);
73 }
74
75 Thread::Thread(thrd_t *t, void (*func)(), void *a) {
76         int ret;
77
78         user_thread = t;
79         start_routine = func;
80         arg = a;
81
82         /* Initialize state */
83         ret = create_context();
84         if (ret)
85                 printf("Error in create_context\n");
86
87         state = THREAD_CREATED;
88         id = model->get_next_id();
89         *user_thread = id;
90         parent = thread_current();
91 }
92
93 Thread::~Thread()
94 {
95         complete();
96         model->remove_thread(this);
97 }
98
99 thread_id_t Thread::get_id()
100 {
101         return id;
102 }
103
104 /*
105  * Return 1 if found next thread, 0 otherwise
106  */
107 static int thread_system_next(void)
108 {
109         Thread *curr, *next;
110
111         curr = thread_current();
112         if (curr) {
113                 if (curr->get_state() == THREAD_READY) {
114                         model->check_current_action();
115                         model->scheduler->add_thread(curr);
116                 } else if (curr->get_state() == THREAD_RUNNING)
117                         /* Stopped while running; i.e., completed */
118                         curr->complete();
119                 else
120                         ASSERT(false);
121         }
122         next = model->scheduler->next_thread();
123         if (next)
124                 next->set_state(THREAD_RUNNING);
125         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
126         if (!next)
127                 return 1;
128         return Thread::swap(model->get_system_context(), next);
129 }
130
131 static void thread_wait_finish(void)
132 {
133
134         DBG();
135
136         while (!thread_system_next());
137 }
138
139 /*
140  * Main system function
141  */
142 int main()
143 {
144         thrd_t user_thread;
145         ucontext_t main_context;
146
147         model = new ModelChecker();
148
149         if (getcontext(&main_context))
150                 return 1;
151
152         model->set_system_context(&main_context);
153
154         do {
155                 /* Start user program */
156                 model->add_thread(new Thread(&user_thread, &user_main, NULL));
157
158                 /* Wait for all threads to complete */
159                 thread_wait_finish();
160         } while (model->next_execution());
161
162         delete model;
163
164         DEBUG("Exiting\n");
165         return 0;
166 }