Ignore:
File:
1 edited

Legend:

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

    re768aea r3b1cc8d  
    4949#include <async.h>
    5050
    51 #include "private/fibril.h"
    52 
     51#ifdef FUTEX_UPGRADABLE
     52#include <rcu.h>
     53#endif
    5354
    5455/**
     
    7172static void fibril_main(void)
    7273{
    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();
     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
    7882
    7983        /* Call the implementing function. */
    8084        fibril->retval = fibril->func(fibril->arg);
    8185
    82         futex_lock(&async_futex);
     86        futex_down(&async_futex);
    8387        fibril_switch(FIBRIL_FROM_DEAD);
    8488        /* Not reached */
     
    9498                return NULL;
    9599
    96         fibril_t *fibril = calloc(1, sizeof(fibril_t));
     100        fibril_t *fibril = malloc(sizeof(fibril_t));
    97101        if (!fibril) {
    98102                tls_free(tcb);
     
    102106        tcb->fibril_data = fibril;
    103107        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;
    104117
    105118        /*
     
    128141/** Switch from the current fibril.
    129142 *
    130  * The async_futex must be held when entering this function,
    131  * and is still held on return.
     143 * If stype is FIBRIL_TO_MANAGER or FIBRIL_FROM_DEAD, the async_futex must
     144 * be held.
    132145 *
    133146 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     
    141154int fibril_switch(fibril_switch_type_t stype)
    142155{
    143         /* Make sure the async_futex is held. */
    144         futex_assert_is_locked(&async_futex);
    145 
    146156        futex_lock(&fibril_futex);
    147157
    148         fibril_t *srcf = fibril_self();
     158        fibril_t *srcf = __tcb_get()->fibril_data;
    149159        fibril_t *dstf = NULL;
    150160
    151161        /* Choose a new fibril to run */
    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                 }
     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);
    159167
    160168                /* If we are going to manager and none exists, create it */
     
    167175                dstf = list_get_instance(list_first(&manager_list),
    168176                    fibril_t, link);
    169         } else {
     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
    170188                dstf = list_get_instance(list_first(&ready_list), fibril_t,
    171189                    link);
    172         }
    173 
     190                break;
     191        }
    174192        list_remove(&dstf->link);
    175         if (stype == FIBRIL_FROM_DEAD)
    176                 dstf->clean_after_me = srcf;
    177193
    178194        /* Put the current fibril into the correct run list */
     
    185201                break;
    186202        case FIBRIL_FROM_DEAD:
    187         case FIBRIL_FROM_BLOCKED:
    188203                // Nothing.
    189204                break;
    190         }
    191 
    192         /* Bookkeeping. */
    193         futex_give_to(&fibril_futex, dstf);
    194         futex_give_to(&async_futex, dstf);
     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
    195218
    196219        /* Swap to the next fibril. */
     
    322345}
    323346
    324 fibril_t *fibril_self(void)
    325 {
    326         return __tcb_get()->fibril_data;
    327 }
    328 
    329347/** Return fibril id of the currently running fibril.
    330348 *
     
    334352fid_t fibril_get_id(void)
    335353{
    336         return (fid_t) fibril_self();
    337 }
    338 
    339 void fibril_yield(void)
    340 {
    341         futex_lock(&async_futex);
    342         (void) fibril_switch(FIBRIL_PREEMPT);
    343         futex_unlock(&async_futex);
     354        return (fid_t) __tcb_get()->fibril_data;
    344355}
    345356
Note: See TracChangeset for help on using the changeset viewer.