Changes in uspace/lib/c/generic/fibril.c [6aeca0d:eceff5f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/fibril.c
r6aeca0d receff5f 50 50 #include <async.h> 51 51 52 #ifdef FUTEX_UPGRADABLE53 #include <rcu.h>54 #endif55 56 52 /** 57 53 * This futex serializes access to ready_list, 58 * manager_list and fibril_list.59 */ 60 static futex_t fibril_futex = FUTEX_INITIALIZER;54 * serialized_list and manager_list. 55 */ 56 static atomic_t fibril_futex = FUTEX_INITIALIZER; 61 57 62 58 static LIST_INITIALIZE(ready_list); 59 static LIST_INITIALIZE(serialized_list); 63 60 static LIST_INITIALIZE(manager_list); 64 static LIST_INITIALIZE(fibril_list); 61 62 /** Number of threads that are executing a manager fibril. */ 63 static int threads_in_manager; 64 65 /** 66 * Number of threads that are executing a manager fibril 67 * and are serialized. Protected by async_futex. 68 */ 69 static int serialized_threads; 70 71 /** Fibril-local count of serialization. If > 0, we must not preempt */ 72 static fibril_local int serialization_count; 65 73 66 74 /** Function that spans the whole life-cycle of a fibril. … … 74 82 { 75 83 fibril_t *fibril = __tcb_get()->fibril_data; 76 77 #ifdef FUTEX_UPGRADABLE78 rcu_register_fibril();79 #endif80 84 81 85 /* Call the implementing function. */ 82 86 fibril->retval = fibril->func(fibril->arg); 83 87 84 futex_down(&async_futex);85 88 fibril_switch(FIBRIL_FROM_DEAD); 86 89 /* Not reached */ … … 113 116 114 117 fibril->waits_for = NULL; 115 116 fibril->switches = 0;117 118 /*119 * We are called before __tcb_set(), so we need to use120 * futex_down/up() instead of futex_lock/unlock() that121 * may attempt to access TLS.122 */123 futex_down(&fibril_futex);124 list_append(&fibril->all_link, &fibril_list);125 futex_up(&fibril_futex);126 118 127 119 return fibril; 128 120 } 129 121 130 void fibril_teardown(fibril_t *fibril, bool locked) 131 { 132 if (!locked) 133 futex_lock(&fibril_futex); 134 list_remove(&fibril->all_link); 135 if (!locked) 136 futex_unlock(&fibril_futex); 122 void fibril_teardown(fibril_t *fibril) 123 { 137 124 tls_free(fibril->tcb); 138 125 free(fibril); … … 141 128 /** Switch from the current fibril. 142 129 * 143 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must144 * beheld.130 * If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be 131 * held. 145 132 * 146 133 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, … … 154 141 int fibril_switch(fibril_switch_type_t stype) 155 142 { 156 futex_lock(&fibril_futex); 157 158 switch (stype) { 159 case FIBRIL_PREEMPT: 160 case FIBRIL_FROM_MANAGER: 161 if (list_empty(&ready_list)) { 162 futex_unlock(&fibril_futex); 163 return 0; 164 } 165 break; 166 case FIBRIL_TO_MANAGER: 167 case FIBRIL_FROM_DEAD: 168 /* Make sure the async_futex is held. */ 169 assert((atomic_signed_t) async_futex.val.count <= 0); 170 171 /* If we are going to manager and none exists, create it */ 143 int retval = 0; 144 145 futex_down(&fibril_futex); 146 147 if (stype == FIBRIL_PREEMPT && list_empty(&ready_list)) 148 goto ret_0; 149 150 if (stype == FIBRIL_FROM_MANAGER) { 151 if ((list_empty(&ready_list)) && (list_empty(&serialized_list))) 152 goto ret_0; 153 154 /* 155 * Do not preempt if there is not enough threads to run the 156 * ready fibrils which are not serialized. 157 */ 158 if ((list_empty(&serialized_list)) && 159 (threads_in_manager <= serialized_threads)) { 160 goto ret_0; 161 } 162 } 163 164 /* If we are going to manager and none exists, create it */ 165 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 172 166 while (list_empty(&manager_list)) { 173 futex_u nlock(&fibril_futex);167 futex_up(&fibril_futex); 174 168 async_create_manager(); 175 futex_lock(&fibril_futex); 176 } 177 break; 169 futex_down(&fibril_futex); 170 } 178 171 } 179 172 … … 183 176 /* Save current state */ 184 177 if (!context_save(&srcf->ctx)) { 178 if (serialization_count) 179 srcf->flags &= ~FIBRIL_SERIALIZED; 180 185 181 if (srcf->clean_after_me) { 186 182 /* … … 200 196 as_area_destroy(stack); 201 197 } 202 fibril_teardown(srcf->clean_after_me , true);198 fibril_teardown(srcf->clean_after_me); 203 199 srcf->clean_after_me = NULL; 204 200 } 205 201 206 return 1; /* futex_u nlockalready done here */202 return 1; /* futex_up already done here */ 207 203 } 208 204 209 /* Put the current fibril into the correct run list */ 210 switch (stype) { 211 case FIBRIL_PREEMPT: 205 /* Save myself to the correct run list */ 206 if (stype == FIBRIL_PREEMPT) 212 207 list_append(&srcf->link, &ready_list); 213 break; 214 case FIBRIL_FROM_MANAGER: 208 else if (stype == FIBRIL_FROM_MANAGER) { 215 209 list_append(&srcf->link, &manager_list); 216 break; 217 default: 218 assert(stype == FIBRIL_TO_MANAGER); 219 220 srcf->switches++; 221 210 threads_in_manager--; 211 } else { 222 212 /* 223 * Don't put the current fibril into any list, it should 224 * already be somewhere, or it will be lost. 213 * If stype == FIBRIL_TO_MANAGER, don't put ourselves to 214 * any list, we should already be somewhere, or we will 215 * be lost. 225 216 */ 226 break;227 228 }229 217 } 218 } 219 220 /* Choose a new fibril to run */ 230 221 fibril_t *dstf; 231 232 /* Choose a new fibril to run */ 233 switch (stype) { 234 case FIBRIL_TO_MANAGER: 235 case FIBRIL_FROM_DEAD: 222 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 236 223 dstf = list_get_instance(list_first(&manager_list), fibril_t, 237 224 link); 225 if (serialization_count && stype == FIBRIL_TO_MANAGER) { 226 serialized_threads++; 227 srcf->flags |= FIBRIL_SERIALIZED; 228 } 229 threads_in_manager++; 238 230 239 231 if (stype == FIBRIL_FROM_DEAD) 240 232 dstf->clean_after_me = srcf; 241 break; 242 default: 243 dstf = list_get_instance(list_first(&ready_list), fibril_t, 244 link); 245 break; 246 } 247 233 } else { 234 if (!list_empty(&serialized_list)) { 235 dstf = list_get_instance(list_first(&serialized_list), 236 fibril_t, link); 237 serialized_threads--; 238 } else { 239 dstf = list_get_instance(list_first(&ready_list), 240 fibril_t, link); 241 } 242 } 248 243 list_remove(&dstf->link); 249 244 250 futex_unlock(&fibril_futex); 251 252 #ifdef FUTEX_UPGRADABLE 253 if (stype == FIBRIL_FROM_DEAD) { 254 rcu_deregister_fibril(); 255 } 256 #endif 257 245 futex_up(&fibril_futex); 258 246 context_restore(&dstf->ctx); 259 247 /* not reached */ 248 249 ret_0: 250 futex_up(&fibril_futex); 251 return retval; 260 252 } 261 253 … … 279 271 size_t stack_size = (stksz == FIBRIL_DFLT_STK_SIZE) ? 280 272 stack_size_get() : stksz; 281 fibril->stack = as_area_create( AS_AREA_ANY, stack_size,273 fibril->stack = as_area_create((void *) -1, stack_size, 282 274 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | AS_AREA_GUARD | 283 AS_AREA_LATE_RESERVE , AS_AREA_UNPAGED);275 AS_AREA_LATE_RESERVE); 284 276 if (fibril->stack == (void *) -1) { 285 fibril_teardown(fibril , false);277 fibril_teardown(fibril); 286 278 return 0; 287 279 } … … 310 302 311 303 as_area_destroy(fibril->stack); 312 fibril_teardown(fibril , false);304 fibril_teardown(fibril); 313 305 } 314 306 … … 323 315 fibril_t *fibril = (fibril_t *) fid; 324 316 325 futex_lock(&fibril_futex); 326 list_append(&fibril->link, &ready_list); 327 futex_unlock(&fibril_futex); 317 futex_down(&fibril_futex); 318 319 if ((fibril->flags & FIBRIL_SERIALIZED)) 320 list_append(&fibril->link, &serialized_list); 321 else 322 list_append(&fibril->link, &ready_list); 323 324 futex_up(&fibril_futex); 328 325 } 329 326 … … 338 335 fibril_t *fibril = (fibril_t *) fid; 339 336 340 futex_ lock(&fibril_futex);337 futex_down(&fibril_futex); 341 338 list_append(&fibril->link, &manager_list); 342 futex_u nlock(&fibril_futex);339 futex_up(&fibril_futex); 343 340 } 344 341 … … 346 343 void fibril_remove_manager(void) 347 344 { 348 futex_lock(&fibril_futex); 345 futex_down(&fibril_futex); 346 349 347 if (!list_empty(&manager_list)) 350 348 list_remove(list_first(&manager_list)); 351 futex_unlock(&fibril_futex); 349 350 futex_up(&fibril_futex); 352 351 } 353 352 … … 362 361 } 363 362 363 /** Disable preemption 364 * 365 * If the fibril wants to send several message in a row and does not want to be 366 * preempted, it should start async_serialize_start() in the beginning of 367 * communication and async_serialize_end() in the end. If it is a true 368 * multithreaded application, it should protect the communication channel by a 369 * futex as well. 370 * 371 */ 372 void fibril_inc_sercount(void) 373 { 374 serialization_count++; 375 } 376 377 /** Restore the preemption counter to the previous state. */ 378 void fibril_dec_sercount(void) 379 { 380 serialization_count--; 381 } 382 383 int fibril_get_sercount(void) 384 { 385 return serialization_count; 386 } 387 364 388 /** @} 365 389 */
Note:
See TracChangeset
for help on using the changeset viewer.