00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <libadt/list.h>
00036 #include <psthread.h>
00037 #include <malloc.h>
00038 #include <unistd.h>
00039 #include <thread.h>
00040 #include <stdio.h>
00041 #include <kernel/arch/faddr.h>
00042 #include <futex.h>
00043 #include <assert.h>
00044 #include <async.h>
00045
00046 #ifndef PSTHREAD_INITIAL_STACK_PAGES_NO
00047 #define PSTHREAD_INITIAL_STACK_PAGES_NO 1
00048 #endif
00049
00050 static LIST_INITIALIZE(ready_list);
00051 static LIST_INITIALIZE(serialized_list);
00052 static LIST_INITIALIZE(manager_list);
00053
00054 static void psthread_main(void);
00055
00056 static atomic_t psthread_futex = FUTEX_INITIALIZER;
00058 static int serialized_threads;
00060 static __thread int serialization_count;
00062 static int threads_in_manager;
00063
00065 psthread_data_t * psthread_setup()
00066 {
00067 psthread_data_t *pt;
00068 tcb_t *tcb;
00069
00070 tcb = __make_tls();
00071 if (!tcb)
00072 return NULL;
00073
00074 pt = malloc(sizeof(*pt));
00075 if (!pt) {
00076 __free_tls(tcb);
00077 return NULL;
00078 }
00079
00080 tcb->pst_data = pt;
00081 pt->tcb = tcb;
00082
00083 return pt;
00084 }
00085
00086 void psthread_teardown(psthread_data_t *pt)
00087 {
00088 __free_tls(pt->tcb);
00089 free(pt);
00090 }
00091
00093 void psthread_main(void)
00094 {
00095 psthread_data_t *pt = __tcb_get()->pst_data;
00096
00097 pt->retval = pt->func(pt->arg);
00098
00099 pt->finished = 1;
00100 if (pt->waiter)
00101 list_append(&pt->waiter->link, &ready_list);
00102
00103 psthread_schedule_next_adv(PS_FROM_DEAD);
00104 }
00105
00114 int psthread_schedule_next_adv(pschange_type ctype)
00115 {
00116 psthread_data_t *srcpt, *dstpt;
00117 int retval = 0;
00118
00119 futex_down(&psthread_futex);
00120
00121 if (ctype == PS_PREEMPT && list_empty(&ready_list))
00122 goto ret_0;
00123
00124 if (ctype == PS_FROM_MANAGER) {
00125 if (list_empty(&ready_list) && list_empty(&serialized_list))
00126 goto ret_0;
00127
00128 if (list_empty(&serialized_list) && threads_in_manager <= serialized_threads) {
00129 goto ret_0;
00130 }
00131 }
00132
00133 if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
00134 while (list_empty(&manager_list)) {
00135 futex_up(&psthread_futex);
00136 async_create_manager();
00137 futex_down(&psthread_futex);
00138 }
00139 }
00140
00141 if (ctype != PS_FROM_DEAD) {
00142
00143 srcpt = __tcb_get()->pst_data;
00144 if (!context_save(&srcpt->ctx)) {
00145 if (serialization_count)
00146 srcpt->flags &= ~PSTHREAD_SERIALIZED;
00147 return 1;
00148 }
00149
00150
00151 if (ctype == PS_PREEMPT)
00152 list_append(&srcpt->link, &ready_list);
00153 else if (ctype == PS_FROM_MANAGER) {
00154 list_append(&srcpt->link, &manager_list);
00155 threads_in_manager--;
00156 }
00157
00158 } else
00159 srcpt = NULL;
00160
00161
00162 if (ctype == PS_TO_MANAGER || ctype == PS_FROM_DEAD) {
00163 dstpt = list_get_instance(manager_list.next,psthread_data_t, link);
00164 if (serialization_count && ctype == PS_TO_MANAGER) {
00165 serialized_threads++;
00166 srcpt->flags |= PSTHREAD_SERIALIZED;
00167 }
00168 threads_in_manager++;
00169 } else {
00170 if (!list_empty(&serialized_list)) {
00171 dstpt = list_get_instance(serialized_list.next, psthread_data_t, link);
00172 serialized_threads--;
00173 } else
00174 dstpt = list_get_instance(ready_list.next, psthread_data_t, link);
00175 }
00176 list_remove(&dstpt->link);
00177
00178 futex_up(&psthread_futex);
00179 context_restore(&dstpt->ctx);
00180
00181 ret_0:
00182 futex_up(&psthread_futex);
00183 return retval;
00184 }
00185
00192 int psthread_join(pstid_t psthrid)
00193 {
00194 volatile psthread_data_t *pt;
00195 volatile int retval;
00196
00197
00198 pt = (psthread_data_t *) psthrid;
00199
00200
00201 printf("join unsupported\n");
00202 _exit(1);
00203
00204 retval = pt->retval;
00205
00206 free(pt->stack);
00207 psthread_teardown((void *)pt);
00208
00209 return retval;
00210 }
00211
00220 pstid_t psthread_create(int (*func)(void *), void *arg)
00221 {
00222 psthread_data_t *pt;
00223
00224 pt = psthread_setup();
00225 if (!pt)
00226 return 0;
00227 pt->stack = (char *) malloc(PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize());
00228
00229 if (!pt->stack) {
00230 psthread_teardown(pt);
00231 return 0;
00232 }
00233
00234 pt->arg= arg;
00235 pt->func = func;
00236 pt->finished = 0;
00237 pt->waiter = NULL;
00238 pt->flags = 0;
00239
00240 context_save(&pt->ctx);
00241 context_set(&pt->ctx, FADDR(psthread_main), pt->stack, PSTHREAD_INITIAL_STACK_PAGES_NO*getpagesize(), pt->tcb);
00242
00243 return (pstid_t )pt;
00244 }
00245
00247 void psthread_add_ready(pstid_t psthrid)
00248 {
00249 psthread_data_t *pt;
00250
00251 pt = (psthread_data_t *) psthrid;
00252 futex_down(&psthread_futex);
00253 if ((pt->flags & PSTHREAD_SERIALIZED))
00254 list_append(&pt->link, &serialized_list);
00255 else
00256 list_append(&pt->link, &ready_list);
00257 futex_up(&psthread_futex);
00258 }
00259
00261 void psthread_add_manager(pstid_t psthrid)
00262 {
00263 psthread_data_t *pt;
00264
00265 pt = (psthread_data_t *) psthrid;
00266
00267 futex_down(&psthread_futex);
00268 list_append(&pt->link, &manager_list);
00269 futex_up(&psthread_futex);
00270 }
00271
00273 void psthread_remove_manager()
00274 {
00275 futex_down(&psthread_futex);
00276 if (list_empty(&manager_list)) {
00277 futex_up(&psthread_futex);
00278 return;
00279 }
00280 list_remove(manager_list.next);
00281 futex_up(&psthread_futex);
00282 }
00283
00285 pstid_t psthread_get_id(void)
00286 {
00287 return (pstid_t)__tcb_get()->pst_data;
00288 }
00289
00298 void psthread_inc_sercount(void)
00299 {
00300 serialization_count++;
00301 }
00302
00303 void psthread_dec_sercount(void)
00304 {
00305 serialization_count--;
00306 }
00307
00308