Changeset 04803bf in mainline for uspace/lib/c/generic/fibril.c
- Timestamp:
- 2011-03-21T22:00:17Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 143932e3
- Parents:
- b50b5af2 (diff), 7308e84 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/fibril.c
rb50b5af2 r04803bf 41 41 #include <unistd.h> 42 42 #include <stdio.h> 43 #include <arch/barrier.h> 43 44 #include <libarch/faddr.h> 44 45 #include <futex.h> … … 47 48 48 49 #ifndef FIBRIL_INITIAL_STACK_PAGES_NO 49 #define FIBRIL_INITIAL_STACK_PAGES_NO150 #define FIBRIL_INITIAL_STACK_PAGES_NO 1 50 51 #endif 51 52 52 53 /** 53 * This futex serializes access to ready_list, serialized_list and manager_list. 54 */ 54 * This futex serializes access to ready_list, 55 * serialized_list and manager_list. 56 */ 55 57 static atomic_t fibril_futex = FUTEX_INITIALIZER; 56 58 … … 59 61 static LIST_INITIALIZE(manager_list); 60 62 61 static void fibril_main(void);62 63 63 /** Number of threads that are executing a manager fibril. */ 64 64 static int threads_in_manager; 65 /** Number of threads that are executing a manager fibril and are serialized. */ 66 static int serialized_threads; /* Protected by async_futex */ 65 66 /** 67 * Number of threads that are executing a manager fibril 68 * and are serialized. Protected by async_futex. 69 */ 70 static int serialized_threads; 71 67 72 /** Fibril-local count of serialization. If > 0, we must not preempt */ 68 73 static fibril_local int serialization_count; 69 70 /** Setup fibril information into TCB structure */71 fibril_t *fibril_setup(void)72 {73 fibril_t *f;74 tcb_t *tcb;75 76 tcb = __make_tls();77 if (!tcb)78 return NULL;79 80 f = malloc(sizeof(fibril_t));81 if (!f) {82 __free_tls(tcb);83 return NULL;84 }85 86 tcb->fibril_data = f;87 f->tcb = tcb;88 89 f->func = NULL;90 f->arg = NULL;91 f->stack = NULL;92 f->clean_after_me = NULL;93 f->retval = 0;94 f->flags = 0;95 96 return f;97 }98 99 void fibril_teardown(fibril_t *f)100 {101 __free_tls(f->tcb);102 free(f);103 }104 74 105 75 /** Function that spans the whole life-cycle of a fibril. … … 108 78 * the fibril logic is called. After its return, the return value is saved. 109 79 * The fibril then switches to another fibril, which cleans up after it. 110 */ 111 void fibril_main(void) 112 { 113 fibril_t *f = __tcb_get()->fibril_data; 114 80 * 81 */ 82 static void fibril_main(void) 83 { 84 fibril_t *fibril = __tcb_get()->fibril_data; 85 115 86 /* Call the implementing function. */ 116 f ->retval = f->func(f->arg);117 87 fibril->retval = fibril->func(fibril->arg); 88 118 89 fibril_switch(FIBRIL_FROM_DEAD); 119 /* not reached */ 90 /* Not reached */ 91 } 92 93 /** Setup fibril information into TCB structure 94 * 95 */ 96 fibril_t *fibril_setup(void) 97 { 98 tcb_t *tcb = __make_tls(); 99 if (!tcb) 100 return NULL; 101 102 fibril_t *fibril = malloc(sizeof(fibril_t)); 103 if (!fibril) { 104 __free_tls(tcb); 105 return NULL; 106 } 107 108 tcb->fibril_data = fibril; 109 fibril->tcb = tcb; 110 111 fibril->func = NULL; 112 fibril->arg = NULL; 113 fibril->stack = NULL; 114 fibril->clean_after_me = NULL; 115 fibril->retval = 0; 116 fibril->flags = 0; 117 118 fibril->waits_for = NULL; 119 120 return fibril; 121 } 122 123 void fibril_teardown(fibril_t *fibril) 124 { 125 __free_tls(fibril->tcb); 126 free(fibril); 120 127 } 121 128 … … 125 132 * held. 126 133 * 127 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, 128 * FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter 129 * describes the circumstances of the switch. 130 * @return Return 0 if there is no ready fibril, 131 * return 1 otherwise. 134 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, 135 * FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter 136 * describes the circumstances of the switch. 137 * 138 * @return 0 if there is no ready fibril, 139 * @return 1 otherwise. 140 * 132 141 */ 133 142 int fibril_switch(fibril_switch_type_t stype) 134 143 { 135 fibril_t *srcf, *dstf;136 144 int retval = 0; 137 145 138 146 futex_down(&fibril_futex); 139 147 140 148 if (stype == FIBRIL_PREEMPT && list_empty(&ready_list)) 141 149 goto ret_0; 142 150 143 151 if (stype == FIBRIL_FROM_MANAGER) { 144 if ( list_empty(&ready_list) && list_empty(&serialized_list))152 if ((list_empty(&ready_list)) && (list_empty(&serialized_list))) 145 153 goto ret_0; 154 146 155 /* 147 156 * Do not preempt if there is not enough threads to run the 148 157 * ready fibrils which are not serialized. 149 158 */ 150 if ( list_empty(&serialized_list) &&151 threads_in_manager <= serialized_threads) {159 if ((list_empty(&serialized_list)) && 160 (threads_in_manager <= serialized_threads)) { 152 161 goto ret_0; 153 162 } 154 163 } 164 155 165 /* If we are going to manager and none exists, create it */ 156 if ( stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) {166 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 157 167 while (list_empty(&manager_list)) { 158 168 futex_up(&fibril_futex); … … 162 172 } 163 173 164 srcf = __tcb_get()->fibril_data;174 fibril_t *srcf = __tcb_get()->fibril_data; 165 175 if (stype != FIBRIL_FROM_DEAD) { 176 166 177 /* Save current state */ 167 178 if (!context_save(&srcf->ctx)) { 168 179 if (serialization_count) 169 180 srcf->flags &= ~FIBRIL_SERIALIZED; 181 170 182 if (srcf->clean_after_me) { 171 183 /* … … 173 185 * restored context here. 174 186 */ 175 void *stack = srcf->clean_after_me->stack; 187 void *stack = srcf->clean_after_me->stack; 176 188 if (stack) { 177 189 /* … … 188 200 srcf->clean_after_me = NULL; 189 201 } 202 190 203 return 1; /* futex_up already done here */ 191 204 } 192 205 193 206 /* Save myself to the correct run list */ 194 207 if (stype == FIBRIL_PREEMPT) … … 197 210 list_append(&srcf->link, &manager_list); 198 211 threads_in_manager--; 199 } else { 212 } else { 200 213 /* 201 214 * If stype == FIBRIL_TO_MANAGER, don't put ourselves to … … 207 220 208 221 /* Choose a new fibril to run */ 209 if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) { 222 fibril_t *dstf; 223 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 210 224 dstf = list_get_instance(manager_list.next, fibril_t, link); 211 225 if (serialization_count && stype == FIBRIL_TO_MANAGER) { … … 214 228 } 215 229 threads_in_manager++; 216 230 217 231 if (stype == FIBRIL_FROM_DEAD) 218 232 dstf->clean_after_me = srcf; … … 228 242 } 229 243 list_remove(&dstf->link); 230 244 231 245 futex_up(&fibril_futex); 232 246 context_restore(&dstf->ctx); 233 247 /* not reached */ 234 248 235 249 ret_0: 236 250 futex_up(&fibril_futex); … … 240 254 /** Create a new fibril. 241 255 * 242 * @param func Implementing function of the new fibril. 243 * @param arg Argument to pass to func. 244 * 245 * @return Return 0 on failure or TLS of the new fibril. 256 * @param func Implementing function of the new fibril. 257 * @param arg Argument to pass to func. 258 * 259 * @return 0 on failure or TLS of the new fibril. 260 * 246 261 */ 247 262 fid_t fibril_create(int (*func)(void *), void *arg) 248 263 { 249 fibril_t *f ;250 251 f = fibril_setup();252 if ( !f)264 fibril_t *fibril; 265 266 fibril = fibril_setup(); 267 if (fibril == NULL) 253 268 return 0; 254 f->stack = (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * 255 getpagesize()); 256 if (!f->stack) { 257 fibril_teardown(f); 269 270 fibril->stack = 271 (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize()); 272 if (!fibril->stack) { 273 fibril_teardown(fibril); 258 274 return 0; 259 275 } 260 276 261 f ->func = func;262 f ->arg = arg;263 264 context_save(&f ->ctx);265 context_set(&f ->ctx, FADDR(fibril_main), f->stack,266 FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), f ->tcb);267 268 return (fid_t) f ;277 fibril->func = func; 278 fibril->arg = arg; 279 280 context_save(&fibril->ctx); 281 context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack, 282 FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), fibril->tcb); 283 284 return (fid_t) fibril; 269 285 } 270 286 271 287 /** Add a fibril to the ready list. 272 288 * 273 * @param fid Pointer to the fibril structure of the fibril to be 274 * added. 289 * @param fid Pointer to the fibril structure of the fibril to be 290 * added. 291 * 275 292 */ 276 293 void fibril_add_ready(fid_t fid) 277 294 { 278 fibril_t *f; 279 280 f = (fibril_t *) fid; 295 fibril_t *fibril = (fibril_t *) fid; 296 281 297 futex_down(&fibril_futex); 282 if ((f->flags & FIBRIL_SERIALIZED)) 283 list_append(&f->link, &serialized_list); 298 299 if ((fibril->flags & FIBRIL_SERIALIZED)) 300 list_append(&fibril->link, &serialized_list); 284 301 else 285 list_append(&f->link, &ready_list); 302 list_append(&fibril->link, &ready_list); 303 286 304 futex_up(&fibril_futex); 287 305 } … … 289 307 /** Add a fibril to the manager list. 290 308 * 291 * @param fid Pointer to the fibril structure of the fibril to be 292 * added. 309 * @param fid Pointer to the fibril structure of the fibril to be 310 * added. 311 * 293 312 */ 294 313 void fibril_add_manager(fid_t fid) 295 314 { 296 fibril_t *f; 297 298 f = (fibril_t *) fid; 299 315 fibril_t *fibril = (fibril_t *) fid; 316 300 317 futex_down(&fibril_futex); 301 list_append(&f ->link, &manager_list);318 list_append(&fibril->link, &manager_list); 302 319 futex_up(&fibril_futex); 303 320 } … … 307 324 { 308 325 futex_down(&fibril_futex); 309 if (list_empty(&manager_list)) { 310 futex_up(&fibril_futex); 311 return; 312 } 313 list_remove(manager_list.next); 326 327 if (!list_empty(&manager_list)) 328 list_remove(manager_list.next); 329 314 330 futex_up(&fibril_futex); 315 331 } … … 345 361 } 346 362 363 int fibril_get_sercount(void) 364 { 365 return serialization_count; 366 } 367 347 368 /** @} 348 369 */
Note:
See TracChangeset
for help on using the changeset viewer.