reformat DEBUG messages
[c11tester.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 int create_context(struct thread *t)
16 {
17         int ret;
18
19         memset(&t->context, 0, sizeof(t->context));
20         ret = getcontext(&t->context);
21         if (ret)
22                 return ret;
23
24         /* t->start_routine == NULL means this is our initial context */
25         if (!t->start_routine)
26                 return 0;
27
28         /* Initialize new managed context */
29         t->stack = stack_allocate(STACK_SIZE);
30         t->context.uc_stack.ss_sp = t->stack;
31         t->context.uc_stack.ss_size = STACK_SIZE;
32         t->context.uc_stack.ss_flags = 0;
33         t->context.uc_link = &main_thread->context;
34         makecontext(&t->context, t->start_routine, 1, t->arg);
35
36         return 0;
37 }
38
39 static int create_initial_thread(struct thread *t)
40 {
41         memset(t, 0, sizeof(*t));
42         return create_context(t);
43 }
44
45 static int thread_swap(struct thread *old, struct thread *new)
46 {
47         return swapcontext(&old->context, &new->context);
48 }
49
50 static int thread_yield()
51 {
52         struct thread *old, *next;
53
54         DBG();
55         if (current) {
56                 old = current;
57                 schedule_add_thread(old);
58         } else {
59                 old = main_thread;
60         }
61         schedule_choose_next(&next);
62         current = next;
63         return thread_swap(old, next);
64 }
65
66 static int master_thread_yield()
67 {
68         struct thread *next;
69
70         DBG();
71
72         if (current) {
73                 DEBUG("completed thread %d\n", current->index);
74                 current->completed = 1;
75         }
76         schedule_choose_next(&next);
77         if (next && !next->completed) {
78                 current = next;
79                 return thread_swap(main_thread, next);
80         }
81         return 1;
82 }
83
84 int thread_create(struct thread *t, void (*start_routine), void *arg)
85 {
86         static int created = 1;
87         int ret = 0;
88
89         DBG();
90
91         memset(t, 0, sizeof(*t));
92         t->index = created++;
93         DEBUG("create thread %d\n", t->index);
94
95         t->start_routine = start_routine;
96         t->arg = arg;
97
98         /* Initialize state */
99         ret = create_context(t);
100         if (ret)
101                 return ret;
102
103         schedule_add_thread(t);
104         return 0;
105 }
106
107 void thread_join(struct thread *t)
108 {
109         while (!t->completed)
110                 thread_yield();
111 }
112
113 void a(int *idx)
114 {
115         int i;
116
117         for (i = 0; i < 10; i++) {
118                 printf("Thread %d, loop %d\n", *idx, i);
119                 if (i % 2)
120                         thread_yield();
121         }
122 }
123
124 void user_main()
125 {
126         struct thread t1, t2;
127         int i = 2, j = 3;
128
129         printf("%s() creating 2 threads\n", __func__);
130         thread_create(&t1, &a, &i);
131         thread_create(&t2, &a, &j);
132
133         thread_join(&t1);
134         thread_join(&t2);
135         printf("%s() is finished\n", __func__);
136 }
137
138 int main()
139 {
140         struct thread user_thread;
141
142         main_thread = malloc(sizeof(struct thread));
143         create_initial_thread(main_thread);
144
145         thread_create(&user_thread, &user_main, NULL);
146
147         /* Wait for all threads to complete */
148         while (master_thread_yield() == 0);
149
150         DEBUG("Exiting\n");
151         return 0;
152 }