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


Ignore:
Timestamp:
2018-03-08T18:25:31Z (7 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
53ad43c, 615e83d
Parents:
fd57cf17
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-06 22:03:11)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-08 18:25:31)
Message:

Introduce context_swap() and use it to simplify fibril implementation.

This wraps the use of context_save()/context_restore(), to provide a more
natural (and easier to understand) control flow. The patch also hides the
details of the underlying context, requiring the use of context_get_pc()
to acquire program counter. This might allow context_swap() to only store
one pointer in the context, storing the remaining information in its stack
frame. However, that is not done in this patch.

File:
1 edited

Legend:

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

    rfd57cf17 re0a4686  
    4444#include <stdio.h>
    4545#include <libarch/barrier.h>
    46 #include <libarch/faddr.h>
     46#include <context.h>
    4747#include <futex.h>
    4848#include <assert.h>
     
    155155        futex_lock(&fibril_futex);
    156156
     157        fibril_t *srcf = __tcb_get()->fibril_data;
     158        fibril_t *dstf = NULL;
     159
     160        /* Choose a new fibril to run */
    157161        switch (stype) {
     162        case FIBRIL_TO_MANAGER:
     163        case FIBRIL_FROM_DEAD:
     164                /* Make sure the async_futex is held. */
     165                assert((atomic_signed_t) async_futex.val.count <= 0);
     166
     167                /* If we are going to manager and none exists, create it */
     168                while (list_empty(&manager_list)) {
     169                        futex_unlock(&fibril_futex);
     170                        async_create_manager();
     171                        futex_lock(&fibril_futex);
     172                }
     173
     174                dstf = list_get_instance(list_first(&manager_list),
     175                    fibril_t, link);
     176
     177                if (stype == FIBRIL_FROM_DEAD)
     178                        dstf->clean_after_me = srcf;
     179                break;
    158180        case FIBRIL_PREEMPT:
    159181        case FIBRIL_FROM_MANAGER:
     
    162184                        return 0;
    163185                }
    164                 break;
    165         case FIBRIL_TO_MANAGER:
    166         case FIBRIL_FROM_DEAD:
    167                 /* Make sure the async_futex is held. */
    168                 assert((atomic_signed_t) async_futex.val.count <= 0);
    169 
    170                 /* If we are going to manager and none exists, create it */
    171                 while (list_empty(&manager_list)) {
    172                         futex_unlock(&fibril_futex);
    173                         async_create_manager();
    174                         futex_lock(&fibril_futex);
    175                 }
    176                 break;
    177         }
    178 
    179         fibril_t *srcf = __tcb_get()->fibril_data;
    180         if (stype != FIBRIL_FROM_DEAD) {
    181 
    182                 /* Save current state */
    183                 if (!context_save(&srcf->ctx)) {
    184                         if (srcf->clean_after_me) {
    185                                 /*
    186                                  * Cleanup after the dead fibril from which we
    187                                  * restored context here.
    188                                  */
    189                                 void *stack = srcf->clean_after_me->stack;
    190                                 if (stack) {
    191                                         /*
    192                                          * This check is necessary because a
    193                                          * thread could have exited like a
    194                                          * normal fibril using the
    195                                          * FIBRIL_FROM_DEAD switch type. In that
    196                                          * case, its fibril will not have the
    197                                          * stack member filled.
    198                                          */
    199                                         as_area_destroy(stack);
    200                                 }
    201                                 fibril_teardown(srcf->clean_after_me, true);
    202                                 srcf->clean_after_me = NULL;
    203                         }
    204 
    205                         return 1;       /* futex_unlock already done here */
    206                 }
    207 
    208                 /* Put the current fibril into the correct run list */
    209                 switch (stype) {
    210                 case FIBRIL_PREEMPT:
    211                         list_append(&srcf->link, &ready_list);
    212                         break;
    213                 case FIBRIL_FROM_MANAGER:
    214                         list_append(&srcf->link, &manager_list);
    215                         break;
    216                 default:
    217                         assert(stype == FIBRIL_TO_MANAGER);
    218 
    219                         srcf->switches++;
    220 
    221                         /*
    222                          * Don't put the current fibril into any list, it should
    223                          * already be somewhere, or it will be lost.
    224                          */
    225                         break;
    226                 }
    227         }
    228 
    229         fibril_t *dstf;
    230 
    231         /* Choose a new fibril to run */
    232         switch (stype) {
    233         case FIBRIL_TO_MANAGER:
    234         case FIBRIL_FROM_DEAD:
    235                 dstf = list_get_instance(list_first(&manager_list), fibril_t,
    236                     link);
    237 
    238                 if (stype == FIBRIL_FROM_DEAD)
    239                         dstf->clean_after_me = srcf;
    240                 break;
    241         default:
     186
    242187                dstf = list_get_instance(list_first(&ready_list), fibril_t,
    243188                    link);
    244189                break;
    245190        }
    246 
    247191        list_remove(&dstf->link);
     192
     193        /* Put the current fibril into the correct run list */
     194        switch (stype) {
     195        case FIBRIL_PREEMPT:
     196                list_append(&srcf->link, &ready_list);
     197                break;
     198        case FIBRIL_FROM_MANAGER:
     199                list_append(&srcf->link, &manager_list);
     200                break;
     201        case FIBRIL_FROM_DEAD:
     202                // Nothing.
     203                break;
     204        case FIBRIL_TO_MANAGER:
     205                srcf->switches++;
     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        }
    248212
    249213        futex_unlock(&fibril_futex);
     
    255219#endif
    256220
    257         context_restore(&dstf->ctx);
    258         /* not reached */
     221        /* Swap to the next fibril. */
     222        context_swap(&srcf->ctx, &dstf->ctx);
     223
     224        /* Restored by another fibril! */
     225
     226        if (srcf->clean_after_me) {
     227                /*
     228                 * Cleanup after the dead fibril from which we
     229                 * restored context here.
     230                 */
     231                void *stack = srcf->clean_after_me->stack;
     232                if (stack) {
     233                        /*
     234                         * This check is necessary because a
     235                         * thread could have exited like a
     236                         * normal fibril using the
     237                         * FIBRIL_FROM_DEAD switch type. In that
     238                         * case, its fibril will not have the
     239                         * stack member filled.
     240                         */
     241                        as_area_destroy(stack);
     242                }
     243                fibril_teardown(srcf->clean_after_me, true);
     244                srcf->clean_after_me = NULL;
     245        }
     246
     247        return 1;
    259248}
    260249
     
    289278        fibril->arg = arg;
    290279
    291         context_save(&fibril->ctx);
    292         context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
    293             stack_size, fibril->tcb);
    294 
     280        context_create_t sctx = {
     281                .fn = fibril_main,
     282                .stack_base = fibril->stack,
     283                .stack_size = stack_size,
     284                .tls = fibril->tcb,
     285        };
     286
     287        context_create(&fibril->ctx, &sctx);
    295288        return (fid_t) fibril;
    296289}
Note: See TracChangeset for help on using the changeset viewer.