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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.