Changeset 5c81105


Ignore:
Timestamp:
Dec 6, 2016, 6:28:47 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
2cd0434
Parents:
fa66f4e
Message:

cleaned-up coroutines code to no longer need a manual start

Location:
src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/CtxSwitch-x86_64.S

    rfa66f4e r5c81105  
    8181.globl  coInvokeStub
    8282coInvokeStub:
    83         movq %rbx, %rdi
    84         movq %r12, %rsi
    85         jmp *%r13
     83        movq %rbx, %rdi
     84        jmp *%r12
    8685
    8786// Local Variables: //
  • src/libcfa/concurrency/invoke.c

    rfa66f4e r5c81105  
    77#include "invoke.h"
    88
    9 struct machine_context_t {
    10         void *SP;
    11         void *FP;
    12         void *PC;
    13 };
    14 
    15 extern void coInvokeStub( void );
     9#define __CFA_INVOKE_PRIVATE__
     10#include "invoke.h"
    1611
    1712// magically invoke the "main" of the most derived class
    1813// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    19 void __invokeCoroutine__F_P9scoVtablePv__1(struct coVtable *vtable, void* vthis)
     14
     15void invokeCoroutine(covptr_t* vthis)
    2016{
    21       LIB_DEBUG_PRINTF("Invoke : Received %p (v %p)\n", vthis, vtable);
     17      LIB_DEBUG_PRINTF("Invoke : Received %p (v %p)\n", vthis, *vthis);
    2218
    23       struct coroutine* cor = vtable->this_coroutine(vthis);
     19      struct coroutine* cor = get_coroutine( vthis );
    2420
    2521      cor->state = Active;
    2622
    27       vtable->main(vthis);
     23      (*vthis)->main( get_object(vthis) );
    2824}
    2925
    30 void __startCoroutine__A0_1_0___this_coroutine__PFP10scoroutine_Pd0___co_main__PF_Pd0___vtable__PFP9scoVtable_Pd0__F_Pd0PF_P9scoVtablePv___1(
    31       struct coroutine *(*this_coroutine)(void * ),
    32       void (*co_main)(void *),
    33       struct coVtable *(*get_vtable)(void *),
    34       void *vthis,
    35       void (*invoke)(struct coVtable *, void *)
    36 ) {
    37       LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (v %p) to %p\n", vthis, vtable, invoke);
    3826
    39       struct coVtable * vtable = get_vtable( vthis );
    40       struct coroutine* this = this_coroutine( vthis );
     27void startCoroutine(covptr_t* vthis, void (*invoke)(covptr_t*)) {
     28      LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (v %p) to %p\n", vthis, *vthis, invoke);
     29
     30      struct coroutine* this = get_coroutine( vthis );
    4131      struct coStack_t* stack = &this->stack;
    4232
     
    4737            void *rturn;                                      // where to go on return from uSwitch
    4838            void *dummyReturn;                          // fake return compiler would have pushed on call to uInvoke
    49             void *argument[2];                          // for 16-byte ABI, 16-byte alignment starts here
    50             void *padding[2];                           // padding to force 16-byte alignment, as "base" is 16-byte aligned
     39            void *argument;                             // for 16-byte ABI, 16-byte alignment starts here
     40            void *padding[3];                           // padding to force 16-byte alignment, as "base" is 16-byte aligned
    5141        };
    5242
     
    5545
    5646        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;
    57         ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = vtable; // argument to invoke
    58       ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[1] = vthis;  // argument to invoke
     47        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument = vthis;     // argument to invoke
    5948        ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke;
    6049
     
    7261      ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;
    7362      ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = coInvokeStub;
    74       ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = vtable;
    75       ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = vthis;
    76       ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[2] = invoke;
     63      ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = vthis;
     64      ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke;
    7765#else
    7866      #error Only __i386__ and __x86_64__ is supported for threads in cfa
  • src/libcfa/concurrency/invoke.h

    rfa66f4e r5c81105  
     1#include <stdbool.h>
     2#include <stdint.h>
    13
     4#ifdef __CFORALL__
     5extern "C" {
     6#endif
     7
     8#if ! defined(__CFA_INVOKE_PRIVATE__)
    29#ifndef _INVOKE_H_
    310#define _INVOKE_H_
    411
    5 struct coVtable {
    6       void (*main)(void*);
    7       struct coroutine* (*this_coroutine)(void*);
    8 };
     12      #define OFFSET_OF(type, field) ((intptr_t)( &((type*)0)->field))
     13      #define VPTR_OFFSET(type, vptr, field) (OFFSET_OF(type, field) - OFFSET_OF(type, vptr))
    914
    10 struct coStack_t {
    11       unsigned int size;                // size of stack
    12       void *storage;                    // pointer to stack
    13       void *limit;                      // stack grows towards stack limit
    14       void *base;                               // base of stack
    15       void *context;                    // address of cfa_context_t
    16       void *top;                                // address of top of storage
    17       bool userStack;   
    18 };
     15      struct coVtable_t {
     16            void (*main)(void*);
     17            intptr_t offset_coroutine;
     18            intptr_t offset_object;
     19      };
    1920
     21      typedef struct coVtable_t* covptr_t;
    2022
    21 enum coroutine_state { Start, Inactive, Active, Halt };
     23      static inline struct coroutine* get_coroutine(covptr_t* vthis) {
     24            return (struct coroutine*) ( ((intptr_t)vthis) + ((intptr_t)(*vthis)->offset_coroutine) );
     25      }
    2226
    23 struct coroutine {
    24       struct coStack_t stack;
    25       const char *name;                 // textual name for coroutine/task, initialized by uC++ generated code
    26       int errno_;                               // copy of global UNIX variable errno
    27       enum coroutine_state state;             // current execution status for coroutine
    28       bool notHalted;                   // indicate if execuation state is not halted
     27      static inline void* get_object(covptr_t* vthis) {
     28            return (void*) ( ((intptr_t)vthis) + ((intptr_t)(*vthis)->offset_object) );
     29      }
    2930
    30       struct coroutine *starter;                // first coroutine to resume this one
    31       struct coroutine *last;                   // last coroutine to resume this one
    32 };
     31      struct coStack_t {
     32            unsigned int size;          // size of stack
     33            void *storage;                      // pointer to stack
     34            void *limit;                        // stack grows towards stack limit
     35            void *base;                         // base of stack
     36            void *context;                      // address of cfa_context_t
     37            void *top;                          // address of top of storage
     38            bool userStack;     
     39      };
    3340
     41      enum coroutine_state { Start, Inactive, Active, Halt };
     42
     43      struct coroutine {
     44            struct coStack_t stack;
     45            const char *name;                   // textual name for coroutine/task, initialized by uC++ generated code
     46            int errno_;                         // copy of global UNIX variable errno
     47            enum coroutine_state state; // current execution status for coroutine
     48            bool notHalted;                     // indicate if execuation state is not halted
     49
     50            struct coroutine *starter;  // first coroutine to resume this one
     51            struct coroutine *last;             // last coroutine to resume this one
     52      };
     53
     54      void invokeCoroutine(covptr_t* this);
     55      void startCoroutine(covptr_t* this, void (*invoke)(covptr_t*));
    3456#endif //_INVOKE_H_
     57#else //! defined(__CFA_INVOKE_PRIVATE__)
     58#ifndef _INVOKE_PRIVATE_H_
     59#define _INVOKE_PRIVATE_H_
     60     
     61     struct machine_context_t {
     62            void *SP;
     63            void *FP;
     64            void *PC;
     65      };
     66
     67      // assembler routines that performs the context switch
     68      extern void coInvokeStub( void );
     69      void CtxSwitch( void *from, void *to ) asm ("CtxSwitch");
     70
     71#endif //_INVOKE_PRIVATE_H_
     72#endif //! defined(__CFA_INVOKE_PRIVATE__)
     73#ifdef __CFORALL__
     74}
     75#endif
  • src/libcfa/concurrency/threads

    rfa66f4e r5c81105  
    1818#define __THREADS_H__
    1919
    20 #include <stdbool.h>
    21 
    22 extern "C" {
    23       struct coVtable {
    24             void (*main)(void*);
    25             struct coroutine* (*this_coroutine)(void*);
    26       };
    27 
    28       struct coStack_t {
    29             unsigned int size;          // size of stack
    30             void *storage;                      // pointer to stack
    31             void *limit;                        // stack grows towards stack limit
    32             void *base;                         // base of stack
    33             void *context;                      // address of cfa_context_t
    34             void *top;                          // address of top of storage
    35             bool userStack;     
    36       };
    37 
    38 
    39       enum coroutine_state { Start, Inactive, Active, Halt };
    40 
    41       struct coroutine {
    42             coStack_t stack;
    43             const char *name;                   // textual name for coroutine/task, initialized by uC++ generated code
    44             int errno_;                         // copy of global UNIX variable errno
    45             coroutine_state state;            // current execution status for coroutine
    46             bool notHalted;                     // indicate if execuation state is not halted
    47 
    48             coroutine *starter;         // first coroutine to resume this one
    49             coroutine *last;                    // last coroutine to resume this one
    50       };
    51 }
     20#include "invoke.h"
    5221
    5322void ?{}(coStack_t* this);
    5423
    5524void ?{}(coroutine* this);
     25void ?{}(coroutine* this, covptr_t* object);
    5626
    5727trait coroutine_t(dtype T) {
    58       coroutine* this_coroutine(T* this);
    5928      void co_main(T* this);
    60       coVtable* vtable(T* this);
     29      covptr_t* vtable(T* this);
    6130};
    62 
    63 forall(dtype T | coroutine_t(T))
    64 void start(T* cor);
    6531
    6632void suspend(void);
  • src/libcfa/concurrency/threads.c

    rfa66f4e r5c81105  
    2727#include "libhdr.h"
    2828
    29 extern "C" { extern void coInvokeStub( void ); }
     29#define __CFA_INVOKE_PRIVATE__
     30#include "invoke.h"
    3031
    3132// minimum feasible stack size in bytes
    3233#define MinStackSize 1000
     34static size_t pageSize = 0;                             // architecture pagesize
    3335
    3436static coroutine main_coroutine;
    3537static coroutine* current_coroutine = &main_coroutine;
    3638
    37 extern "C" {
    38         struct machine_context_t {
    39                 void *SP;
    40                 void *FP;
    41                 void *PC;
    42         };
     39coroutine* this_coroutine(void) {
     40        return current_coroutine;
    4341}
    4442
    45 extern "C" { void CtxSwitch( void *from, void *to ) asm ("CtxSwitch"); }// assembler routine that performs the context switch
     43void ctxSwitchDirect(coroutine* src, coroutine* dst);
     44void create_stack( coStack_t* this, unsigned int storageSize ); // used by all constructors
    4645
    47 static size_t pageSize = 0;                             // architecture pagesize
     46void ?{}(coStack_t* this) {
     47        this->size              = 10240;        // size of stack
     48        this->storage   = NULL; // pointer to stack
     49        this->limit             = NULL; // stack grows towards stack limit
     50        this->base              = NULL; // base of stack
     51        this->context   = NULL; // address of cfa_context_t
     52        this->top               = NULL; // address of top of storage
     53        this->userStack = false;       
     54
     55        create_stack(this, this->size);
     56}
     57
     58void ?{}(coroutine* this)
     59{
     60        this->name = "Anonymous Coroutine";
     61        this->errno_ = 0;
     62        this->state = Start;
     63      this->notHalted = true;
     64        this->starter = NULL;
     65        this->last = NULL;
     66}
     67
     68void ?{}(coroutine* this, covptr_t* object)
     69{
     70        this{};
     71
     72        startCoroutine(object, invokeCoroutine);
     73}
     74
     75void suspend() {
     76      coroutine* src = this_coroutine();                // optimization
     77
     78        assertf( src->last != 0,
     79                "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
     80                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     81                src->name, src );
     82        assertf( src->last->notHalted,
     83                "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
     84                "Possible cause is terminated coroutine's main routine has already returned.",
     85                src->name, src, src->last->name, src->last );
     86
     87        ctxSwitchDirect( src, src->last );
     88}
     89
     90forall(dtype T | coroutine_t(T))
     91void resume(T* cor) {
     92        coroutine* src = this_coroutine();              // optimization
     93        coroutine* dst = get_coroutine(vtable(cor));
     94
     95        if ( src != dst ) {                             // not resuming self ?
     96                assertf( dst->notHalted ,
     97                        "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n"
     98                        "Possible cause is terminated coroutine's main routine has already returned.",
     99                        src->name, src, dst->name, dst );
     100                dst->last = src;                                        // set last resumer
     101        } // if
     102        ctxSwitchDirect( src, dst );                            // always done for performance testing
     103}
    48104
    49105void ctxSwitchDirect(coroutine* src, coroutine* dst) {
     
    65121        // THREAD_GETMEM( This )->enableInterrupts();
    66122} //ctxSwitchDirect
    67 
    68 void invokeCoroutine(coVtable* vtable, void* this);
    69 
    70 forall(dtype T | coroutine_t(T))
    71 void startCoroutine(T* this, void (*invoke)(coVtable*, void*));
    72123
    73124// used by all constructors
     
    116167}
    117168
    118 coroutine* this_coroutine() {
    119         return current_coroutine;
    120 }
    121 
    122 void ?{}(coStack_t* this) {
    123         this->size              = 10240;        // size of stack
    124         this->storage   = NULL; // pointer to stack
    125         this->limit             = NULL; // stack grows towards stack limit
    126         this->base              = NULL; // base of stack
    127         this->context   = NULL; // address of cfa_context_t
    128         this->top               = NULL; // address of top of storage
    129         this->userStack = false;       
    130         create_stack(this, this->size);
    131 }
    132 
    133 void ?{}(coroutine* this)
    134 {
    135         this->name = "Anonymous Coroutine";
    136         this->errno_ = 0;
    137         this->state = Start;
    138       this->notHalted = true;
    139         this->starter = NULL;
    140         this->last = NULL;
    141 }
    142 
    143 forall(dtype T | coroutine_t(T))
    144 void start(T* this) {
    145         startCoroutine(this, invokeCoroutine);
    146 }
    147 
    148 void suspend() {
    149       coroutine* src = this_coroutine();                // optimization
    150 
    151         assertf( src->last != 0,
    152                 "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
    153                 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    154                 src->name, src );
    155         assertf( src->last->notHalted,
    156                 "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
    157                 "Possible cause is terminated coroutine's main routine has already returned.",
    158                 src->name, src, src->last->name, src->last );
    159 
    160         ctxSwitchDirect( src, src->last );
    161 }
    162 
    163 forall(dtype T | coroutine_t(T))
    164 void resume(T* cor) {
    165         coroutine* src = this_coroutine();              // optimization
    166         coroutine* dst = this_coroutine(cor);
    167 
    168         if ( src != dst ) {                             // not resuming self ?
    169                 assertf( dst->notHalted ,
    170                         "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n"
    171                         "Possible cause is terminated coroutine's main routine has already returned.",
    172                         src->name, src, dst->name, dst );
    173                 dst->last = src;                                        // set last resumer
    174         } // if
    175         ctxSwitchDirect( src, dst );                            // always done for performance testing
    176 }
    177 
    178169// Local Variables: //
    179170// mode: c //
  • src/tests/coroutine.c

    rfa66f4e r5c81105  
    33
    44struct Fibonacci {
     5      int fn; // used for communication
     6      covptr_t v;
    57      coroutine c;
    6       coVtable v;
    7       int fn; // used for communication
    88};
    99
    10 coroutine* this_coroutine(Fibonacci* this);
    1110void co_main(Fibonacci* this);
    12 coVtable* vtable(Fibonacci* this);
     11covptr_t* vtable(Fibonacci* this);
    1312
     13//GENERATED in proposal for virtuals
    1414void co_main_fib(void* this) {
    1515      co_main( (Fibonacci*) this );
    1616}
    1717
    18 coroutine* this_coroutine_fib(void* this) {
    19       return this_coroutine( (Fibonacci*) this);
    20 }
     18//GENERATED in proposal for virtuals
     19static coVtable_t FibonacciVtable = {
     20      co_main_fib,
     21      VPTR_OFFSET(Fibonacci, v, c),
     22      VPTR_OFFSET(Fibonacci, v, fn)     
     23};
    2124
    2225void ?{}(Fibonacci* this) {
    2326      this->fn = 0;
    24       this->v.main = co_main_fib;
    25       this->v.this_coroutine = this_coroutine_fib;
    26       start(this);
     27      this->v = &FibonacciVtable;  //GENERATED in proposal for virtuals
     28      (&this->c) { &this->v };
    2729}
    2830
     
    3032#ifdef MORE_DEBUG
    3133      sout | "Starting main of coroutine " | this | endl;
    32       sout | "Started from " | this_coroutine(this)->last | endl;
     34      sout | "Started from " | this->c.last | endl;
    3335#endif
    3436      int fn1, fn2;             // retained between resumes
     
    5557}
    5658
    57 coroutine* this_coroutine(Fibonacci* this) {
    58       return &this->c;
    59 }
    60 
    61 coVtable* vtable(Fibonacci* this) {
     59covptr_t* vtable(Fibonacci* this) {
    6260      return &this->v;
    6361}
     
    6664      Fibonacci f1, f2;
    6765#ifdef MORE_DEBUG     
    68       sout | "User coroutines : " | &f1 | ' ' | &f1 | endl;
     66      Fibonacci *pf1 = &f1, *pf2 = &f2;
     67      coroutine *cf1 = &f1.c, *cf2 = &f2.c;
     68      covptr_t  *vf1 = vtable(pf1), *vf2 = vtable(pf2);
     69      coroutine *cv1 = get_coroutine(vf1), *cv2 = get_coroutine(vf2);
     70      Fibonacci *ov1 = (Fibonacci *)get_object(vf1), *ov2 = (Fibonacci *)get_object(vf2);
     71
     72      sout | "User coroutines : " | pf1 | ' ' | pf2 | endl;
     73      sout | "Coroutine data  : " | cf1 | ' ' | cf2 | endl;
     74      sout | "Vptr address    : " | vf1 | ' ' | vf2 | endl;
     75      sout | "Vptr obj data   : " | ov1 | ' ' | ov2 | endl;
     76      sout | "Vptr cor data   : " | cv1 | ' ' | cv2 | endl;
    6977#endif
    7078      for ( int i = 1; i <= 10; i += 1 ) {
Note: See TracChangeset for help on using the changeset viewer.