demote 'system_thread' to just 'system_context'
[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         /* start_routine == NULL means this is our initial context */
37         if (!start_routine)
38                 return 0;
39
40         /* Initialize new managed context */
41         stack = stack_allocate(STACK_SIZE);
42         context.uc_stack.ss_sp = stack;
43         context.uc_stack.ss_size = STACK_SIZE;
44         context.uc_stack.ss_flags = 0;
45         context.uc_link = model->get_system_context();
46         makecontext(&context, start_routine, 1, arg);
47
48         return 0;
49 }
50
51 int Thread::swap(Thread *t, ucontext_t *ctxt)
52 {
53         return swapcontext(&t->context, ctxt);
54 }
55
56 int Thread::swap(ucontext_t *ctxt, Thread *t)
57 {
58         return swapcontext(ctxt, &t->context);
59 }
60
61 void Thread::complete()
62 {
63         if (state != THREAD_COMPLETED) {
64                 DEBUG("completed thread %d\n", get_id());
65                 state = THREAD_COMPLETED;
66                 if (stack)
67                         stack_free(stack);
68         }
69 }
70
71 void * Thread::operator new(size_t size) {
72         return userMalloc(size);
73 }
74
75 void Thread::operator delete(void *ptr) {
76         userFree(ptr);
77 }
78
79 Thread::Thread(thrd_t *t, void (*func)(), void *a) {
80         int ret;
81
82         user_thread = t;
83         start_routine = func;
84         arg = a;
85
86         /* Initialize state */
87         ret = create_context();
88         if (ret)
89                 printf("Error in create_context\n");
90
91         state = THREAD_CREATED;
92         id = model->get_next_id();
93         *user_thread = id;
94 }
95
96 Thread::Thread(thrd_t *t) {
97         /* system thread */
98         user_thread = t;
99         start_routine = NULL;
100         arg = NULL;
101
102         create_context();
103         stack = NULL;
104         state = THREAD_CREATED;
105         id = model->get_next_id();
106         *user_thread = id;
107         model->set_system_context(&context);
108 }
109
110 Thread::~Thread()
111 {
112         complete();
113         model->remove_thread(this);
114 }
115
116 thread_id_t Thread::get_id()
117 {
118         return id;
119 }
120
121 /*
122  * Return 1 if found next thread, 0 otherwise
123  */
124 static int thread_system_next(void)
125 {
126         Thread *curr, *next;
127
128         curr = thread_current();
129         if (curr) {
130                 if (curr->get_state() == THREAD_READY) {
131                         model->check_current_action();
132                         model->scheduler->add_thread(curr);
133                 } else if (curr->get_state() == THREAD_RUNNING)
134                         /* Stopped while running; i.e., completed */
135                         curr->complete();
136                 else
137                         DEBUG("ERROR: current thread in unexpected state??\n");
138         }
139         next = model->scheduler->next_thread();
140         if (next)
141                 next->set_state(THREAD_RUNNING);
142         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
143         if (!next)
144                 return 1;
145         return Thread::swap(model->get_system_context(), next);
146 }
147
148 static void thread_wait_finish(void)
149 {
150
151         DBG();
152
153         while (!thread_system_next());
154 }
155
156 /*
157  * Main system function
158  */
159 int main()
160 {
161         thrd_t user_thread;
162         ucontext_t main_context;
163
164         model = new ModelChecker();
165
166         if (getcontext(&main_context))
167                 return 1;
168
169         model->set_system_context(&main_context);
170
171         do {
172                 /* Start user program */
173                 thrd_create(&user_thread, &user_main, NULL);
174
175                 /* Wait for all threads to complete */
176                 thread_wait_finish();
177         } while (model->next_execution());
178
179         delete model;
180
181         DEBUG("Exiting\n");
182         return 0;
183 }