Rev 1155 | Rev 1407 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1155 | Rev 1392 | ||
---|---|---|---|
Line 31... | Line 31... | ||
31 | #include <malloc.h> |
31 | #include <malloc.h> |
32 | #include <unistd.h> |
32 | #include <unistd.h> |
33 | #include <thread.h> |
33 | #include <thread.h> |
34 | #include <stdio.h> |
34 | #include <stdio.h> |
35 | #include <kernel/arch/faddr.h> |
35 | #include <kernel/arch/faddr.h> |
36 | - | ||
- | 36 | #include <futex.h> |
|
- | 37 | #include <assert.h> |
|
37 | 38 | ||
38 | #ifndef PSTHREAD_INITIAL_STACK_PAGES_NO |
39 | #ifndef PSTHREAD_INITIAL_STACK_PAGES_NO |
39 | #define PSTHREAD_INITIAL_STACK_PAGES_NO 1 |
40 | #define PSTHREAD_INITIAL_STACK_PAGES_NO 1 |
40 | #endif |
41 | #endif |
41 | 42 | ||
42 | static LIST_INITIALIZE(ready_list); |
43 | static LIST_INITIALIZE(ready_list); |
- | 44 | static LIST_INITIALIZE(manager_list); |
|
43 | 45 | ||
44 | static void psthread_exit(void) __attribute__ ((noinline)); |
46 | static void psthread_exit(void) __attribute__ ((noinline)); |
45 | static void psthread_main(void); |
47 | static void psthread_main(void); |
46 | 48 | ||
- | 49 | static atomic_t psthread_futex = FUTEX_INITIALIZER; |
|
- | 50 | ||
47 | /** Setup PSthread information into TCB structure */ |
51 | /** Setup PSthread information into TCB structure */ |
48 | psthread_data_t * psthread_setup(tcb_t *tcb) |
52 | psthread_data_t * psthread_setup() |
49 | { |
53 | { |
50 | psthread_data_t *pt; |
54 | psthread_data_t *pt; |
- | 55 | tcb_t *tcb; |
|
- | 56 | ||
- | 57 | tcb = __make_tls(); |
|
- | 58 | if (!tcb) |
|
- | 59 | return NULL; |
|
51 | 60 | ||
52 | pt = malloc(sizeof(*pt)); |
61 | pt = malloc(sizeof(*pt)); |
53 | if (!pt) { |
62 | if (!pt) { |
- | 63 | __free_tls(tcb); |
|
54 | return NULL; |
64 | return NULL; |
55 | } |
65 | } |
56 | 66 | ||
57 | tcb->pst_data = pt; |
67 | tcb->pst_data = pt; |
58 | pt->tcb = tcb; |
68 | pt->tcb = tcb; |
Line 60... | Line 70... | ||
60 | return pt; |
70 | return pt; |
61 | } |
71 | } |
62 | 72 | ||
63 | void psthread_teardown(psthread_data_t *pt) |
73 | void psthread_teardown(psthread_data_t *pt) |
64 | { |
74 | { |
- | 75 | __free_tls(pt->tcb); |
|
65 | free(pt); |
76 | free(pt); |
66 | } |
77 | } |
67 | 78 | ||
68 | /** Function to preempt to other pseudo thread without adding |
79 | /** Function to preempt to other pseudo thread without adding |
69 | * currently running pseudo thread to ready_list. |
80 | * currently running pseudo thread to ready_list. |
70 | */ |
81 | */ |
71 | void psthread_exit(void) |
82 | void psthread_exit(void) |
72 | { |
83 | { |
73 | psthread_data_t *pt; |
84 | psthread_data_t *pt; |
74 | 85 | ||
- | 86 | futex_down(&psthread_futex); |
|
- | 87 | ||
75 | if (list_empty(&ready_list)) { |
88 | if (!list_empty(&ready_list)) |
- | 89 | pt = list_get_instance(ready_list.next, psthread_data_t, link); |
|
76 | /* Wait on IPC queue etc... */ |
90 | else if (!list_empty(&manager_list)) |
- | 91 | pt = list_get_instance(manager_list.next, psthread_data_t, link); |
|
- | 92 | else { |
|
77 | printf("Cannot exit!!!\n"); |
93 | printf("Cannot find suitable psthread to run.\n"); |
78 | _exit(0); |
94 | _exit(0); |
79 | } |
95 | } |
80 | pt = list_get_instance(ready_list.next, psthread_data_t, link); |
- | |
81 | list_remove(&pt->link); |
96 | list_remove(&pt->link); |
- | 97 | futex_up(&psthread_futex); |
|
- | 98 | ||
82 | context_restore(&pt->ctx); |
99 | context_restore(&pt->ctx); |
- | 100 | /* Never reached */ |
|
83 | } |
101 | } |
84 | 102 | ||
85 | /** Function that is called on entry to new uspace thread */ |
103 | /** Function that is called on entry to new uspace thread */ |
86 | void psthread_main(void) |
104 | void psthread_main(void) |
87 | { |
105 | { |
Line 96... | Line 114... | ||
96 | psthread_exit(); |
114 | psthread_exit(); |
97 | } |
115 | } |
98 | 116 | ||
99 | /** Schedule next userspace pseudo thread. |
117 | /** Schedule next userspace pseudo thread. |
100 | * |
118 | * |
- | 119 | * @param tomanager If true, we are switching to next ready manager thread |
|
- | 120 | * (if none is found, thread is exited) |
|
- | 121 | * @param frommanager If true, we are switching from manager thread |
|
101 | * @return 0 if there is no ready pseudo thread, 1 otherwise. |
122 | * @return 0 if there is no ready pseudo thread, 1 otherwise. |
102 | */ |
123 | */ |
103 | int psthread_schedule_next(void) |
124 | int psthread_schedule_next_adv(pschange_type ctype) |
104 | { |
125 | { |
105 | psthread_data_t *pt; |
126 | psthread_data_t *pt; |
- | 127 | int retval = 0; |
|
- | 128 | ||
- | 129 | futex_down(&psthread_futex); |
|
106 | 130 | ||
107 | if (list_empty(&ready_list)) |
131 | if (ctype == PS_PREEMPT && list_empty(&ready_list)) |
108 | return 0; |
132 | goto ret_0; |
- | 133 | ||
- | 134 | if (ctype == PS_FROM_MANAGER && list_empty(&ready_list)) { |
|
- | 135 | goto ret_0; |
|
- | 136 | } |
|
- | 137 | assert(!(ctype == PS_TO_MANAGER && list_empty(&manager_list))); |
|
109 | 138 | ||
110 | pt = __tcb_get()->pst_data; |
139 | pt = __tcb_get()->pst_data; |
111 | if (!context_save(&pt->ctx)) |
140 | if (!context_save(&pt->ctx)) |
112 | return 1; |
141 | return 1; // futex_up already done here |
- | 142 | ||
- | 143 | if (ctype == PS_PREEMPT) |
|
- | 144 | list_append(&pt->link, &ready_list); |
|
- | 145 | else if (ctype == PS_FROM_MANAGER) |
|
- | 146 | list_append(&pt->link, &manager_list); |
|
113 | 147 | ||
- | 148 | if (ctype == PS_TO_MANAGER) |
|
114 | list_append(&pt->link, &ready_list); |
149 | pt = list_get_instance(manager_list.next,psthread_data_t, link); |
- | 150 | else |
|
115 | pt = list_get_instance(ready_list.next, psthread_data_t, link); |
151 | pt = list_get_instance(ready_list.next, psthread_data_t, link); |
116 | list_remove(&pt->link); |
152 | list_remove(&pt->link); |
117 | 153 | ||
- | 154 | futex_up(&psthread_futex); |
|
118 | context_restore(&pt->ctx); |
155 | context_restore(&pt->ctx); |
- | 156 | ||
- | 157 | ret_0: |
|
- | 158 | futex_up(&psthread_futex); |
|
- | 159 | return retval; |
|
119 | } |
160 | } |
120 | 161 | ||
121 | /** Wait for uspace pseudo thread to finish. |
162 | /** Wait for uspace pseudo thread to finish. |
122 | * |
163 | * |
123 | * @param psthrid Pseudo thread to wait for. |
164 | * @param psthrid Pseudo thread to wait for. |
Line 140... | Line 181... | ||
140 | } |
181 | } |
141 | } |
182 | } |
142 | retval = pt->retval; |
183 | retval = pt->retval; |
143 | 184 | ||
144 | free(pt->stack); |
185 | free(pt->stack); |
145 | __free_tls(pt->tcb); |
- | |
146 | psthread_teardown((void *)pt); |
186 | psthread_teardown((void *)pt); |
147 | 187 | ||
148 | return retval; |
188 | return retval; |
149 | } |
189 | } |
150 | 190 | ||
151 | /** |
191 | /** |
152 | * Create a userspace thread and append it to ready list. |
192 | * Create a userspace thread |
153 | * |
193 | * |
154 | * @param func Pseudo thread function. |
194 | * @param func Pseudo thread function. |
155 | * @param arg Argument to pass to func. |
195 | * @param arg Argument to pass to func. |
156 | * |
196 | * |
157 | * @return 0 on failure, TLS of the new pseudo thread. |
197 | * @return 0 on failure, TLS of the new pseudo thread. |
158 | */ |
198 | */ |
159 | pstid_t psthread_create(int (*func)(void *), void *arg) |
199 | pstid_t psthread_create(int (*func)(void *), void *arg) |
160 | { |
200 | { |
161 | psthread_data_t *pt; |
201 | psthread_data_t *pt; |
162 | tcb_t *tcb; |
- | |
163 | - | ||
164 | tcb = __make_tls(); |
- | |
165 | if (!tcb) |
- | |
166 | return 0; |
- | |
167 | 202 | ||
168 | pt = psthread_setup(tcb); |
203 | pt = psthread_setup(); |
169 | if (!pt) { |
204 | if (!pt) |
170 | __free_tls(tcb); |
- | |
171 | return 0; |
205 | return 0; |
172 | } |
- | |
173 | pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize()); |
206 | pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize()); |
174 | 207 | ||
175 | if (!pt->stack) { |
208 | if (!pt->stack) { |
176 | __free_tls(tcb); |
- | |
177 | psthread_teardown(pt); |
209 | psthread_teardown(pt); |
178 | return 0; |
210 | return 0; |
179 | } |
211 | } |
180 | 212 | ||
181 | pt->arg= arg; |
213 | pt->arg= arg; |
Line 183... | Line 215... | ||
183 | pt->finished = 0; |
215 | pt->finished = 0; |
184 | pt->waiter = NULL; |
216 | pt->waiter = NULL; |
185 | 217 | ||
186 | context_save(&pt->ctx); |
218 | context_save(&pt->ctx); |
187 | context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(), |
219 | context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(), |
188 | tcb); |
220 | pt->tcb); |
- | 221 | ||
- | 222 | return (pstid_t )pt; |
|
- | 223 | } |
|
- | 224 | ||
- | 225 | /** Add a thread to ready list */ |
|
- | 226 | void psthread_add_ready(pstid_t psthrid) |
|
- | 227 | { |
|
- | 228 | psthread_data_t *pt; |
|
189 | 229 | ||
- | 230 | pt = (psthread_data_t *) psthrid; |
|
- | 231 | futex_down(&psthread_futex); |
|
190 | list_append(&pt->link, &ready_list); |
232 | list_append(&pt->link, &ready_list); |
- | 233 | futex_up(&psthread_futex); |
|
- | 234 | } |
|
191 | 235 | ||
- | 236 | /** Add a thread to manager list */ |
|
- | 237 | void psthread_add_manager(pstid_t psthrid) |
|
- | 238 | { |
|
192 | return (pstid_t )pt; |
239 | psthread_data_t *pt; |
- | 240 | ||
- | 241 | pt = (psthread_data_t *) psthrid; |
|
- | 242 | ||
- | 243 | futex_down(&psthread_futex); |
|
- | 244 | list_append(&pt->link, &manager_list); |
|
- | 245 | futex_up(&psthread_futex); |
|
- | 246 | } |
|
- | 247 | ||
- | 248 | /** Remove one manager from manager list */ |
|
- | 249 | void psthread_remove_manager() |
|
- | 250 | { |
|
- | 251 | futex_down(&psthread_futex); |
|
- | 252 | if (list_empty(&manager_list)) { |
|
- | 253 | printf("No manager found!.\n"); |
|
- | 254 | futex_up(&psthread_futex); |
|
- | 255 | return; |
|
- | 256 | } |
|
- | 257 | list_remove(manager_list.next); |
|
- | 258 | futex_up(&psthread_futex); |
|
193 | } |
259 | } |