libthreads: perform all scheduling/model-checking from master thread
[model-checker.git] / libthreads.c
1 #include <string.h>
2 #include <stdlib.h>
3
4 #include "libthreads.h"
5 #include "schedule.h"
6 #include "common.h"
7
8 /* global "model" struct */
9 #include "model.h"
10
11 #define STACK_SIZE (1024 * 1024)
12
13 static void *stack_allocate(size_t size)
14 {
15         return malloc(size);
16 }
17
18 static void stack_free(void *stack)
19 {
20         free(stack);
21 }
22
23 static int create_context(struct thread *t)
24 {
25         int ret;
26
27         memset(&t->context, 0, sizeof(t->context));
28         ret = getcontext(&t->context);
29         if (ret)
30                 return ret;
31
32         /* t->start_routine == NULL means this is our initial context */
33         if (!t->start_routine)
34                 return 0;
35
36         /* Initialize new managed context */
37         t->stack = stack_allocate(STACK_SIZE);
38         t->context.uc_stack.ss_sp = t->stack;
39         t->context.uc_stack.ss_size = STACK_SIZE;
40         t->context.uc_stack.ss_flags = 0;
41         t->context.uc_link = &model->system_thread->context;
42         makecontext(&t->context, t->start_routine, 1, t->arg);
43
44         return 0;
45 }
46
47 static int create_initial_thread(struct thread *t)
48 {
49         memset(t, 0, sizeof(*t));
50         return create_context(t);
51 }
52
53 static int thread_swap(struct thread *old, struct thread *new)
54 {
55         return swapcontext(&old->context, &new->context);
56 }
57
58 int thread_yield(void)
59 {
60         struct thread *old, *next;
61
62         DBG();
63         old = thread_current();
64         old->state = THREAD_READY;
65         next = model->system_thread;
66         return thread_swap(old, next);
67 }
68
69 static void thread_dispose(struct thread *t)
70 {
71         DEBUG("completed thread %d\n", thread_current()->index);
72         t->state = THREAD_COMPLETED;
73         stack_free(t->stack);
74 }
75
76 /*
77  * Return 1 if found next thread, 0 otherwise
78  */
79 static int thread_system_next(void)
80 {
81         struct thread *curr, *next;
82
83         curr = thread_current();
84         if (curr) {
85                 if (curr->state == THREAD_READY)
86                         model->scheduler->add_thread(curr);
87                 else if (curr->state == THREAD_RUNNING)
88                         /* Stopped while running; i.e., completed */
89                         thread_dispose(curr);
90                 else
91                         DEBUG("ERROR: current thread in unexpected state??\n");
92         }
93         next = model->scheduler->next_thread();
94         if (next)
95                 next->state = THREAD_RUNNING;
96         DEBUG("(%d, %d)\n", curr ? curr->index : -1, next ? next->index : -1);
97         if (!next)
98                 return 1;
99         return thread_swap(model->system_thread, next);
100 }
101
102 static void thread_wait_finish(void)
103 {
104
105         DBG();
106
107         while (!thread_system_next());
108 }
109
110 int thread_create(struct thread *t, void (*start_routine), void *arg)
111 {
112         static int created = 1;
113         int ret = 0;
114
115         DBG();
116
117         memset(t, 0, sizeof(*t));
118         t->index = created++;
119         DEBUG("create thread %d\n", t->index);
120
121         t->start_routine = start_routine;
122         t->arg = arg;
123
124         /* Initialize state */
125         ret = create_context(t);
126         if (ret)
127                 return ret;
128
129         t->state = THREAD_CREATED;
130
131         model->scheduler->add_thread(t);
132         return 0;
133 }
134
135 void thread_join(struct thread *t)
136 {
137         while (t->state != THREAD_COMPLETED)
138                 thread_yield();
139 }
140
141 struct thread *thread_current(void)
142 {
143         return model->scheduler->get_current_thread();
144 }
145
146 int main()
147 {
148         struct thread user_thread;
149         struct thread *main_thread;
150
151         model_checker_init();
152
153         main_thread = malloc(sizeof(struct thread));
154         create_initial_thread(main_thread);
155         model_checker_add_system_thread(main_thread);
156
157         /* Start user program */
158         thread_create(&user_thread, &user_main, NULL);
159
160         /* Wait for all threads to complete */
161         thread_wait_finish();
162
163         DEBUG("Exiting\n");
164         return 0;
165 }