rename other *.c to *.cc
[c11tester.git] / libthreads.cc
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" object */
9 #include "model.h"
10
11 #define STACK_SIZE (1024 * 1024)
12
13 static void *stack_allocate(size_t size)
14 {
15         return malloc(size);
16 }
17
18 static void stack_free(void *stack)
19 {
20         free(stack);
21 }
22
23 static int create_context(struct thread *t)
24 {
25         int ret;
26
27         memset(&t->context, 0, sizeof(t->context));
28         ret = getcontext(&t->context);
29         if (ret)
30                 return ret;
31
32         /* t->start_routine == NULL means this is our initial context */
33         if (!t->start_routine)
34                 return 0;
35
36         /* Initialize new managed context */
37         t->stack = stack_allocate(STACK_SIZE);
38         t->context.uc_stack.ss_sp = t->stack;
39         t->context.uc_stack.ss_size = STACK_SIZE;
40         t->context.uc_stack.ss_flags = 0;
41         t->context.uc_link = &model->system_thread->context;
42         makecontext(&t->context, t->start_routine, 1, t->arg);
43
44         return 0;
45 }
46
47 static int create_initial_thread(struct thread *t)
48 {
49         memset(t, 0, sizeof(*t));
50         model->assign_id(t);
51         return create_context(t);
52 }
53
54 static int thread_swap(struct thread *t1, struct thread *t2)
55 {
56         return swapcontext(&t1->context, &t2->context);
57 }
58
59 static void thread_dispose(struct thread *t)
60 {
61         DEBUG("completed thread %d\n", thread_current()->id);
62         t->state = THREAD_COMPLETED;
63         stack_free(t->stack);
64 }
65
66 /*
67  * Return 1 if found next thread, 0 otherwise
68  */
69 static int thread_system_next(void)
70 {
71         struct thread *curr, *next;
72
73         curr = thread_current();
74         if (curr) {
75                 if (curr->state == THREAD_READY)
76                         model->scheduler->add_thread(curr);
77                 else if (curr->state == THREAD_RUNNING)
78                         /* Stopped while running; i.e., completed */
79                         thread_dispose(curr);
80                 else
81                         DEBUG("ERROR: current thread in unexpected state??\n");
82         }
83         next = model->scheduler->next_thread();
84         if (next)
85                 next->state = THREAD_RUNNING;
86         DEBUG("(%d, %d)\n", curr ? curr->id : -1, next ? next->id : -1);
87         if (!next)
88                 return 1;
89         return thread_swap(model->system_thread, next);
90 }
91
92 static void thread_wait_finish(void)
93 {
94
95         DBG();
96
97         while (!thread_system_next());
98 }
99
100 /*
101  * User program API functions
102  */
103 int thread_create(struct thread *t, void (*start_routine)(), void *arg)
104 {
105         int ret = 0;
106
107         DBG();
108
109         memset(t, 0, sizeof(*t));
110         model->assign_id(t);
111         DEBUG("create thread %d\n", t->id);
112
113         t->start_routine = start_routine;
114         t->arg = arg;
115
116         /* Initialize state */
117         ret = create_context(t);
118         if (ret)
119                 return ret;
120
121         t->state = THREAD_CREATED;
122
123         model->scheduler->add_thread(t);
124         return 0;
125 }
126
127 void thread_join(struct thread *t)
128 {
129         while (t->state != THREAD_COMPLETED)
130                 thread_yield();
131 }
132
133 int thread_yield(void)
134 {
135         struct thread *old, *next;
136
137         DBG();
138         old = thread_current();
139         old->state = THREAD_READY;
140         next = model->system_thread;
141         return thread_swap(old, next);
142 }
143
144 struct thread *thread_current(void)
145 {
146         return model->scheduler->get_current_thread();
147 }
148
149 /*
150  * Main system function
151  */
152 int main()
153 {
154         struct thread user_thread;
155         struct thread *main_thread;
156
157         model = new ModelChecker();
158
159         main_thread = (struct thread *)malloc(sizeof(*main_thread));
160         create_initial_thread(main_thread);
161         model->add_system_thread(main_thread);
162
163         /* Start user program */
164         thread_create(&user_thread, &user_main, NULL);
165
166         /* Wait for all threads to complete */
167         thread_wait_finish();
168
169         delete model;
170
171         DEBUG("Exiting\n");
172         return 0;
173 }