Ignore:
File:
1 edited

Legend:

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

    r3b1cc8d re768aea  
    4949#include <async.h>
    5050
    51 #ifdef FUTEX_UPGRADABLE
    52 #include <rcu.h>
    53 #endif
     51#include "private/fibril.h"
     52
    5453
    5554/**
     
    7271static void fibril_main(void)
    7372{
    74         /* fibril_futex is locked when a fibril is first started. */
    75         futex_unlock(&fibril_futex);
    76 
    77         fibril_t *fibril = __tcb_get()->fibril_data;
    78 
    79 #ifdef FUTEX_UPGRADABLE
    80         rcu_register_fibril();
    81 #endif
     73        /* fibril_futex and async_futex are locked when a fibril is started. */
     74        futex_unlock(&fibril_futex);
     75        futex_unlock(&async_futex);
     76
     77        fibril_t *fibril = fibril_self();
    8278
    8379        /* Call the implementing function. */
    8480        fibril->retval = fibril->func(fibril->arg);
    8581
    86         futex_down(&async_futex);
     82        futex_lock(&async_futex);
    8783        fibril_switch(FIBRIL_FROM_DEAD);
    8884        /* Not reached */
     
    9894                return NULL;
    9995
    100         fibril_t *fibril = malloc(sizeof(fibril_t));
     96        fibril_t *fibril = calloc(1, sizeof(fibril_t));
    10197        if (!fibril) {
    10298                tls_free(tcb);
     
    106102        tcb->fibril_data = fibril;
    107103        fibril->tcb = tcb;
    108 
    109         fibril->func = NULL;
    110         fibril->arg = NULL;
    111         fibril->stack = NULL;
    112         fibril->clean_after_me = NULL;
    113         fibril->retval = 0;
    114         fibril->flags = 0;
    115 
    116         fibril->waits_for = NULL;
    117104
    118105        /*
     
    141128/** Switch from the current fibril.
    142129 *
    143  * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
    144  * be held.
     130 * The async_futex must be held when entering this function,
     131 * and is still held on return.
    145132 *
    146133 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    154141int fibril_switch(fibril_switch_type_t stype)
    155142{
     143        /* Make sure the async_futex is held. */
     144        futex_assert_is_locked(&async_futex);
     145
    156146        futex_lock(&fibril_futex);
    157147
    158         fibril_t *srcf = __tcb_get()->fibril_data;
     148        fibril_t *srcf = fibril_self();
    159149        fibril_t *dstf = NULL;
    160150
    161151        /* Choose a new fibril to run */
    162         switch (stype) {
    163         case FIBRIL_TO_MANAGER:
    164         case FIBRIL_FROM_DEAD:
    165                 /* Make sure the async_futex is held. */
    166                 assert((atomic_signed_t) async_futex.val.count <= 0);
     152        if (list_empty(&ready_list)) {
     153                if (stype == FIBRIL_PREEMPT || stype == FIBRIL_FROM_MANAGER) {
     154                        // FIXME: This means that as long as there is a fibril
     155                        // that only yields, IPC messages are never retrieved.
     156                        futex_unlock(&fibril_futex);
     157                        return 0;
     158                }
    167159
    168160                /* If we are going to manager and none exists, create it */
     
    175167                dstf = list_get_instance(list_first(&manager_list),
    176168                    fibril_t, link);
    177 
    178                 if (stype == FIBRIL_FROM_DEAD)
    179                         dstf->clean_after_me = srcf;
    180                 break;
    181         case FIBRIL_PREEMPT:
    182         case FIBRIL_FROM_MANAGER:
    183                 if (list_empty(&ready_list)) {
    184                         futex_unlock(&fibril_futex);
    185                         return 0;
    186                 }
    187 
     169        } else {
    188170                dstf = list_get_instance(list_first(&ready_list), fibril_t,
    189171                    link);
    190                 break;
    191         }
     172        }
     173
    192174        list_remove(&dstf->link);
     175        if (stype == FIBRIL_FROM_DEAD)
     176                dstf->clean_after_me = srcf;
    193177
    194178        /* Put the current fibril into the correct run list */
     
    201185                break;
    202186        case FIBRIL_FROM_DEAD:
     187        case FIBRIL_FROM_BLOCKED:
    203188                // Nothing.
    204189                break;
    205         case FIBRIL_TO_MANAGER:
    206                 /*
    207                  * Don't put the current fibril into any list, it should
    208                  * already be somewhere, or it will be lost.
    209                  */
    210                 break;
    211         }
    212 
    213 #ifdef FUTEX_UPGRADABLE
    214         if (stype == FIBRIL_FROM_DEAD) {
    215                 rcu_deregister_fibril();
    216         }
    217 #endif
     190        }
     191
     192        /* Bookkeeping. */
     193        futex_give_to(&fibril_futex, dstf);
     194        futex_give_to(&async_futex, dstf);
    218195
    219196        /* Swap to the next fibril. */
     
    345322}
    346323
     324fibril_t *fibril_self(void)
     325{
     326        return __tcb_get()->fibril_data;
     327}
     328
    347329/** Return fibril id of the currently running fibril.
    348330 *
     
    352334fid_t fibril_get_id(void)
    353335{
    354         return (fid_t) __tcb_get()->fibril_data;
     336        return (fid_t) fibril_self();
     337}
     338
     339void fibril_yield(void)
     340{
     341        futex_lock(&async_futex);
     342        (void) fibril_switch(FIBRIL_PREEMPT);
     343        futex_unlock(&async_futex);
    355344}
    356345
Note: See TracChangeset for help on using the changeset viewer.