thread: remove dead Thread code
[c11tester.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 }
91
92 Thread::~Thread()
93 {
94         complete();
95         model->remove_thread(this);
96 }
97
98 thread_id_t Thread::get_id()
99 {
100         return id;
101 }
102
103 /*
104  * Return 1 if found next thread, 0 otherwise
105  */
106 static int thread_system_next(void)
107 {
108         Thread *curr, *next;
109
110         curr = thread_current();
111         if (curr) {
112                 if (curr->get_state() == THREAD_READY) {
113                         model->check_current_action();
114                         model->scheduler->add_thread(curr);
115                 } else if (curr->get_state() == THREAD_RUNNING)
116                         /* Stopped while running; i.e., completed */
117                         curr->complete();
118                 else
119                         DEBUG("ERROR: current thread in unexpected state??\n");
120         }
121         next = model->scheduler->next_thread();
122         if (next)
123                 next->set_state(THREAD_RUNNING);
124         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
125         if (!next)
126                 return 1;
127         return Thread::swap(model->get_system_context(), next);
128 }
129
130 static void thread_wait_finish(void)
131 {
132
133         DBG();
134
135         while (!thread_system_next());
136 }
137
138 /*
139  * Main system function
140  */
141 int main()
142 {
143         thrd_t user_thread;
144         ucontext_t main_context;
145
146         model = new ModelChecker();
147
148         if (getcontext(&main_context))
149                 return 1;
150
151         model->set_system_context(&main_context);
152
153         do {
154                 /* Start user program */
155                 thrd_create(&user_thread, &user_main, NULL);
156
157                 /* Wait for all threads to complete */
158                 thread_wait_finish();
159         } while (model->next_execution());
160
161         delete model;
162
163         DEBUG("Exiting\n");
164         return 0;
165 }