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