Changes in uspace/lib/c/generic/fibril.c [c170438:4d11204] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/fibril.c
rc170438 r4d11204 49 49 #include <assert.h> 50 50 #include <async.h> 51 #include <futex.h> 51 52 52 53 #ifdef FUTEX_UPGRADABLE … … 56 57 /** 57 58 * This futex serializes access to ready_list, 58 * manager_list and fibril_list.59 * serialized_list, manager_list and fibril_list. 59 60 */ 60 61 static futex_t fibril_futex = FUTEX_INITIALIZER; 61 62 62 63 static LIST_INITIALIZE(ready_list); 64 static LIST_INITIALIZE(serialized_list); 63 65 static LIST_INITIALIZE(manager_list); 64 66 static LIST_INITIALIZE(fibril_list); 67 68 /** Number of threads that are executing a manager fibril. */ 69 static int threads_in_manager; 70 71 /** 72 * Number of threads that are executing a manager fibril 73 * and are serialized. Protected by async_futex. 74 */ 75 static int serialized_threads; 76 77 /** Fibril-local count of serialization. If > 0, we must not preempt */ 78 static fibril_local int serialization_count; 65 79 66 80 /** Function that spans the whole life-cycle of a fibril. … … 82 96 fibril->retval = fibril->func(fibril->arg); 83 97 84 futex_down(&async_futex);85 98 fibril_switch(FIBRIL_FROM_DEAD); 86 99 /* Not reached */ … … 114 127 fibril->waits_for = NULL; 115 128 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); 129 futex_lock(&fibril_futex); 124 130 list_append(&fibril->all_link, &fibril_list); 125 futex_u p(&fibril_futex);131 futex_unlock(&fibril_futex); 126 132 127 133 return fibril; … … 141 147 /** Switch from the current fibril. 142 148 * 143 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must144 * beheld.149 * If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be 150 * held. 145 151 * 146 152 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, … … 154 160 int fibril_switch(fibril_switch_type_t stype) 155 161 { 162 int retval = 0; 163 156 164 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 */ 165 166 if (stype == FIBRIL_PREEMPT && list_empty(&ready_list)) 167 goto ret_0; 168 169 if (stype == FIBRIL_FROM_MANAGER) { 170 if ((list_empty(&ready_list)) && (list_empty(&serialized_list))) 171 goto ret_0; 172 173 /* 174 * Do not preempt if there is not enough threads to run the 175 * ready fibrils which are not serialized. 176 */ 177 if ((list_empty(&serialized_list)) && 178 (threads_in_manager <= serialized_threads)) { 179 goto ret_0; 180 } 181 } 182 183 /* If we are going to manager and none exists, create it */ 184 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 172 185 while (list_empty(&manager_list)) { 173 186 futex_unlock(&fibril_futex); … … 175 188 futex_lock(&fibril_futex); 176 189 } 177 break;178 190 } 179 191 … … 183 195 /* Save current state */ 184 196 if (!context_save(&srcf->ctx)) { 197 if (serialization_count) 198 srcf->flags &= ~FIBRIL_SERIALIZED; 199 185 200 if (srcf->clean_after_me) { 186 201 /* … … 207 222 } 208 223 209 /* Put the current fibril into the correct run list */ 210 switch (stype) { 211 case FIBRIL_PREEMPT: 224 /* Save myself to the correct run list */ 225 if (stype == FIBRIL_PREEMPT) 212 226 list_append(&srcf->link, &ready_list); 213 break; 214 case FIBRIL_FROM_MANAGER: 227 else if (stype == FIBRIL_FROM_MANAGER) { 215 228 list_append(&srcf->link, &manager_list); 216 break; 217 default: 218 assert(stype == FIBRIL_TO_MANAGER); 219 220 srcf->switches++; 221 229 threads_in_manager--; 230 } else { 222 231 /* 223 * Don't put the current fibril into any list, it should 224 * already be somewhere, or it will be lost. 232 * If stype == FIBRIL_TO_MANAGER, don't put ourselves to 233 * any list, we should already be somewhere, or we will 234 * be lost. 225 235 */ 226 break;227 228 }229 236 } 237 } 238 239 /* Choose a new fibril to run */ 230 240 fibril_t *dstf; 231 232 /* Choose a new fibril to run */ 233 switch (stype) { 234 case FIBRIL_TO_MANAGER: 235 case FIBRIL_FROM_DEAD: 241 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 236 242 dstf = list_get_instance(list_first(&manager_list), fibril_t, 237 243 link); 244 if (serialization_count && stype == FIBRIL_TO_MANAGER) { 245 serialized_threads++; 246 srcf->flags |= FIBRIL_SERIALIZED; 247 } 248 threads_in_manager++; 238 249 239 250 if (stype == FIBRIL_FROM_DEAD) 240 251 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 252 } else { 253 if (!list_empty(&serialized_list)) { 254 dstf = list_get_instance(list_first(&serialized_list), 255 fibril_t, link); 256 serialized_threads--; 257 } else { 258 dstf = list_get_instance(list_first(&ready_list), 259 fibril_t, link); 260 } 261 } 248 262 list_remove(&dstf->link); 249 263 … … 258 272 context_restore(&dstf->ctx); 259 273 /* not reached */ 274 275 ret_0: 276 futex_unlock(&fibril_futex); 277 return retval; 260 278 } 261 279 … … 324 342 325 343 futex_lock(&fibril_futex); 326 list_append(&fibril->link, &ready_list); 344 345 if ((fibril->flags & FIBRIL_SERIALIZED)) 346 list_append(&fibril->link, &serialized_list); 347 else 348 list_append(&fibril->link, &ready_list); 349 327 350 futex_unlock(&fibril_futex); 328 351 } … … 347 370 { 348 371 futex_lock(&fibril_futex); 372 349 373 if (!list_empty(&manager_list)) 350 374 list_remove(list_first(&manager_list)); 375 351 376 futex_unlock(&fibril_futex); 352 377 } … … 362 387 } 363 388 389 /** Disable preemption 390 * 391 * If the fibril wants to send several message in a row and does not want to be 392 * preempted, it should start async_serialize_start() in the beginning of 393 * communication and async_serialize_end() in the end. If it is a true 394 * multithreaded application, it should protect the communication channel by a 395 * futex as well. 396 * 397 */ 398 void fibril_inc_sercount(void) 399 { 400 serialization_count++; 401 } 402 403 /** Restore the preemption counter to the previous state. */ 404 void fibril_dec_sercount(void) 405 { 406 serialization_count--; 407 } 408 409 int fibril_get_sercount(void) 410 { 411 return serialization_count; 412 } 413 364 414 /** @} 365 415 */
Note:
See TracChangeset
for help on using the changeset viewer.