libthreads: add THREAD_* states
[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         model->scheduler->add_thread(old);
65         next = model->scheduler->next_thread();
66         DEBUG("(%d, %d)\n", old->index, next->index);
67         return thread_swap(old, next);
68 }
69
70 static void thread_dispose(struct thread *t)
71 {
72         DEBUG("completed thread %d\n", thread_current()->index);
73         t->state = THREAD_COMPLETED;
74         stack_free(t->stack);
75 }
76
77 static void thread_wait_finish(void)
78 {
79         struct thread *curr, *next;
80
81         DBG();
82
83         do {
84                 if ((curr = thread_current()))
85                         thread_dispose(curr);
86                 next = model->scheduler->next_thread();
87         } while (next && !thread_swap(model->system_thread, next));
88 }
89
90 int thread_create(struct thread *t, void (*start_routine), void *arg)
91 {
92         static int created = 1;
93         int ret = 0;
94
95         DBG();
96
97         memset(t, 0, sizeof(*t));
98         t->index = created++;
99         DEBUG("create thread %d\n", t->index);
100
101         t->start_routine = start_routine;
102         t->arg = arg;
103
104         /* Initialize state */
105         ret = create_context(t);
106         if (ret)
107                 return ret;
108
109         t->state = THREAD_CREATED;
110
111         model->scheduler->add_thread(t);
112         return 0;
113 }
114
115 void thread_join(struct thread *t)
116 {
117         while (t->state != THREAD_COMPLETED)
118                 thread_yield();
119 }
120
121 struct thread *thread_current(void)
122 {
123         return model->scheduler->get_current_thread();
124 }
125
126 int main()
127 {
128         struct thread user_thread;
129         struct thread *main_thread;
130
131         model_checker_init();
132
133         main_thread = malloc(sizeof(struct thread));
134         create_initial_thread(main_thread);
135         model_checker_add_system_thread(main_thread);
136
137         /* Start user program */
138         thread_create(&user_thread, &user_main, NULL);
139
140         /* Wait for all threads to complete */
141         thread_wait_finish();
142
143         DEBUG("Exiting\n");
144         return 0;
145 }