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
00029
00036 #include <adt/list.h>
00037 #include <fibril.h>
00038 #include <thread.h>
00039 #include <tls.h>
00040 #include <malloc.h>
00041 #include <unistd.h>
00042 #include <stdio.h>
00043 #include <arch/barrier.h>
00044 #include <libarch/faddr.h>
00045 #include <futex.h>
00046 #include <assert.h>
00047 #include <async.h>
00048
00049 #ifndef FIBRIL_INITIAL_STACK_PAGES_NO
00050 #define FIBRIL_INITIAL_STACK_PAGES_NO 1
00051 #endif
00052
00057 static atomic_t fibril_futex = FUTEX_INITIALIZER;
00058
00059 static LIST_INITIALIZE(ready_list);
00060 static LIST_INITIALIZE(serialized_list);
00061 static LIST_INITIALIZE(manager_list);
00062
00064 static int threads_in_manager;
00065
00070 static int serialized_threads;
00071
00073 static fibril_local int serialization_count;
00074
00082 static void fibril_main(void)
00083 {
00084 fibril_t *fibril = __tcb_get()->fibril_data;
00085
00086
00087 fibril->retval = fibril->func(fibril->arg);
00088
00089 fibril_switch(FIBRIL_FROM_DEAD);
00090
00091 }
00092
00096 fibril_t *fibril_setup(void)
00097 {
00098 tcb_t *tcb = __make_tls();
00099 if (!tcb)
00100 return NULL;
00101
00102 fibril_t *fibril = malloc(sizeof(fibril_t));
00103 if (!fibril) {
00104 __free_tls(tcb);
00105 return NULL;
00106 }
00107
00108 tcb->fibril_data = fibril;
00109 fibril->tcb = tcb;
00110
00111 fibril->func = NULL;
00112 fibril->arg = NULL;
00113 fibril->stack = NULL;
00114 fibril->clean_after_me = NULL;
00115 fibril->retval = 0;
00116 fibril->flags = 0;
00117
00118 fibril->waits_for = NULL;
00119
00120 return fibril;
00121 }
00122
00123 void fibril_teardown(fibril_t *fibril)
00124 {
00125 __free_tls(fibril->tcb);
00126 free(fibril);
00127 }
00128
00142 int fibril_switch(fibril_switch_type_t stype)
00143 {
00144 int retval = 0;
00145
00146 futex_down(&fibril_futex);
00147
00148 if (stype == FIBRIL_PREEMPT && list_empty(&ready_list))
00149 goto ret_0;
00150
00151 if (stype == FIBRIL_FROM_MANAGER) {
00152 if ((list_empty(&ready_list)) && (list_empty(&serialized_list)))
00153 goto ret_0;
00154
00155
00156
00157
00158
00159 if ((list_empty(&serialized_list)) &&
00160 (threads_in_manager <= serialized_threads)) {
00161 goto ret_0;
00162 }
00163 }
00164
00165
00166 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
00167 while (list_empty(&manager_list)) {
00168 futex_up(&fibril_futex);
00169 async_create_manager();
00170 futex_down(&fibril_futex);
00171 }
00172 }
00173
00174 fibril_t *srcf = __tcb_get()->fibril_data;
00175 if (stype != FIBRIL_FROM_DEAD) {
00176
00177
00178 if (!context_save(&srcf->ctx)) {
00179 if (serialization_count)
00180 srcf->flags &= ~FIBRIL_SERIALIZED;
00181
00182 if (srcf->clean_after_me) {
00183
00184
00185
00186
00187 void *stack = srcf->clean_after_me->stack;
00188 if (stack) {
00189
00190
00191
00192
00193
00194
00195
00196
00197 free(stack);
00198 }
00199 fibril_teardown(srcf->clean_after_me);
00200 srcf->clean_after_me = NULL;
00201 }
00202
00203 return 1;
00204 }
00205
00206
00207 if (stype == FIBRIL_PREEMPT)
00208 list_append(&srcf->link, &ready_list);
00209 else if (stype == FIBRIL_FROM_MANAGER) {
00210 list_append(&srcf->link, &manager_list);
00211 threads_in_manager--;
00212 } else {
00213
00214
00215
00216
00217
00218 }
00219 }
00220
00221
00222 fibril_t *dstf;
00223 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
00224 dstf = list_get_instance(manager_list.next, fibril_t, link);
00225 if (serialization_count && stype == FIBRIL_TO_MANAGER) {
00226 serialized_threads++;
00227 srcf->flags |= FIBRIL_SERIALIZED;
00228 }
00229 threads_in_manager++;
00230
00231 if (stype == FIBRIL_FROM_DEAD)
00232 dstf->clean_after_me = srcf;
00233 } else {
00234 if (!list_empty(&serialized_list)) {
00235 dstf = list_get_instance(serialized_list.next, fibril_t,
00236 link);
00237 serialized_threads--;
00238 } else {
00239 dstf = list_get_instance(ready_list.next, fibril_t,
00240 link);
00241 }
00242 }
00243 list_remove(&dstf->link);
00244
00245 futex_up(&fibril_futex);
00246 context_restore(&dstf->ctx);
00247
00248
00249 ret_0:
00250 futex_up(&fibril_futex);
00251 return retval;
00252 }
00253
00262 fid_t fibril_create(int (*func)(void *), void *arg)
00263 {
00264 fibril_t *fibril;
00265
00266 fibril = fibril_setup();
00267 if (fibril == NULL)
00268 return 0;
00269
00270 fibril->stack =
00271 (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize());
00272 if (!fibril->stack) {
00273 fibril_teardown(fibril);
00274 return 0;
00275 }
00276
00277 fibril->func = func;
00278 fibril->arg = arg;
00279
00280 context_save(&fibril->ctx);
00281 context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
00282 FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), fibril->tcb);
00283
00284 return (fid_t) fibril;
00285 }
00286
00293 void fibril_add_ready(fid_t fid)
00294 {
00295 fibril_t *fibril = (fibril_t *) fid;
00296
00297 futex_down(&fibril_futex);
00298
00299 if ((fibril->flags & FIBRIL_SERIALIZED))
00300 list_append(&fibril->link, &serialized_list);
00301 else
00302 list_append(&fibril->link, &ready_list);
00303
00304 futex_up(&fibril_futex);
00305 }
00306
00313 void fibril_add_manager(fid_t fid)
00314 {
00315 fibril_t *fibril = (fibril_t *) fid;
00316
00317 futex_down(&fibril_futex);
00318 list_append(&fibril->link, &manager_list);
00319 futex_up(&fibril_futex);
00320 }
00321
00323 void fibril_remove_manager(void)
00324 {
00325 futex_down(&fibril_futex);
00326
00327 if (!list_empty(&manager_list))
00328 list_remove(manager_list.next);
00329
00330 futex_up(&fibril_futex);
00331 }
00332
00338 fid_t fibril_get_id(void)
00339 {
00340 return (fid_t) __tcb_get()->fibril_data;
00341 }
00342
00352 void fibril_inc_sercount(void)
00353 {
00354 serialization_count++;
00355 }
00356
00358 void fibril_dec_sercount(void)
00359 {
00360 serialization_count--;
00361 }
00362
00363 int fibril_get_sercount(void)
00364 {
00365 return serialization_count;
00366 }
00367