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 | } |