libthreads: print out trace at end of execution
[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 static int create_context(struct thread *t)
25 {
26         int ret;
27
28         memset(&t->context, 0, sizeof(t->context));
29         ret = getcontext(&t->context);
30         if (ret)
31                 return ret;
32
33         /* t->start_routine == NULL means this is our initial context */
34         if (!t->start_routine)
35                 return 0;
36
37         /* Initialize new managed context */
38         t->stack = stack_allocate(STACK_SIZE);
39         t->context.uc_stack.ss_sp = t->stack;
40         t->context.uc_stack.ss_size = STACK_SIZE;
41         t->context.uc_stack.ss_flags = 0;
42         t->context.uc_link = &model->system_thread->context;
43         makecontext(&t->context, t->start_routine, 1, t->arg);
44
45         return 0;
46 }
47
48 static int create_initial_thread(struct thread *t)
49 {
50         memset(t, 0, sizeof(*t));
51         model->assign_id(t);
52         return create_context(t);
53 }
54
55 static int thread_swap(struct thread *t1, struct thread *t2)
56 {
57         return swapcontext(&t1->context, &t2->context);
58 }
59
60 static void thread_dispose(struct thread *t)
61 {
62         DEBUG("completed thread %d\n", thread_current()->id);
63         t->state = THREAD_COMPLETED;
64         stack_free(t->stack);
65 }
66
67 /*
68  * Return 1 if found next thread, 0 otherwise
69  */
70 static int thread_system_next(void)
71 {
72         struct thread *curr, *next;
73
74         curr = thread_current();
75         model->check_current_action();
76         if (curr) {
77                 if (curr->state == THREAD_READY)
78                         model->scheduler->add_thread(curr);
79                 else if (curr->state == THREAD_RUNNING)
80                         /* Stopped while running; i.e., completed */
81                         thread_dispose(curr);
82                 else
83                         DEBUG("ERROR: current thread in unexpected state??\n");
84         }
85         next = model->scheduler->next_thread();
86         if (next)
87                 next->state = THREAD_RUNNING;
88         DEBUG("(%d, %d)\n", curr ? curr->id : -1, next ? next->id : -1);
89         if (!next)
90                 return 1;
91         return thread_swap(model->system_thread, next);
92 }
93
94 static void thread_wait_finish(void)
95 {
96
97         DBG();
98
99         while (!thread_system_next());
100 }
101
102 int thread_switch_to_master(ModelAction *act)
103 {
104         struct thread *old, *next;
105
106         DBG();
107         model->set_current_action(act);
108         old = thread_current();
109         old->state = THREAD_READY;
110         next = model->system_thread;
111         return thread_swap(old, next);
112 }
113
114 /*
115  * User program API functions
116  */
117 int thread_create(struct thread *t, void (*start_routine)(), void *arg)
118 {
119         int ret = 0;
120
121         DBG();
122
123         memset(t, 0, sizeof(*t));
124         model->assign_id(t);
125         DEBUG("create thread %d\n", t->id);
126
127         t->start_routine = start_routine;
128         t->arg = arg;
129
130         /* Initialize state */
131         ret = create_context(t);
132         if (ret)
133                 return ret;
134
135         t->state = THREAD_CREATED;
136
137         model->scheduler->add_thread(t);
138         return 0;
139 }
140
141 int thread_join(struct thread *t)
142 {
143         int ret = 0;
144         while (t->state != THREAD_COMPLETED && !ret)
145                 /* seq_cst is just a 'don't care' parameter */
146                 ret = thread_switch_to_master(new ModelAction(THREAD_JOIN, memory_order_seq_cst, NULL, VALUE_NONE));
147         return ret;
148 }
149
150 int thread_yield(void)
151 {
152         /* seq_cst is just a 'don't care' parameter */
153         return thread_switch_to_master(new ModelAction(THREAD_YIELD, memory_order_seq_cst, NULL, VALUE_NONE));
154 }
155
156 struct thread *thread_current(void)
157 {
158         return model->scheduler->get_current_thread();
159 }
160
161 /*
162  * Main system function
163  */
164 int main()
165 {
166         struct thread user_thread;
167         struct thread *main_thread;
168
169         model = new ModelChecker();
170
171         main_thread = (struct thread *)myMalloc(sizeof(*main_thread));
172         create_initial_thread(main_thread);
173         model->add_system_thread(main_thread);
174
175         /* Start user program */
176         thread_create(&user_thread, &user_main, NULL);
177
178         /* Wait for all threads to complete */
179         thread_wait_finish();
180
181         model->print_trace();
182         delete model;
183         myFree(main_thread);
184
185         DEBUG("Exiting\n");
186         return 0;
187 }