major rewrite - 'struct thread' replaced with internal 'class Thread'
[model-checker.git] / libthreads.cc
1 #include <string.h>
2 #include <stdlib.h>
3
4 #include "libthreads.h"
5 #include "schedule.h"
6 #include "common.h"
7 #include "threads_internal.h"
8
9 /* global "model" object */
10 #include "model.h"
11
12 #define STACK_SIZE (1024 * 1024)
13
14 static void *stack_allocate(size_t size)
15 {
16         return malloc(size);
17 }
18
19 static void stack_free(void *stack)
20 {
21         free(stack);
22 }
23
24 Thread *thread_current(void)
25 {
26         return model->scheduler->get_current_thread();
27 }
28
29 int Thread::create_context()
30 {
31         int ret;
32
33         ret = getcontext(&context);
34         if (ret)
35                 return ret;
36
37         /* start_routine == NULL means this is our initial context */
38         if (!start_routine)
39                 return 0;
40
41         /* Initialize new managed context */
42         stack = stack_allocate(STACK_SIZE);
43         context.uc_stack.ss_sp = stack;
44         context.uc_stack.ss_size = STACK_SIZE;
45         context.uc_stack.ss_flags = 0;
46         context.uc_link = &model->system_thread->context;
47         makecontext(&context, start_routine, 1, arg);
48
49         return 0;
50 }
51
52 int Thread::swap(Thread *t)
53 {
54         return swapcontext(&this->context, &t->context);
55 }
56
57 void Thread::dispose()
58 {
59         DEBUG("completed thread %d\n", thread_current()->get_id());
60         state = THREAD_COMPLETED;
61         stack_free(stack);
62 }
63
64 /*
65  * Return 1 if found next thread, 0 otherwise
66  */
67 static int thread_system_next(void)
68 {
69         Thread *curr, *next;
70
71         curr = thread_current();
72         model->check_current_action();
73         if (curr) {
74                 if (curr->get_state() == THREAD_READY)
75                         model->scheduler->add_thread(curr);
76                 else if (curr->get_state() == THREAD_RUNNING)
77                         /* Stopped while running; i.e., completed */
78                         curr->dispose();
79                 else
80                         DEBUG("ERROR: current thread in unexpected state??\n");
81         }
82         next = model->scheduler->next_thread();
83         if (next)
84                 next->set_state(THREAD_RUNNING);
85         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
86         if (!next)
87                 return 1;
88         return model->system_thread->swap(next);
89 }
90
91 static void thread_wait_finish(void)
92 {
93
94         DBG();
95
96         while (!thread_system_next());
97 }
98
99 int Thread::switch_to_master(ModelAction *act)
100 {
101         Thread *next;
102
103         DBG();
104         model->set_current_action(act);
105         state = THREAD_READY;
106         next = model->system_thread;
107         return swap(next);
108 }
109
110 Thread::Thread(thrd_t *t, void (*func)(), void *a) {
111         int ret;
112
113         user_thread = t;
114         start_routine = func;
115         arg = a;
116
117         /* Initialize state */
118         ret = create_context();
119         if (ret)
120                 printf("Error in create_context\n");
121
122         state = THREAD_CREATED;
123         model->assign_id(this);
124         model->scheduler->add_thread(this);
125 }
126
127 Thread::Thread(thrd_t *t) {
128         /* system thread */
129         user_thread = t;
130         state = THREAD_CREATED;
131         model->assign_id(this);
132         create_context();
133         model->add_system_thread(this);
134 }
135
136 static thread_id_t thrd_to_id(thrd_t t)
137 {
138         return t;
139 }
140
141 thread_id_t Thread::get_id()
142 {
143         return thrd_to_id(*user_thread);
144 }
145
146 /*
147  * User program API functions
148  */
149 int thrd_create(thrd_t *t, void (*start_routine)(), void *arg)
150 {
151         int ret;
152         DBG();
153         ret = model->add_thread(new Thread(t, start_routine, arg));
154         DEBUG("create thread %d\n", thrd_to_id(*t));
155         return ret;
156 }
157
158 int thrd_join(thrd_t t)
159 {
160         int ret = 0;
161         Thread *th = model->get_thread(thrd_to_id(t));
162         while (th->get_state() != THREAD_COMPLETED && !ret)
163                 /* seq_cst is just a 'don't care' parameter */
164                 ret = thread_current()->switch_to_master(new ModelAction(THREAD_JOIN, memory_order_seq_cst, NULL, VALUE_NONE));
165         return ret;
166 }
167
168 int thrd_yield(void)
169 {
170         /* seq_cst is just a 'don't care' parameter */
171         return thread_current()->switch_to_master(new ModelAction(THREAD_YIELD, memory_order_seq_cst, NULL, VALUE_NONE));
172 }
173
174 thrd_t thrd_current(void)
175 {
176         return thread_current()->get_thrd_t();
177 }
178
179 /*
180  * Main system function
181  */
182 int main()
183 {
184         thrd_t user_thread, main_thread;
185         Thread *th;
186
187         model = new ModelChecker();
188
189         th = new Thread(&main_thread);
190
191         /* Start user program */
192         thrd_create(&user_thread, &user_main, NULL);
193
194         /* Wait for all threads to complete */
195         thread_wait_finish();
196
197         model->print_trace();
198         delete th;
199         delete model;
200
201         DEBUG("Exiting\n");
202         return 0;
203 }