Changeset e0a4686 in mainline


Ignore:
Timestamp:
2018-03-08T18:25:31Z (6 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.

Location:
uspace
Files:
3 added
15 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/taskdump/fibrildump.c

    rfd57cf17 re0a4686  
    110110                        return EIO;
    111111
    112                 pc = fibril.ctx.pc;
     112                pc = context_get_pc(&fibril.ctx);
    113113                fp = context_get_fp(&fibril.ctx);
    114114                if (0) stacktrace_print_generic(&fibrildump_st_ops, sess,
  • uspace/lib/c/Makefile

    rfd57cf17 re0a4686  
    6565        generic/clipboard.c \
    6666        generic/config.c \
     67        generic/context.c \
    6768        generic/corecfg.c \
    6869        generic/devman.c \
  • uspace/lib/c/arch/abs32le/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    3737
    3838#include <stdint.h>
     39#include <libarch/fibril_context.h>
    3940
    4041#define SP_DELTA  0
     
    4849        } while (0)
    4950
    50 /*
    51  * On real hardware this stores the registers which
    52  * need to be preserved across function calls.
    53  */
    54 typedef struct {
    55         uintptr_t sp;
    56         uintptr_t fp;
    57         uintptr_t pc;
    58         uintptr_t tls;
    59 } context_t;
    60 
    61 static inline uintptr_t context_get_fp(context_t *ctx)
     51static inline uintptr_t _context_get_fp(context_t *ctx)
    6252{
    6353        /* On real hardware, this function returns the frame pointer. */
  • uspace/lib/c/arch/amd64/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5353        } while (0)
    5454
    55 static inline uintptr_t context_get_fp(context_t *ctx)
     55static inline uintptr_t _context_get_fp(context_t *ctx)
    5656{
    5757        return ctx->rbp;
  • uspace/lib/c/arch/arm32/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    6767        } while (0)
    6868
    69 static inline uintptr_t context_get_fp(context_t *ctx)
     69static inline uintptr_t _context_get_fp(context_t *ctx)
    7070{
    7171        return ctx->fp;
  • uspace/lib/c/arch/ia32/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5454        } while (0)
    5555
    56 static inline uintptr_t context_get_fp(context_t *ctx)
     56static inline uintptr_t _context_get_fp(context_t *ctx)
    5757{
    5858        return ctx->ebp;
  • uspace/lib/c/arch/ia64/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    6565        } while (0)
    6666
    67 static inline uintptr_t context_get_fp(context_t *ctx)
     67static inline uintptr_t _context_get_fp(context_t *ctx)
    6868{
    6969        return 0;       /* FIXME */
  • uspace/lib/c/arch/mips32/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5757        } while (0)
    5858
    59 static inline uintptr_t context_get_fp(context_t *ctx)
     59static inline uintptr_t _context_get_fp(context_t *ctx)
    6060{
    6161        return ctx->sp;
  • uspace/lib/c/arch/ppc32/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5454        } while (0)
    5555
    56 static inline uintptr_t context_get_fp(context_t *ctx)
     56static inline uintptr_t _context_get_fp(context_t *ctx)
    5757{
    5858        return ctx->sp;
  • uspace/lib/c/arch/riscv64/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5959} context_t;
    6060
    61 static inline uintptr_t context_get_fp(context_t *ctx)
     61static inline uintptr_t _context_get_fp(context_t *ctx)
    6262{
    6363        /* This function returns the frame pointer. */
  • uspace/lib/c/arch/sparc64/include/libarch/fibril.h

    rfd57cf17 re0a4686  
    5252        } while (0)
    5353
    54 static inline uintptr_t context_get_fp(context_t *ctx)
     54static inline uintptr_t _context_get_fp(context_t *ctx)
    5555{
    5656        return ctx->sp + STACK_BIAS;
  • 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}
  • uspace/lib/c/generic/fibril_synch.c

    rfd57cf17 re0a4686  
    7373                if (oi->owned_by == f)
    7474                        break;
    75                 stacktrace_print_fp_pc(context_get_fp(&oi->owned_by->ctx),
    76                     oi->owned_by->ctx.pc);
     75                stacktrace_print_fp_pc(
     76                    context_get_fp(&oi->owned_by->ctx),
     77                    context_get_pc(&oi->owned_by->ctx));
    7778                printf("Fibril %p waits for primitive %p.\n",
    7879                     oi->owned_by, oi->owned_by->waits_for);
  • uspace/lib/c/generic/setjmp.c

    rfd57cf17 re0a4686  
    3737
    3838#include <setjmp.h>
    39 #include <libarch/fibril.h>
    40 #include <fibril.h>
     39#include <context.h>
     40
     41// TODO: setjmp/longjmp are basically a stronger version of
     42// context_save/context_restore. It would be preferable to turn
     43// those two into setjmp/longjmp (all it would need is preserving the
     44// return value).
    4145
    4246/**
     
    5256        env[0].return_value = (val == 0) ? 1 : val;
    5357        context_restore(&env[0].context);
    54         __builtin_unreachable();
    5558}
    5659
  • uspace/lib/c/include/fibril.h

    rfd57cf17 re0a4686  
    3636#define LIBC_FIBRIL_H_
    3737
    38 #include <libarch/fibril.h>
     38#include <context.h>
    3939#include <types/common.h>
    4040#include <adt/list.h>
    4141#include <libarch/tls.h>
    42 
    43 #define context_set_generic(c, _pc, stack, size, ptls) \
    44         do { \
    45                 (c)->pc = (sysarg_t) (_pc); \
    46                 (c)->sp = ((sysarg_t) (stack)) + (size) - SP_DELTA; \
    47                 (c)->tls = (sysarg_t) (ptls); \
    48         } while (0)
    4942
    5043#define FIBRIL_WRITER   1
     
    8679#define fibril_local __thread
    8780
    88 extern int context_save(context_t *ctx) __attribute__((returns_twice));
    89 extern void context_restore(context_t *ctx) __attribute__((noreturn));
    90 
    9181#define FIBRIL_DFLT_STK_SIZE    0
    9282
    93 #define fibril_create(func, arg) \
    94         fibril_create_generic((func), (arg), FIBRIL_DFLT_STK_SIZE)
    9583extern fid_t fibril_create_generic(errno_t (*func)(void *), void *arg, size_t);
    9684extern void fibril_destroy(fid_t fid);
     
    10391extern fid_t fibril_get_id(void);
    10492
     93static inline fid_t fibril_create(errno_t (*func)(void *), void *arg)
     94{
     95        return fibril_create_generic(func, arg, FIBRIL_DFLT_STK_SIZE);
     96}
     97
    10598static inline int fibril_yield(void)
    10699{
Note: See TracChangeset for help on using the changeset viewer.