Changeset 78b3f52 for src/libcfa


Ignore:
Timestamp:
Dec 2, 2016, 5:10:22 PM (7 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
d7bcbf5
Parents:
4cb935e
Message:

Ugly but working coroutines

Location:
src/libcfa
Files:
6 added
4 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/assert

    r4cb935e r78b3f52  
    2020        #include <assert.h>
    2121
    22         #define __STRINGIFY__(str) #str
    23         #define __VSTRINGIFY__(str) __STRINGIFY__(str)
    24         #define assertf(expr, fmt, ...) ((expr) ? ((void)2) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
     22        #ifdef NDEBUG
     23                #define assertf(expr, fmt, ...) ((void)0)
     24        #else
     25                #define __STRINGIFY__(str) #str
     26                #define __VSTRINGIFY__(str) __STRINGIFY__(str)
     27                #define assertf(expr, fmt, ...) ((expr) ? ((void)0) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ ))
    2528
    26         void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn));
     29                void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn));
     30        #endif
    2731}
    2832
  • src/libcfa/concurrency/CtxSwitch-x86_64.S

    r4cb935e r78b3f52  
     1//                               -*- Mode: Asm -*-
     2//
     3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
     4//
     5// The contents of this file are covered under the licence agreement in the
     6// file "LICENCE" distributed with Cforall.
     7//
     8// CtxSwitch-x86_64.S --
     9//
     10// Author           : Thierry Delisle
     11// Created On       : Mon Nov 28 12:27:26 2016
     12// Last Modified By : Thierry Delisle
     13// Last Modified On : Mon Nov 28 12:27:26 2016
     14// Update Count     : 0
     15//
     16// This  library is free  software; you  can redistribute  it and/or  modify it
     17// under the terms of the GNU Lesser General Public License as published by the
     18// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
     19// option) any later version.
     20//
     21// This library is distributed in the  hope that it will be useful, but WITHOUT
     22// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
     23// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
     24// for more details.
     25//
     26// You should  have received a  copy of the  GNU Lesser General  Public License
     27// along  with this library.
     28//
     29
     30// This context switch routine depends on the fact that the stack of a new
     31// thread has been set up to look like the thread has saved its context in
     32// the normal manner.
     33//
     34// void CtxSwitch( machine_context *from, machine_context *to );
     35
     36// Offsets in the context structure. This needs to be synchronized with the
     37// high level code a little better.
     38
     39#define PTR_BYTE        8
     40#define SP_OFFSET       ( 0 * PTR_BYTE )
     41#define FP_OFFSET       ( 1 * PTR_BYTE )
     42#define PC_OFFSET       ( 2 * PTR_BYTE )
     43
     44.text
     45        .align 2
     46.globl  CtxSwitch
     47CtxSwitch:
     48
     49        // Save volatile registers on the stack.
     50
     51        pushq %r15
     52        pushq %r14
     53        pushq %r13
     54        pushq %r12
     55        pushq %rbx
     56
     57        // Save old context in the "from" area.
     58
     59        movq %rsp,SP_OFFSET(%rdi)
     60        movq %rbp,FP_OFFSET(%rdi)
     61
     62        // Load new context from the "to" area.
     63
     64        movq SP_OFFSET(%rsi),%rsp
     65        movq FP_OFFSET(%rsi),%rbp
     66
     67        // Load volatile registers from the stack.
     68
     69        popq %rbx
     70        popq %r12
     71        popq %r13
     72        popq %r14
     73        popq %r15
     74
     75        // Return to thread.
     76
     77        ret
     78
     79.text
     80        .align 2
     81.globl  coInvokeStub
     82coInvokeStub:
     83        movq %rbx, %rdi
     84        movq %r12, %rsi
     85        jmp *%r13
     86
     87// Local Variables: //
     88// mode: c //
     89// tab-width: 4 //
     90// End: //
  • src/libcfa/concurrency/threads

    r4cb935e r78b3f52  
     1//                              -*- Mode: CFA -*-
    12//
    2 // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
     3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
    34//
    45// The contents of this file are covered under the licence agreement in the
    56// file "LICENCE" distributed with Cforall.
    67//
    7 // fstream --
     8// threads --
    89//
    9 // Author           : Peter A. Buhr
    10 // Created On       : Wed May 27 17:56:53 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 28 08:08:04 2016
    13 // Update Count     : 88
     10// Author           : Thierry Delisle
     11// Created On       : Mon Nov 28 12:27:26 2016
     12// Last Modified By : Thierry Delisle
     13// Last Modified On : Mon Nov 28 12:27:26 2016
     14// Update Count     : 0
    1415//
    1516
     
    1920#include <stdbool.h>
    2021
    21 struct coroutine {
    22       coroutine* last;
    23       const char* name;
    24       bool notHalted;
    25 };
     22extern "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}
     52
     53void ?{}(coStack_t* this);
    2654
    2755void ?{}(coroutine* this);
     
    2957trait coroutine_t(dtype T) {
    3058      coroutine* this_coroutine(T* this);
     59      void co_main(T* this);
     60      coVtable* vtable(T* this);
    3161};
     62
     63forall(dtype T | coroutine_t(T))
     64void start(T* cor);
    3265
    3366void suspend(void);
     
    3770
    3871#endif //__THREADS_H__
     72
     73// Local Variables: //
     74// mode: c //
     75// tab-width: 4 //
     76// End: //
  • src/libcfa/concurrency/threads.c

    r4cb935e r78b3f52  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// threads.c --
     8//
     9// Author           : Thierry Delisle
     10// Created On       : Mon Nov 28 12:27:26 2016
     11// Last Modified By : Thierry Delisle
     12// Last Modified On : Mon Nov 28 12:27:26 2016
     13// Update Count     : 0
     14//
     15
     16extern "C" {
     17#include <stddef.h>
     18#include <malloc.h>
     19#include <errno.h>
     20#include <string.h>
     21#include <unistd.h>
     22#include <sys/mman.h>
     23}
     24
    125#include "threads"
    226#include "assert"
     27#include "libhdr.h"
    328
    4 #include <stddef.h>
     29extern "C" { extern void coInvokeStub( void ); }
    530
    6 #include <fstream>
    7  
     31// minimum feasible stack size in bytes
     32#define MinStackSize 1000
     33
    834static coroutine main_coroutine;
    935static coroutine* current_coroutine = &main_coroutine;
    1036
    11 void ctxSwitchDirect(void* src, void* dst) {
    12         current_coroutine = dst;
     37extern "C" {
     38        struct machine_context_t {
     39                void *SP;
     40                void *FP;
     41                void *PC;
     42        };
     43}
     44
     45extern "C" { void CtxSwitch( void *from, void *to ) asm ("CtxSwitch"); }// assembler routine that performs the context switch
     46
     47static size_t pageSize = 0;                             // architecture pagesize
     48
     49void ctxSwitchDirect(coroutine* src, coroutine* dst) {
     50        // THREAD_GETMEM( This )->disableInterrupts();
     51
     52        // set state of current coroutine to inactive
     53        src->state = Inactive;
     54
     55        // set new coroutine that task is executing
     56        current_coroutine = dst;                       
     57
     58        // context switch to specified coroutine
     59        CtxSwitch( src->stack.context, dst->stack.context );
     60        // when CtxSwitch returns we are back in the src coroutine             
     61
     62        // set state of new coroutine to active
     63        src->state = Active;
     64
     65        // THREAD_GETMEM( This )->enableInterrupts();
     66} //ctxSwitchDirect
     67
     68void invokeCoroutine(coVtable* vtable, void* this);
     69
     70forall(dtype T | coroutine_t(T))
     71void startCoroutine(T* this, void (*invoke)(coVtable*, void*));
     72
     73// used by all constructors
     74void create_stack( coStack_t* this, unsigned int storageSize ) {
     75        //TEMP HACK do this on proper kernel startup
     76        if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
     77
     78        size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
     79
     80        if ( (intptr_t)this->storage == 0 ) {
     81                this->userStack = false;
     82                this->size = libCeiling( storageSize, 16 );
     83                // use malloc/memalign because "new" raises an exception for out-of-memory
     84               
     85                // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
     86                LIB_DEBUG_DO( this->storage = memalign( pageSize, cxtSize + this->size + pageSize ) );
     87                LIB_NO_DEBUG_DO( this->storage = malloc( cxtSize + this->size + 8 ) );
     88
     89                LIB_DEBUG_DO(
     90                        if ( mprotect( this->storage, pageSize, PROT_NONE ) == -1 ) {
     91                                abortf( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
     92                        } // if
     93                );
     94
     95                if ( (intptr_t)this->storage == 0 ) {
     96                        abortf( "Attempt to allocate %d bytes of storage for coroutine or task execution-state but insufficient memory available.", this->size );
     97                } // if
     98
     99                LIB_DEBUG_DO( this->limit = (char *)this->storage + pageSize );
     100                LIB_NO_DEBUG_DO( this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ) ); // minimum alignment
     101
     102        } else {
     103                assertf( ((size_t)this->storage & (libAlign() - 1)) != 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", this->storage, (int)libAlign() );
     104                this->userStack = true;
     105                this->size = storageSize - cxtSize;
     106
     107                if ( this->size % 16 != 0u ) this->size -= 8;
     108
     109                this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ); // minimum alignment
     110        } // if
     111        assertf( this->size >= MinStackSize, "Stack size %d provides less than minimum of %d bytes for a stack.", this->size, MinStackSize );
     112
     113        this->base = (char *)this->limit + this->size;
     114        this->context = this->base;
     115        this->top = (char *)this->context + cxtSize;
    13116}
    14117
     
    17120}
    18121
     122void ?{}(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
    19133void ?{}(coroutine* this)
    20134{
     135        this->name = "Anonymous Coroutine";
     136        this->errno_ = 0;
     137        this->state = Start;
     138      this->notHalted = true;
     139        this->starter = NULL;
    21140        this->last = NULL;
    22       this->name = "A Coroutine";
    23       this->notHalted = true;
     141}
     142
     143forall(dtype T | coroutine_t(T))
     144void start(T* this) {
     145        startCoroutine(this, invokeCoroutine);
    24146}
    25147
     
    27149      coroutine* src = this_coroutine();                // optimization
    28150
    29         assertf( src->last == (coroutine*)0,
     151        assertf( src->last != 0,
    30152                "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
    31153                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     
    44166        coroutine* dst = this_coroutine(cor);
    45167
     168        fprintf(stderr, "Resuming %p from %p\n", dst, src);
    46169        if ( src != dst ) {                             // not resuming self ?
    47170                assertf( dst->notHalted ,
     
    49172                        "Possible cause is terminated coroutine's main routine has already returned.",
    50173                        src->name, src, dst->name, dst );
     174                fprintf(stderr, "Assigning last pointer\n");
    51175                dst->last = src;                                        // set last resumer
    52176        } // if
    53177        ctxSwitchDirect( src, dst );                            // always done for performance testing
    54178}
     179
     180// Local Variables: //
     181// mode: c //
     182// tab-width: 4 //
     183// End: //
Note: See TracChangeset for help on using the changeset viewer.