Changeset cf3aee19 in mainline for uspace/lib/c/generic/fibril.c
- Timestamp:
- 2015-06-17T23:45:24Z (9 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 523b17a
- Parents:
- fc7bf19 (diff), 2654afb (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 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/fibril.c
rfc7bf19 rcf3aee19 57 57 /** 58 58 * This futex serializes access to ready_list, 59 * serialized_list and manager_list.59 * manager_list and fibril_list. 60 60 */ 61 61 static futex_t fibril_futex = FUTEX_INITIALIZER; 62 62 63 63 static LIST_INITIALIZE(ready_list); 64 static LIST_INITIALIZE(serialized_list);65 64 static LIST_INITIALIZE(manager_list); 66 65 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 fibril73 * 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;79 66 80 67 /** Function that spans the whole life-cycle of a fibril. … … 96 83 fibril->retval = fibril->func(fibril->arg); 97 84 85 futex_down(&async_futex); 98 86 fibril_switch(FIBRIL_FROM_DEAD); 99 87 /* Not reached */ … … 126 114 127 115 fibril->waits_for = NULL; 116 117 futex_lock(&fibril_futex); 128 118 list_append(&fibril->all_link, &fibril_list); 119 futex_unlock(&fibril_futex); 129 120 130 121 return fibril; 131 122 } 132 123 133 void fibril_teardown(fibril_t *fibril) 134 { 124 void fibril_teardown(fibril_t *fibril, bool locked) 125 { 126 if (!locked) 127 futex_lock(&fibril_futex); 135 128 list_remove(&fibril->all_link); 129 if (!locked) 130 futex_unlock(&fibril_futex); 136 131 tls_free(fibril->tcb); 137 132 free(fibril); … … 140 135 /** Switch from the current fibril. 141 136 * 142 * If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be143 * held.137 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must 138 * be held. 144 139 * 145 140 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER, … … 153 148 int fibril_switch(fibril_switch_type_t stype) 154 149 { 155 int retval = 0; 156 157 futex_lock(&fibril_futex); 158 159 if (stype == FIBRIL_PREEMPT && list_empty(&ready_list)) 160 goto ret_0; 161 162 if (stype == FIBRIL_FROM_MANAGER) { 163 if ((list_empty(&ready_list)) && (list_empty(&serialized_list))) 164 goto ret_0; 165 166 /* 167 * Do not preempt if there is not enough threads to run the 168 * ready fibrils which are not serialized. 169 */ 170 if ((list_empty(&serialized_list)) && 171 (threads_in_manager <= serialized_threads)) { 172 goto ret_0; 150 futex_lock(&fibril_futex); 151 152 switch (stype) { 153 case FIBRIL_PREEMPT: 154 case FIBRIL_FROM_MANAGER: 155 if (list_empty(&ready_list)) { 156 futex_unlock(&fibril_futex); 157 return 0; 173 158 } 174 } 175 176 /* If we are going to manager and none exists, create it */ 177 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 159 break; 160 case FIBRIL_TO_MANAGER: 161 case FIBRIL_FROM_DEAD: 162 /* Make sure the async_futex is held. */ 163 assert((atomic_signed_t) async_futex.val.count <= 0); 164 165 /* If we are going to manager and none exists, create it */ 178 166 while (list_empty(&manager_list)) { 179 167 futex_unlock(&fibril_futex); … … 181 169 futex_lock(&fibril_futex); 182 170 } 171 break; 183 172 } 184 173 … … 188 177 /* Save current state */ 189 178 if (!context_save(&srcf->ctx)) { 190 if (serialization_count)191 srcf->flags &= ~FIBRIL_SERIALIZED;192 193 179 if (srcf->clean_after_me) { 194 180 /* … … 208 194 as_area_destroy(stack); 209 195 } 210 fibril_teardown(srcf->clean_after_me );196 fibril_teardown(srcf->clean_after_me, true); 211 197 srcf->clean_after_me = NULL; 212 198 } … … 215 201 } 216 202 217 /* Save myself to the correct run list */ 218 if (stype == FIBRIL_PREEMPT) 203 /* Put the current fibril into the correct run list */ 204 switch (stype) { 205 case FIBRIL_PREEMPT: 219 206 list_append(&srcf->link, &ready_list); 220 else if (stype == FIBRIL_FROM_MANAGER) { 207 break; 208 case FIBRIL_FROM_MANAGER: 221 209 list_append(&srcf->link, &manager_list); 222 threads_in_manager--; 223 } else { 210 break; 211 default: 212 assert(stype == FIBRIL_TO_MANAGER); 213 224 214 /* 225 * If stype == FIBRIL_TO_MANAGER, don't put ourselves to 226 * any list, we should already be somewhere, or we will 227 * be lost. 215 * Don't put the current fibril into any list, it should 216 * already be somewhere, or it will be lost. 228 217 */ 218 break; 229 219 } 230 220 } 231 221 222 fibril_t *dstf; 223 232 224 /* Choose a new fibril to run */ 233 fibril_t *dstf; 234 if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) { 225 switch (stype) { 226 case FIBRIL_TO_MANAGER: 227 case FIBRIL_FROM_DEAD: 235 228 dstf = list_get_instance(list_first(&manager_list), fibril_t, 236 229 link); 237 if (serialization_count && stype == FIBRIL_TO_MANAGER) {238 serialized_threads++;239 srcf->flags |= FIBRIL_SERIALIZED;240 }241 threads_in_manager++;242 230 243 231 if (stype == FIBRIL_FROM_DEAD) 244 232 dstf->clean_after_me = srcf; 245 } else { 246 if (!list_empty(&serialized_list)) { 247 dstf = list_get_instance(list_first(&serialized_list), 248 fibril_t, link); 249 serialized_threads--; 250 } else { 251 dstf = list_get_instance(list_first(&ready_list), 252 fibril_t, link); 253 } 254 } 233 break; 234 default: 235 dstf = list_get_instance(list_first(&ready_list), fibril_t, 236 link); 237 break; 238 } 239 255 240 list_remove(&dstf->link); 256 241 … … 265 250 context_restore(&dstf->ctx); 266 251 /* not reached */ 267 268 ret_0:269 futex_unlock(&fibril_futex);270 return retval;271 252 } 272 253 … … 294 275 AS_AREA_LATE_RESERVE); 295 276 if (fibril->stack == (void *) -1) { 296 fibril_teardown(fibril );277 fibril_teardown(fibril, false); 297 278 return 0; 298 279 } … … 321 302 322 303 as_area_destroy(fibril->stack); 323 fibril_teardown(fibril );304 fibril_teardown(fibril, false); 324 305 } 325 306 … … 335 316 336 317 futex_lock(&fibril_futex); 337 338 if ((fibril->flags & FIBRIL_SERIALIZED)) 339 list_append(&fibril->link, &serialized_list); 340 else 341 list_append(&fibril->link, &ready_list); 342 318 list_append(&fibril->link, &ready_list); 343 319 futex_unlock(&fibril_futex); 344 320 } … … 363 339 { 364 340 futex_lock(&fibril_futex); 365 366 341 if (!list_empty(&manager_list)) 367 342 list_remove(list_first(&manager_list)); 368 369 343 futex_unlock(&fibril_futex); 370 344 } … … 380 354 } 381 355 382 /** Disable preemption383 *384 * If the fibril wants to send several message in a row and does not want to be385 * preempted, it should start async_serialize_start() in the beginning of386 * communication and async_serialize_end() in the end. If it is a true387 * multithreaded application, it should protect the communication channel by a388 * futex as well.389 *390 */391 void fibril_inc_sercount(void)392 {393 serialization_count++;394 }395 396 /** Restore the preemption counter to the previous state. */397 void fibril_dec_sercount(void)398 {399 serialization_count--;400 }401 402 int fibril_get_sercount(void)403 {404 return serialization_count;405 }406 407 356 /** @} 408 357 */
Note:
See TracChangeset
for help on using the changeset viewer.