3697c0851e035109ddd49329ea640f8a154b08ca
[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 struct thread *current, *main_thread;
14
15 static void *stack_allocate(size_t size)
16 {
17         return malloc(size);
18 }
19
20 static void stack_free(void *stack)
21 {
22         free(stack);
23 }
24
25 static int create_context(struct thread *t)
26 {
27         int ret;
28
29         memset(&t->context, 0, sizeof(t->context));
30         ret = getcontext(&t->context);
31         if (ret)
32                 return ret;
33
34         /* t->start_routine == NULL means this is our initial context */
35         if (!t->start_routine)
36                 return 0;
37
38         /* Initialize new managed context */
39         t->stack = stack_allocate(STACK_SIZE);
40         t->context.uc_stack.ss_sp = t->stack;
41         t->context.uc_stack.ss_size = STACK_SIZE;
42         t->context.uc_stack.ss_flags = 0;
43         t->context.uc_link = &main_thread->context;
44         makecontext(&t->context, t->start_routine, 1, t->arg);
45
46         return 0;
47 }
48
49 static int create_initial_thread(struct thread *t)
50 {
51         memset(t, 0, sizeof(*t));
52         return create_context(t);
53 }
54
55 static int thread_swap(struct thread *old, struct thread *new)
56 {
57         return swapcontext(&old->context, &new->context);
58 }
59
60 int thread_yield(void)
61 {
62         struct thread *old, *next;
63
64         DBG();
65         old = current;
66         model->scheduler->add_thread(old);
67         next = model->scheduler->next_thread();
68         current = next;
69         DEBUG("(%d, %d)\n", old->index, next->index);
70         return thread_swap(old, next);
71 }
72
73 static void thread_dispose(struct thread *t)
74 {
75         DEBUG("completed thread %d\n", thread_current()->index);
76         t->completed = 1;
77         stack_free(t->stack);
78 }
79
80 static void thread_wait_finish(void)
81 {
82         struct thread *next;
83
84         DBG();
85
86         do {
87                 if (current)
88                         thread_dispose(current);
89                 next = model->scheduler->next_thread();
90                 current = next;
91         } while (next && !thread_swap(main_thread, next));
92 }
93
94 int thread_create(struct thread *t, void (*start_routine), void *arg)
95 {
96         static int created = 1;
97         int ret = 0;
98
99         DBG();
100
101         memset(t, 0, sizeof(*t));
102         t->index = created++;
103         DEBUG("create thread %d\n", t->index);
104
105         t->start_routine = start_routine;
106         t->arg = arg;
107
108         /* Initialize state */
109         ret = create_context(t);
110         if (ret)
111                 return ret;
112
113         model->scheduler->add_thread(t);
114         return 0;
115 }
116
117 void thread_join(struct thread *t)
118 {
119         while (!t->completed)
120                 thread_yield();
121 }
122
123 struct thread *thread_current(void)
124 {
125         return current;
126 }
127
128 int main()
129 {
130         struct thread user_thread;
131
132         model_checker_init();
133
134         main_thread = malloc(sizeof(struct thread));
135         create_initial_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 }