2e3474aaa881b0c460e3cc0e150b5fbcb7461545
[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         old = current;
61         schedule_add_thread(old);
62         schedule_choose_next(&next);
63         current = next;
64         DEBUG("(%d, %d)\n", old->index, next->index);
65         return thread_swap(old, next);
66 }
67
68 static void thread_dispose(struct thread *t)
69 {
70         DEBUG("completed thread %d\n", thread_current()->index);
71         t->completed = 1;
72         stack_free(t->stack);
73 }
74
75 static void thread_wait_finish()
76 {
77         struct thread *next;
78
79         DBG();
80
81         do {
82                 if (current)
83                         thread_dispose(current);
84                 schedule_choose_next(&next);
85                 current = next;
86         } while (next && !thread_swap(main_thread, next));
87 }
88
89 int thread_create(struct thread *t, void (*start_routine), void *arg)
90 {
91         static int created = 1;
92         int ret = 0;
93
94         DBG();
95
96         memset(t, 0, sizeof(*t));
97         t->index = created++;
98         DEBUG("create thread %d\n", t->index);
99
100         t->start_routine = start_routine;
101         t->arg = arg;
102
103         /* Initialize state */
104         ret = create_context(t);
105         if (ret)
106                 return ret;
107
108         schedule_add_thread(t);
109         return 0;
110 }
111
112 void thread_join(struct thread *t)
113 {
114         while (!t->completed)
115                 thread_yield();
116 }
117
118 struct thread *thread_current(void)
119 {
120         return current;
121 }
122
123 void a(int *parm)
124 {
125         int i;
126
127         for (i = 0; i < 10; i++) {
128                 printf("Thread %d, magic number %d, loop %d\n", thread_current()->index, *parm, i);
129                 if (i % 2)
130                         thread_yield();
131         }
132 }
133
134 void user_main()
135 {
136         struct thread t1, t2;
137         int i = 17, j = 13;
138
139         printf("%s() creating 2 threads\n", __func__);
140         thread_create(&t1, &a, &i);
141         thread_create(&t2, &a, &j);
142
143         thread_join(&t1);
144         thread_join(&t2);
145         printf("%s() is finished\n", __func__);
146 }
147
148 int main()
149 {
150         struct thread user_thread;
151
152         main_thread = malloc(sizeof(struct thread));
153         create_initial_thread(main_thread);
154
155         /* Start user program */
156         thread_create(&user_thread, &user_main, NULL);
157
158         /* Wait for all threads to complete */
159         thread_wait_finish();
160
161         DEBUG("Exiting\n");
162         return 0;
163 }