threads/model: move switch_to_master from class Thread to class ModelChecker
[c11tester.git] / threads.cc
1 #include <stdlib.h>
2
3 #include "libthreads.h"
4 #include "schedule.h"
5 #include "common.h"
6 #include "threads_internal.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 Thread *thread_current(void)
24 {
25         return model->scheduler->get_current_thread();
26 }
27
28 int Thread::create_context()
29 {
30         int ret;
31
32         ret = getcontext(&context);
33         if (ret)
34                 return ret;
35
36         /* start_routine == NULL means this is our initial context */
37         if (!start_routine)
38                 return 0;
39
40         /* Initialize new managed context */
41         stack = stack_allocate(STACK_SIZE);
42         context.uc_stack.ss_sp = stack;
43         context.uc_stack.ss_size = STACK_SIZE;
44         context.uc_stack.ss_flags = 0;
45         context.uc_link = &model->system_thread->context;
46         makecontext(&context, start_routine, 1, arg);
47
48         return 0;
49 }
50
51 int Thread::swap(Thread *t)
52 {
53         return swapcontext(&this->context, &t->context);
54 }
55
56 void Thread::dispose()
57 {
58         DEBUG("completed thread %d\n", thread_current()->get_id());
59         state = THREAD_COMPLETED;
60         stack_free(stack);
61 }
62
63 Thread::Thread(thrd_t *t, void (*func)(), void *a) {
64         int ret;
65
66         user_thread = t;
67         start_routine = func;
68         arg = a;
69
70         /* Initialize state */
71         ret = create_context();
72         if (ret)
73                 printf("Error in create_context\n");
74
75         state = THREAD_CREATED;
76         model->assign_id(this);
77         model->scheduler->add_thread(this);
78 }
79
80 Thread::Thread(thrd_t *t) {
81         /* system thread */
82         user_thread = t;
83         state = THREAD_CREATED;
84         model->assign_id(this);
85         create_context();
86         model->add_system_thread(this);
87 }
88
89 thread_id_t Thread::get_id()
90 {
91         return thrd_to_id(*user_thread);
92 }
93
94 /*
95  * Return 1 if found next thread, 0 otherwise
96  */
97 static int thread_system_next(void)
98 {
99         Thread *curr, *next;
100
101         curr = thread_current();
102         model->check_current_action();
103         if (curr) {
104                 if (curr->get_state() == THREAD_READY)
105                         model->scheduler->add_thread(curr);
106                 else if (curr->get_state() == THREAD_RUNNING)
107                         /* Stopped while running; i.e., completed */
108                         curr->dispose();
109                 else
110                         DEBUG("ERROR: current thread in unexpected state??\n");
111         }
112         next = model->scheduler->next_thread();
113         if (next)
114                 next->set_state(THREAD_RUNNING);
115         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
116         if (!next)
117                 return 1;
118         return model->system_thread->swap(next);
119 }
120
121 static void thread_wait_finish(void)
122 {
123
124         DBG();
125
126         while (!thread_system_next());
127 }
128
129 /*
130  * Main system function
131  */
132 int main()
133 {
134         thrd_t user_thread, main_thread;
135         Thread *th;
136
137         model = new ModelChecker();
138
139         th = new Thread(&main_thread);
140
141         /* Start user program */
142         thrd_create(&user_thread, &user_main, NULL);
143
144         /* Wait for all threads to complete */
145         thread_wait_finish();
146
147         model->print_trace();
148         delete th;
149         delete model;
150
151         DEBUG("Exiting\n");
152         return 0;
153 }