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