libthreads: cleanup startup/exit functions
[model-checker.git] / libthreads.c
1 #include <string.h>
2 #include <stdlib.h>
3
4 #include "libthreads.h"
5
6 #define STACK_SIZE (1024 * 1024)
7
8 static struct thread *current, *main_thread;
9
10 static void *stack_allocate(size_t size)
11 {
12         return malloc(size);
13 }
14
15 static void stack_free(void *stack)
16 {
17         free(stack);
18 }
19
20 static int create_context(struct thread *t)
21 {
22         int ret;
23
24         memset(&t->context, 0, sizeof(t->context));
25         ret = getcontext(&t->context);
26         if (ret)
27                 return ret;
28
29         /* t->start_routine == NULL means this is our initial context */
30         if (!t->start_routine)
31                 return 0;
32
33         /* Initialize new managed context */
34         t->stack = stack_allocate(STACK_SIZE);
35         t->context.uc_stack.ss_sp = t->stack;
36         t->context.uc_stack.ss_size = STACK_SIZE;
37         t->context.uc_stack.ss_flags = 0;
38         t->context.uc_link = &main_thread->context;
39         makecontext(&t->context, t->start_routine, 1, t->arg);
40
41         return 0;
42 }
43
44 static int create_initial_thread(struct thread *t)
45 {
46         memset(t, 0, sizeof(*t));
47         return create_context(t);
48 }
49
50 static int thread_swap(struct thread *old, struct thread *new)
51 {
52         return swapcontext(&old->context, &new->context);
53 }
54
55 static int thread_yield()
56 {
57         struct thread *old, *next;
58
59         DBG();
60         if (current) {
61                 old = current;
62                 schedule_add_thread(old);
63         } else {
64                 old = main_thread;
65         }
66         schedule_choose_next(&next);
67         current = next;
68         return thread_swap(old, next);
69 }
70
71 static void thread_dispose(struct thread *t)
72 {
73         DEBUG("completed thread %d\n", current->index);
74         t->completed = 1;
75         stack_free(t->stack);
76 }
77
78 static void thread_wait_finish()
79 {
80         struct thread *next;
81
82         DBG();
83
84         do {
85                 if (current)
86                         thread_dispose(current);
87                 schedule_choose_next(&next);
88                 current = next;
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         schedule_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 void a(int *parm)
122 {
123         int i;
124
125         for (i = 0; i < 10; i++) {
126                 printf("Thread %d, magic number %d, loop %d\n", current->index, *parm, i);
127                 if (i % 2)
128                         thread_yield();
129         }
130 }
131
132 void user_main()
133 {
134         struct thread t1, t2;
135         int i = 17, j = 13;
136
137         printf("%s() creating 2 threads\n", __func__);
138         thread_create(&t1, &a, &i);
139         thread_create(&t2, &a, &j);
140
141         thread_join(&t1);
142         thread_join(&t2);
143         printf("%s() is finished\n", __func__);
144 }
145
146 int main()
147 {
148         struct thread user_thread;
149
150         main_thread = malloc(sizeof(struct thread));
151         create_initial_thread(main_thread);
152
153         /* Start user program */
154         thread_create(&user_thread, &user_main, NULL);
155
156         /* Wait for all threads to complete */
157         thread_wait_finish();
158
159         DEBUG("Exiting\n");
160         return 0;
161 }