Changeset cf3aee19 in mainline for uspace/lib/c/generic/fibril.c


Ignore:
Timestamp:
2015-06-17T23:45:24Z (9 years ago)
Author:
Michal Koutný <xm.koutny+hos@…>
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.
Message:

Sync with mainline

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/fibril.c

    rfc7bf19 rcf3aee19  
    5757/**
    5858 * This futex serializes access to ready_list,
    59  * serialized_list and manager_list.
     59 * manager_list and fibril_list.
    6060 */
    6161static futex_t fibril_futex = FUTEX_INITIALIZER;
    6262
    6363static LIST_INITIALIZE(ready_list);
    64 static LIST_INITIALIZE(serialized_list);
    6564static LIST_INITIALIZE(manager_list);
    6665static 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;
    7966
    8067/** Function that spans the whole life-cycle of a fibril.
     
    9683        fibril->retval = fibril->func(fibril->arg);
    9784       
     85        futex_down(&async_futex);
    9886        fibril_switch(FIBRIL_FROM_DEAD);
    9987        /* Not reached */
     
    126114       
    127115        fibril->waits_for = NULL;
     116
     117        futex_lock(&fibril_futex);
    128118        list_append(&fibril->all_link, &fibril_list);
     119        futex_unlock(&fibril_futex);
    129120       
    130121        return fibril;
    131122}
    132123
    133 void fibril_teardown(fibril_t *fibril)
    134 {
     124void fibril_teardown(fibril_t *fibril, bool locked)
     125{       
     126        if (!locked)
     127                futex_lock(&fibril_futex);
    135128        list_remove(&fibril->all_link);
     129        if (!locked)
     130                futex_unlock(&fibril_futex);
    136131        tls_free(fibril->tcb);
    137132        free(fibril);
     
    140135/** Switch from the current fibril.
    141136 *
    142  * If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be
    143  * held.
     137 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
     138 * be held.
    144139 *
    145140 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    153148int fibril_switch(fibril_switch_type_t stype)
    154149{
    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;
    173158                }
    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 */
    178166                while (list_empty(&manager_list)) {
    179167                        futex_unlock(&fibril_futex);
     
    181169                        futex_lock(&fibril_futex);
    182170                }
     171                break;
    183172        }
    184173       
     
    188177                /* Save current state */
    189178                if (!context_save(&srcf->ctx)) {
    190                         if (serialization_count)
    191                                 srcf->flags &= ~FIBRIL_SERIALIZED;
    192                        
    193179                        if (srcf->clean_after_me) {
    194180                                /*
     
    208194                                        as_area_destroy(stack);
    209195                                }
    210                                 fibril_teardown(srcf->clean_after_me);
     196                                fibril_teardown(srcf->clean_after_me, true);
    211197                                srcf->clean_after_me = NULL;
    212198                        }
     
    215201                }
    216202               
    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:
    219206                        list_append(&srcf->link, &ready_list);
    220                 else if (stype == FIBRIL_FROM_MANAGER) {
     207                        break;
     208                case FIBRIL_FROM_MANAGER:
    221209                        list_append(&srcf->link, &manager_list);
    222                         threads_in_manager--;
    223                 } else {
     210                        break;
     211                default:
     212                        assert(stype == FIBRIL_TO_MANAGER);
     213
    224214                        /*
    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.
    228217                         */
     218                        break;
    229219                }
    230220        }
    231221       
     222        fibril_t *dstf;
     223
    232224        /* 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:
    235228                dstf = list_get_instance(list_first(&manager_list), fibril_t,
    236229                    link);
    237                 if (serialization_count && stype == FIBRIL_TO_MANAGER) {
    238                         serialized_threads++;
    239                         srcf->flags |= FIBRIL_SERIALIZED;
    240                 }
    241                 threads_in_manager++;
    242230               
    243231                if (stype == FIBRIL_FROM_DEAD)
    244232                        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
    255240        list_remove(&dstf->link);
    256241       
     
    265250        context_restore(&dstf->ctx);
    266251        /* not reached */
    267        
    268 ret_0:
    269         futex_unlock(&fibril_futex);
    270         return retval;
    271252}
    272253
     
    294275            AS_AREA_LATE_RESERVE);
    295276        if (fibril->stack == (void *) -1) {
    296                 fibril_teardown(fibril);
     277                fibril_teardown(fibril, false);
    297278                return 0;
    298279        }
     
    321302       
    322303        as_area_destroy(fibril->stack);
    323         fibril_teardown(fibril);
     304        fibril_teardown(fibril, false);
    324305}
    325306
     
    335316       
    336317        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);
    343319        futex_unlock(&fibril_futex);
    344320}
     
    363339{
    364340        futex_lock(&fibril_futex);
    365        
    366341        if (!list_empty(&manager_list))
    367342                list_remove(list_first(&manager_list));
    368        
    369343        futex_unlock(&fibril_futex);
    370344}
     
    380354}
    381355
    382 /** Disable preemption
    383  *
    384  * If the fibril wants to send several message in a row and does not want to be
    385  * preempted, it should start async_serialize_start() in the beginning of
    386  * communication and async_serialize_end() in the end. If it is a true
    387  * multithreaded application, it should protect the communication channel by a
    388  * 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 
    407356/** @}
    408357 */
Note: See TracChangeset for help on using the changeset viewer.