Ignore:
File:
1 edited

Legend:

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

    r4d11204 rc170438  
    4949#include <assert.h>
    5050#include <async.h>
    51 #include <futex.h>
    5251
    5352#ifdef FUTEX_UPGRADABLE
     
    5756/**
    5857 * This futex serializes access to ready_list,
    59  * serialized_list, manager_list and fibril_list.
     58 * manager_list and fibril_list.
    6059 */
    6160static futex_t fibril_futex = FUTEX_INITIALIZER;
    6261
    6362static LIST_INITIALIZE(ready_list);
    64 static LIST_INITIALIZE(serialized_list);
    6563static LIST_INITIALIZE(manager_list);
    6664static 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;
    7965
    8066/** Function that spans the whole life-cycle of a fibril.
     
    9682        fibril->retval = fibril->func(fibril->arg);
    9783       
     84        futex_down(&async_futex);
    9885        fibril_switch(FIBRIL_FROM_DEAD);
    9986        /* Not reached */
     
    127114        fibril->waits_for = NULL;
    128115
    129         futex_lock(&fibril_futex);
     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);
    130124        list_append(&fibril->all_link, &fibril_list);
    131         futex_unlock(&fibril_futex);
     125        futex_up(&fibril_futex);
    132126       
    133127        return fibril;
     
    147141/** Switch from the current fibril.
    148142 *
    149  * If calling with FIBRIL_TO_MANAGER parameter, the async_futex should be
    150  * held.
     143 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
     144 * be held.
    151145 *
    152146 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    160154int fibril_switch(fibril_switch_type_t stype)
    161155{
    162         int retval = 0;
    163        
    164156        futex_lock(&fibril_futex);
    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;
     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;
    180164                }
    181         }
    182        
    183         /* If we are going to manager and none exists, create it */
    184         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 */
    185172                while (list_empty(&manager_list)) {
    186173                        futex_unlock(&fibril_futex);
     
    188175                        futex_lock(&fibril_futex);
    189176                }
     177                break;
    190178        }
    191179       
     
    195183                /* Save current state */
    196184                if (!context_save(&srcf->ctx)) {
    197                         if (serialization_count)
    198                                 srcf->flags &= ~FIBRIL_SERIALIZED;
    199                        
    200185                        if (srcf->clean_after_me) {
    201186                                /*
     
    222207                }
    223208               
    224                 /* Save myself to the correct run list */
    225                 if (stype == FIBRIL_PREEMPT)
     209                /* Put the current fibril into the correct run list */
     210                switch (stype) {
     211                case FIBRIL_PREEMPT:
    226212                        list_append(&srcf->link, &ready_list);
    227                 else if (stype == FIBRIL_FROM_MANAGER) {
     213                        break;
     214                case FIBRIL_FROM_MANAGER:
    228215                        list_append(&srcf->link, &manager_list);
    229                         threads_in_manager--;
    230                 } else {
     216                        break;
     217                default:
     218                        assert(stype == FIBRIL_TO_MANAGER);
     219
     220                        srcf->switches++;
     221
    231222                        /*
    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.
     223                         * Don't put the current fibril into any list, it should
     224                         * already be somewhere, or it will be lost.
    235225                         */
     226                        break;
    236227                }
    237228        }
    238229       
     230        fibril_t *dstf;
     231
    239232        /* Choose a new fibril to run */
    240         fibril_t *dstf;
    241         if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
     233        switch (stype) {
     234        case FIBRIL_TO_MANAGER:
     235        case FIBRIL_FROM_DEAD:
    242236                dstf = list_get_instance(list_first(&manager_list), fibril_t,
    243237                    link);
    244                 if (serialization_count && stype == FIBRIL_TO_MANAGER) {
    245                         serialized_threads++;
    246                         srcf->flags |= FIBRIL_SERIALIZED;
    247                 }
    248                 threads_in_manager++;
    249238               
    250239                if (stype == FIBRIL_FROM_DEAD)
    251240                        dstf->clean_after_me = srcf;
    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         }
     241                break;
     242        default:
     243                dstf = list_get_instance(list_first(&ready_list), fibril_t,
     244                    link);
     245                break;
     246        }
     247
    262248        list_remove(&dstf->link);
    263249       
     
    272258        context_restore(&dstf->ctx);
    273259        /* not reached */
    274        
    275 ret_0:
    276         futex_unlock(&fibril_futex);
    277         return retval;
    278260}
    279261
     
    342324       
    343325        futex_lock(&fibril_futex);
    344        
    345         if ((fibril->flags & FIBRIL_SERIALIZED))
    346                 list_append(&fibril->link, &serialized_list);
    347         else
    348                 list_append(&fibril->link, &ready_list);
    349        
     326        list_append(&fibril->link, &ready_list);
    350327        futex_unlock(&fibril_futex);
    351328}
     
    370347{
    371348        futex_lock(&fibril_futex);
    372        
    373349        if (!list_empty(&manager_list))
    374350                list_remove(list_first(&manager_list));
    375        
    376351        futex_unlock(&fibril_futex);
    377352}
     
    387362}
    388363
    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 
    414364/** @}
    415365 */
Note: See TracChangeset for help on using the changeset viewer.