Changeset 4a3386b4 for src/libcfa


Ignore:
Timestamp:
Jan 19, 2017, 2:56:51 PM (9 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:
8f49a54
Parents:
765aa76 (diff), c2416d5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src/libcfa/concurrency
Files:
10 edited

Legend:

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

    r765aa76 r4a3386b4  
    8686        ret
    8787
     88.text
     89        .align 2
     90.globl  CtxGet
     91CtxGet:
     92        movl %esp,SP_OFFSET(%eax)
     93        movl %ebp,FP_OFFSET(%eax)
     94
     95        ret
     96
    8897// Local Variables: //
    8998// compile-command: "make install" //
  • src/libcfa/concurrency/CtxSwitch-x86_64.S

    r765aa76 r4a3386b4  
    8484        jmp *%r12
    8585
     86.text
     87        .align 2
     88.globl  CtxGet
     89CtxGet:
     90        movq %rsp,SP_OFFSET(%rdi)
     91        movq %rbp,FP_OFFSET(%rdi)
     92
     93        ret
     94
    8695// Local Variables: //
    8796// mode: c //
  • src/libcfa/concurrency/coroutines

    r765aa76 r4a3386b4  
     1//                              - *- Mode: CFA - *-
     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// coroutines --
     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
     17#ifndef COROUTINES_H
     18#define COROUTINES_H
     19
     20#include "assert"
     21#include "invoke.h"
     22
     23//-----------------------------------------------------------------------------
     24// Coroutine trait
     25// Anything that implements this trait can be resumed.
     26// Anything that is resumed is a coroutine.
     27trait is_coroutine(dtype T) {
     28      void main(T * this);
     29      coroutine * get_coroutine(T * this);
     30};
     31
     32#define DECL_COROUTINE(X) static inline coroutine* get_coroutine(X* this) { return &this->c; } void main(X* this);
     33
     34//-----------------------------------------------------------------------------
     35// Ctors and dtors
     36void ?{}(coStack_t * this);
     37void ?{}(coroutine * this);
     38void ^?{}(coStack_t * this);
     39void ^?{}(coroutine * this);
     40
     41//-----------------------------------------------------------------------------
     42// Public coroutine API
     43static inline void suspend();
     44
     45forall(dtype T | is_coroutine(T))
     46static inline void resume(T * cor);
     47
     48forall(dtype T | is_coroutine(T))
     49void prime(T * cor);
     50
     51//-----------------------------------------------------------------------------
     52// PRIVATE exposed because of inline
     53
     54// Start coroutine routines
     55extern "C" {
     56      forall(dtype T | is_coroutine(T))
     57      void CtxInvokeCoroutine(T * this);
     58
     59      forall(dtype T | is_coroutine(T))
     60      void CtxStart(T * this, void ( *invoke)(T *));
     61}
     62
     63// Get current coroutine
     64extern coroutine * current_coroutine; //PRIVATE, never use directly
     65static inline coroutine * this_coroutine(void) {
     66        return current_coroutine;
     67}
     68
     69// Private wrappers for context switch and stack creation
     70extern void corCxtSw(coroutine * src, coroutine * dst);
     71extern void create_stack( coStack_t * this, unsigned int storageSize );
     72
     73// Suspend implementation inlined for performance
     74static inline void suspend() {
     75      coroutine * src = this_coroutine();               // optimization
     76
     77        assertf( src->last != 0,
     78                "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
     79                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     80                src->name, src );
     81        assertf( src->last->notHalted,
     82                "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
     83                "Possible cause is terminated coroutine's main routine has already returned.",
     84                src->name, src, src->last->name, src->last );
     85
     86        corCxtSw( src, src->last );
     87}
     88
     89// Resume implementation inlined for performance
     90forall(dtype T | is_coroutine(T))
     91static inline void resume(T * cor) {
     92        coroutine * src = this_coroutine();             // optimization
     93        coroutine * dst = get_coroutine(cor);
     94
     95      if( unlikely(!dst->stack.base) ) {
     96                create_stack(&dst->stack, dst->stack.size);
     97                CtxStart(cor, CtxInvokeCoroutine);
     98        }
     99
     100      // not resuming self ?
     101        if ( src != dst ) {
     102                assertf( dst->notHalted ,
     103                        "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n"
     104                        "Possible cause is terminated coroutine's main routine has already returned.",
     105                        src->name, src, dst->name, dst );
     106
     107            // set last resumer
     108                dst->last = src;
     109        } // if
     110
     111      // always done for performance testing
     112        corCxtSw( src, dst );
     113}
     114
     115#endif //COROUTINES_H
     116
     117// Local Variables: //
     118// mode: c //
     119// tab-width: 4 //
     120// End: //
  • src/libcfa/concurrency/coroutines.c

    r765aa76 r4a3386b4  
     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// coroutines.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
     25#include "coroutines"
     26#include "libhdr.h"
     27
     28#define __CFA_INVOKE_PRIVATE__
     29#include "invoke.h"
     30
     31//-----------------------------------------------------------------------------
     32// Global state variables
     33
     34// minimum feasible stack size in bytes
     35#define MinStackSize 1000
     36static size_t pageSize = 0;                             // architecture pagesize HACK, should go in proper runtime singleton
     37
     38//Current coroutine
     39//Will need to be in TLS when multi-threading is added
     40coroutine* current_coroutine;
     41
     42//-----------------------------------------------------------------------------
     43// Coroutine ctors and dtors
     44void ?{}(coStack_t* this) {
     45        this->size              = 10240;        // size of stack
     46        this->storage   = NULL; // pointer to stack
     47        this->limit             = NULL; // stack grows towards stack limit
     48        this->base              = NULL; // base of stack
     49        this->context   = NULL; // address of cfa_context_t
     50        this->top               = NULL; // address of top of storage
     51        this->userStack = false;       
     52}
     53
     54void ?{}(coStack_t* this, size_t size) {
     55        this{};
     56        this->size = size;
     57
     58        create_stack(this, this->size);
     59}
     60
     61void ?{}(coroutine* this) {
     62        this->name = "Anonymous Coroutine";
     63        this->errno_ = 0;
     64        this->state = Start;
     65      this->notHalted = true;
     66        this->starter = NULL;
     67        this->last = NULL;
     68}
     69
     70void ?{}(coroutine* this, size_t size) {
     71        this{};
     72        (&this->stack){size};
     73}
     74
     75void ^?{}(coStack_t* this) {
     76        if ( ! this->userStack ) {
     77                LIB_DEBUG_DO(
     78                        if ( mprotect( this->storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) {
     79                                abortf( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", this, errno, strerror( errno ) );
     80                        }
     81                );
     82                free( this->storage );
     83        }
     84}
     85
     86void ^?{}(coroutine* this) {}
     87
     88// Part of the Public API
     89// Not inline since only ever called once per coroutine
     90forall(dtype T | is_coroutine(T))
     91void prime(T* cor) {
     92        coroutine* this = get_coroutine(cor);
     93        assert(this->state == Start);
     94
     95        this->state = Primed;
     96        resume(cor);
     97}
     98
     99// We need to call suspend from invoke.c, so we expose this wrapper that
     100// is not inline (We can't inline Cforall in C)
     101void suspend_no_inline(void) {
     102        LIB_DEBUG_PRINTF("Suspending back : to %p from %p\n", this_coroutine(), this_coroutine() ? this_coroutine()->last : (void*)-1);
     103
     104        suspend();
     105}
     106
     107void corCxtSw(coroutine* src, coroutine* dst) {
     108        // THREAD_GETMEM( This )->disableInterrupts();
     109
     110        // set state of current coroutine to inactive
     111        src->state = Inactive;
     112
     113        // set new coroutine that task is executing
     114        current_coroutine = dst;                       
     115
     116        // context switch to specified coroutine
     117        CtxSwitch( src->stack.context, dst->stack.context );
     118        // when CtxSwitch returns we are back in the src coroutine             
     119
     120        // set state of new coroutine to active
     121        src->state = Active;
     122
     123        // THREAD_GETMEM( This )->enableInterrupts();
     124} //ctxSwitchDirect
     125
     126void create_stack( coStack_t* this, unsigned int storageSize ) {
     127        //TEMP HACK do this on proper kernel startup
     128        if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
     129
     130        size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
     131
     132        if ( (intptr_t)this->storage == 0 ) {
     133                this->userStack = false;
     134                this->size = libCeiling( storageSize, 16 );
     135                // use malloc/memalign because "new" raises an exception for out-of-memory
     136               
     137                // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
     138                LIB_DEBUG_DO( this->storage = memalign( pageSize, cxtSize + this->size + pageSize ) );
     139                LIB_NO_DEBUG_DO( this->storage = malloc( cxtSize + this->size + 8 ) );
     140
     141                LIB_DEBUG_DO(
     142                        if ( mprotect( this->storage, pageSize, PROT_NONE ) == -1 ) {
     143                                abortf( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
     144                        } // if
     145                );
     146
     147                if ( (intptr_t)this->storage == 0 ) {
     148                        abortf( "Attempt to allocate %d bytes of storage for coroutine or task execution-state but insufficient memory available.", this->size );
     149                } // if
     150
     151                LIB_DEBUG_DO( this->limit = (char *)this->storage + pageSize );
     152                LIB_NO_DEBUG_DO( this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ) ); // minimum alignment
     153
     154        } else {
     155                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() );
     156                this->userStack = true;
     157                this->size = storageSize - cxtSize;
     158
     159                if ( this->size % 16 != 0u ) this->size -= 8;
     160
     161                this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ); // minimum alignment
     162        } // if
     163        assertf( this->size >= MinStackSize, "Stack size %d provides less than minimum of %d bytes for a stack.", this->size, MinStackSize );
     164
     165        this->base = (char *)this->limit + this->size;
     166        this->context = this->base;
     167        this->top = (char *)this->context + cxtSize;
     168}
     169
     170// Local Variables: //
     171// mode: c //
     172// tab-width: 4 //
     173// End: //
  • src/libcfa/concurrency/invoke.c

    r765aa76 r4a3386b4  
    1414
    1515extern void __suspend_no_inline__F___1(void);
     16extern void __scheduler_remove__F_P9sthread_h__1(struct thread_h*);
    1617
    1718void CtxInvokeCoroutine(
     
    2021      void *this
    2122) {
    22       LIB_DEBUG_PRINTF("Invoke : Received %p (main %p, get_c %p)\n", this, main, get_coroutine);
     23      // LIB_DEBUG_PRINTF("Invoke Coroutine : Received %p (main %p, get_c %p)\n", this, main, get_coroutine);
    2324
    2425      struct coroutine* cor = get_coroutine( this );
     
    3132
    3233      main( this );
     34
     35      //Final suspend, should never return
     36      __suspend_no_inline__F___1();
     37      assertf(false, "Resumed dead coroutine");
     38}
     39
     40void CtxInvokeThread(
     41      void (*main)(void *),
     42      struct thread_h *(*get_thread)(void *),
     43      void *this
     44) {
     45      // LIB_DEBUG_PRINTF("Invoke Thread : Received %p (main %p, get_t %p)\n", this, main, get_thread);
     46
     47      __suspend_no_inline__F___1();
     48
     49      struct thread_h* thrd = get_thread( this );
     50      struct coroutine* cor = &thrd->c;
     51      cor->state = Active;
     52
     53      // LIB_DEBUG_PRINTF("Invoke Thread : invoking main %p (args %p)\n", main, this);
     54      main( this );
     55
     56      __scheduler_remove__F_P9sthread_h__1(thrd);
     57
     58      //Final suspend, should never return
     59      __suspend_no_inline__F___1();
     60      assertf(false, "Resumed dead thread");
    3361}
    3462
     
    4068      void (*invoke)(void *)
    4169) {
    42       LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (main %p, get_c %p) to %p\n", this, main, get_coroutine, invoke);
     70      // LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (main %p) to invoke (%p) from start (%p)\n", this, main, invoke, CtxStart);
    4371
    4472      struct coStack_t* stack = &get_coroutine( this )->stack;
  • src/libcfa/concurrency/invoke.h

    r765aa76 r4a3386b4  
    3535      };
    3636
     37      struct thread_h {
     38            struct coroutine c;
     39      };
     40
    3741#endif //_INVOKE_H_
    3842#else //! defined(__CFA_INVOKE_PRIVATE__)
     
    4852      // assembler routines that performs the context switch
    4953      extern void CtxInvokeStub( void );
    50       void CtxSwitch( void *from, void *to ) asm ("CtxSwitch");
     54      void CtxSwitch( void * from, void * to ) asm ("CtxSwitch");
     55      void CtxGet( void * this ) asm ("CtxGet");
    5156
    5257#endif //_INVOKE_PRIVATE_H_
  • src/libcfa/concurrency/kernel

    r765aa76 r4a3386b4  
     1//                              -*- Mode: CFA -*-
     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// threads --
     9//
     10// Author           : Thierry Delisle
     11// Created On       : Tue Jan 17 12:27:26 2016
     12// Last Modified By : Thierry Delisle
     13// Last Modified On : --
     14// Update Count     : 0
     15//
     16
     17#ifndef KERNEL_H
     18#define KERNEL_H
     19
     20#include <stdbool.h>
     21
     22struct processor {
     23        struct processorCtx_t * ctx;
     24        unsigned int thread_index;
     25        unsigned int thread_count;
     26        struct thread_h * threads[10];
     27        bool terminated;
     28};
     29
     30void ?{}(processor * this);
     31void ^?{}(processor * this);
     32
     33void scheduler_add( struct thread_h * thrd );
     34void scheduler_remove( struct thread_h * thrd );
     35void kernel_run( void );
     36
     37#endif //KERNEL_H
     38
     39// Local Variables: //
     40// mode: c //
     41// tab-width: 4 //
     42// End: //
  • src/libcfa/concurrency/kernel.c

    r765aa76 r4a3386b4  
     1//                              -*- Mode: CFA -*-
     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// kernel.c --
     9//
     10// Author           : Thierry Delisle
     11// Created On       : Tue Jan 17 12:27:26 2016
     12// Last Modified By : Thierry Delisle
     13// Last Modified On : --
     14// Update Count     : 0
     15//
     16
     17//Header
     18#include "kernel"
     19
     20//C Includes
     21#include <stddef.h>
     22extern "C" {
     23#include <sys/resource.h>
     24}
     25
     26//CFA Includes
     27#include "libhdr.h"
     28#include "threads"
     29
     30//Private includes
     31#define __CFA_INVOKE_PRIVATE__
     32#include "invoke.h"
     33
     34processor * systemProcessor;
     35thread_h * mainThread;
     36
     37void kernel_startup(void)  __attribute__((constructor(101)));
     38void kernel_shutdown(void) __attribute__((destructor(101)));
     39
     40void ?{}(processor * this) {
     41        this->ctx = NULL;
     42        this->thread_index = 0;
     43        this->thread_count = 10;
     44        this->terminated = false;
     45
     46        for(int i = 0; i < 10; i++) {
     47                this->threads[i] = NULL;
     48        }
     49
     50        LIB_DEBUG_PRINTF("Processor : ctor for core %p (core spots %d)\n", this, this->thread_count);
     51}
     52
     53void ^?{}(processor * this) {
     54
     55}
     56
     57//-----------------------------------------------------------------------------
     58// Processor coroutine
     59struct processorCtx_t {
     60        processor * proc;
     61        coroutine c;
     62};
     63
     64DECL_COROUTINE(processorCtx_t)
     65
     66void ?{}(processorCtx_t * this, processor * proc) {
     67        (&this->c){};
     68        this->proc = proc;
     69}
     70
     71void CtxInvokeProcessor(processor * proc) {
     72        processorCtx_t proc_cor_storage = {proc};
     73        resume( &proc_cor_storage );
     74}
     75
     76//-----------------------------------------------------------------------------
     77// Processor running routines
     78void main(processorCtx_t * ctx);
     79thread_h * nextThread(processor * this);
     80void runThread(processor * this, thread_h * dst);
     81void spin(processor * this, unsigned int * spin_count);
     82
     83void main(processorCtx_t * ctx) {
     84        processor * this = ctx->proc;
     85        LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
     86
     87        thread_h * readyThread = NULL;
     88        for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
     89               
     90                readyThread = nextThread(this);
     91
     92                if(readyThread) {
     93                        runThread(this, readyThread);
     94                        spin_count = 0;
     95                } else {
     96                        spin(this, &spin_count);
     97                }               
     98        }
     99
     100        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
     101}
     102
     103thread_h * nextThread(processor * this) {
     104        for(int i = 0; i < this->thread_count; i++) {
     105                this->thread_index = (this->thread_index + 1) % this->thread_count;     
     106               
     107                thread_h * thrd = this->threads[this->thread_index];
     108                if(thrd) return thrd;
     109        }
     110
     111        return NULL;
     112}
     113
     114void runThread(processor * this, thread_h * dst) {
     115        coroutine * proc_ctx = get_coroutine(this->ctx);
     116        coroutine * thrd_ctx = get_coroutine(dst);
     117        thrd_ctx->last = proc_ctx;
     118
     119        // context switch to specified coroutine
     120        // Which is now the current_coroutine
     121        LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     122        current_coroutine = thrd_ctx;
     123        CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
     124        current_coroutine = proc_ctx;
     125        LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     126
     127        // when CtxSwitch returns we are back in the processor coroutine
     128}
     129
     130void spin(processor * this, unsigned int * spin_count) {
     131        (*spin_count)++;
     132}
     133
     134//-----------------------------------------------------------------------------
     135// Kernel runner (Temporary)
     136
     137void scheduler_add( thread_h * thrd ) {
     138        LIB_DEBUG_PRINTF("Kernel : scheduling %p on core %p (%d spots)\n", thrd, systemProcessor, systemProcessor->thread_count);
     139        for(int i = 0; i < systemProcessor->thread_count; i++) {
     140                if(systemProcessor->threads[i] == NULL) {
     141                        systemProcessor->threads[i] = thrd;
     142                        return;
     143                }
     144        }
     145        assert(false);
     146}
     147
     148void scheduler_remove( thread_h * thrd ) {
     149        LIB_DEBUG_PRINTF("Kernel : unscheduling %p from core %p\n", thrd, systemProcessor);
     150        for(int i = 0; i < systemProcessor->thread_count; i++) {
     151                if(systemProcessor->threads[i] == thrd) {
     152                        systemProcessor->threads[i] = NULL;
     153                        break;
     154                }
     155        }
     156        for(int i = 0; i < systemProcessor->thread_count; i++) {
     157                if(systemProcessor->threads[i] != NULL) {
     158                        return;
     159                }
     160        }
     161        LIB_DEBUG_PRINTF("Kernel : terminating core %p\n", systemProcessor);   
     162        systemProcessor->terminated = true;
     163}
     164
     165//-----------------------------------------------------------------------------
     166// Kernel storage
     167#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
     168
     169KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
     170KERNEL_STORAGE(processor, systemProcessor);
     171KERNEL_STORAGE(thread_h, mainThread);
     172KERNEL_STORAGE(machine_context_t, mainThread_context);
     173
     174//-----------------------------------------------------------------------------
     175// Main thread construction
     176struct mainThread_info_t {
     177        machine_context_t ctx; 
     178        unsigned int size;              // size of stack
     179        void *base;                             // base of stack
     180        void *storage;                  // pointer to stack
     181        void *limit;                    // stack grows towards stack limit
     182        void *context;                  // address of cfa_context_t
     183        void *top;                              // address of top of storage
     184};
     185
     186void ?{}( mainThread_info_t * this ) {
     187        CtxGet( &this->ctx );
     188        this->base = this->ctx.FP;
     189        this->storage = this->ctx.SP;
     190
     191        rlimit r;
     192        int ret = getrlimit( RLIMIT_STACK, &r);
     193        this->size = r.rlim_cur;
     194
     195        this->limit = (void *)(((intptr_t)this->base) - this->size);
     196        this->context = &mainThread_context_storage;
     197        this->top = this->base;
     198}
     199
     200void ?{}( coStack_t * this, mainThread_info_t * info) {
     201        this->size = info->size;
     202        this->storage = info->storage;
     203        this->limit = info->limit;
     204        this->base = info->base;
     205        this->context = info->context;
     206        this->top = info->top;
     207        this->userStack = true;
     208}
     209
     210void ?{}( coroutine * this, mainThread_info_t * info) {
     211        (&this->stack){ info };
     212        this->name = "Main Thread";
     213        this->errno_ = 0;
     214        this->state = Inactive;
     215        this->notHalted = true;
     216}
     217
     218void ?{}( thread_h * this, mainThread_info_t * info) {
     219        (&this->c){ info };
     220}
     221
     222//-----------------------------------------------------------------------------
     223// Kernel boot procedures
     224void kernel_startup(void) {
     225
     226        // SKULLDUGGERY: the mainThread steals the process main thread
     227        // which will then be scheduled by the systemProcessor normally
     228        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
     229
     230        mainThread_info_t ctx;
     231        LIB_DEBUG_PRINTF("Kernel :    base : %p\n", ctx.base );
     232        LIB_DEBUG_PRINTF("Kernel :     top : %p\n", ctx.top );
     233        LIB_DEBUG_PRINTF("Kernel :   limit : %p\n", ctx.limit );
     234        LIB_DEBUG_PRINTF("Kernel :    size : %x\n", ctx.size );
     235        LIB_DEBUG_PRINTF("Kernel : storage : %p\n", ctx.storage );
     236        LIB_DEBUG_PRINTF("Kernel : context : %p\n", ctx.context );
     237
     238        // Start by initializing the main thread
     239        mainThread = (thread_h *)&mainThread_storage;
     240        LIB_DEBUG_PRINTF("Kernel : Main thread : %p\n", mainThread );
     241        mainThread{ &ctx };
     242
     243        // // Initialize the system processor
     244        systemProcessor = (processor *)&systemProcessor_storage;
     245        systemProcessor{};
     246
     247        // Initialize the system processor ctx
     248        // (the coroutine that contains the processing control flow)
     249        systemProcessor->ctx = (processorCtx_t *)&systemProcessorCtx_storage;
     250        systemProcessor->ctx{ systemProcessor };
     251
     252        scheduler_add(mainThread);
     253
     254        current_coroutine = &mainThread->c;
     255
     256        LIB_DEBUG_PRINTF("Kernel : Starting system processor\n");       
     257        resume(systemProcessor->ctx);
     258
     259        LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
     260}
     261void kernel_shutdown(void) {
     262        LIB_DEBUG_PRINTF("\n--------------------------------------------------\nKernel : Shutting down");
     263
     264        LIB_DEBUG_PRINTF("Unscheduling main thread\n");
     265        scheduler_remove(mainThread);
     266
     267        LIB_DEBUG_PRINTF("Suspending main\n");
     268        suspend();
     269
     270        LIB_DEBUG_PRINTF("Kernel : Control return to initial process thread\n");
     271
     272        ^(systemProcessor->ctx){};
     273        ^(systemProcessor){};
     274
     275        ^(mainThread){};
     276
     277        LIB_DEBUG_PRINTF("Kernel : Shutdown complete\n");       
     278}
     279
     280// Local Variables: //
     281// mode: c //
     282// tab-width: 4 //
     283// End: //
  • src/libcfa/concurrency/threads

    r765aa76 r4a3386b4  
    99//
    1010// Author           : Thierry Delisle
    11 // Created On       : Mon Nov 28 12:27:26 2016
     11// Created On       : Tue Jan 17 12:27:26 2016
    1212// Last Modified By : Thierry Delisle
    13 // Last Modified On : Mon Nov 28 12:27:26 2016
     13// Last Modified On : --
    1414// Update Count     : 0
    1515//
     
    1818#define THREADS_H
    1919
    20 #include "assert"       //
     20#include "assert"
    2121#include "invoke.h"
     22
     23#include "coroutines"
    2224
    2325//-----------------------------------------------------------------------------
     
    2527// Anything that implements this trait can be resumed.
    2628// Anything that is resumed is a coroutine.
    27 trait is_coroutine(dtype T) {
    28       void co_main(T* this);
    29       coroutine* get_coroutine(T* this);
     29trait is_thread(dtype T /*| sized(T)*/) {
     30      void main(T* this);
     31      thread_h* get_thread(T* this);
     32        /*void ?{}(T*);
     33        void ^?{}(T*);*/
    3034};
     35
     36forall(otype T | is_thread(T) )
     37static inline coroutine* get_coroutine(T* this) {
     38        return &get_thread(this)->c;
     39}
     40
     41static inline coroutine* get_coroutine(thread_h* this) {
     42        return &this->c;
     43}
    3144
    3245//-----------------------------------------------------------------------------
    3346// Ctors and dtors
    34 void ?{}(coStack_t* this);
    35 void ?{}(coroutine* this);
    36 void ^?{}(coStack_t* this);
    37 void ^?{}(coroutine* this);
     47void ?{}(thread_h* this);
     48void ^?{}(thread_h* this);
    3849
    3950//-----------------------------------------------------------------------------
    40 // Public coroutine API
    41 static inline void suspend();
     51// thread runner
     52// Structure that actually start and stop threads
     53forall(otype T | is_thread(T) )
     54struct thread {
     55        T handle;
     56};
    4257
    43 forall(dtype T | is_coroutine(T))
    44 static inline void resume(T* cor);
     58forall(otype T | is_thread(T) )
     59void ?{}( thread(T)* this );
    4560
    46 forall(dtype T | is_coroutine(T))
    47 void prime(T* cor);
     61forall(otype T, ttype P | is_thread(T) | { void ?{}(T*, P); } )
     62void ?{}( thread(T)* this, P params );
     63
     64forall(otype T | is_thread(T) )
     65void ^?{}( thread(T)* this );
    4866
    4967//-----------------------------------------------------------------------------
    5068// PRIVATE exposed because of inline
    51 
    52 // Start coroutine routines
    53 extern "C" {
    54       forall(dtype T | is_coroutine(T))
    55       void CtxInvokeCoroutine(T* this);
    56 
    57       forall(dtype T | is_coroutine(T))
    58       void CtxStart(T* this, void (*invoke)(T*));
    59 }
    60 
    61 // Get current coroutine
    62 extern coroutine* current_coroutine; //PRIVATE, never use directly
    63 static inline coroutine* this_coroutine(void) {
    64         return current_coroutine;
    65 }
    66 
    67 // Private wrappers for context switch and stack creation
    68 extern void corCxtSw(coroutine* src, coroutine* dst);
    69 extern void create_stack( coStack_t* this, unsigned int storageSize );
    70 
    71 // Suspend implementation inlined for performance
    72 static inline void suspend() {
    73       coroutine* src = this_coroutine();                // optimization
    74 
    75         assertf( src->last != 0,
    76                 "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
    77                 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    78                 src->name, src );
    79         assertf( src->last->notHalted,
    80                 "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
    81                 "Possible cause is terminated coroutine's main routine has already returned.",
    82                 src->name, src, src->last->name, src->last );
    83 
    84         corCxtSw( src, src->last );
    85 }
    86 
    87 // Resume implementation inlined for performance
    88 forall(dtype T | is_coroutine(T))
    89 static inline void resume(T* cor) {
    90         coroutine* src = this_coroutine();              // optimization
    91         coroutine* dst = get_coroutine(cor);
    92 
    93       if( unlikely(!dst->stack.base) ) {
    94                 create_stack(&dst->stack, dst->stack.size);
    95                 CtxStart(cor, CtxInvokeCoroutine);
    96         }
    97 
    98       // not resuming self ?
    99         if ( src != dst ) {
    100                 assertf( dst->notHalted ,
    101                         "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n"
    102                         "Possible cause is terminated coroutine's main routine has already returned.",
    103                         src->name, src, dst->name, dst );
    104 
    105             // set last resumer
    106                 dst->last = src;
    107         } // if
    108 
    109       // always done for performance testing
    110         corCxtSw( src, dst );
    111 }
    11269
    11370#endif //THREADS_H
  • src/libcfa/concurrency/threads.c

    r765aa76 r4a3386b4  
     1//                              -*- Mode: CFA -*-
    12//
    23// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
     
    89//
    910// Author           : Thierry Delisle
    10 // Created On       : Mon Nov 28 12:27:26 2016
     11// Created On       : Tue Jan 17 12:27:26 2016
    1112// Last Modified By : Thierry Delisle
    12 // Last Modified On : Mon Nov 28 12:27:26 2016
     13// Last Modified On : --
    1314// Update Count     : 0
    1415//
    1516
    16 extern "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 }
     17#include "threads"
    2418
    25 #include "threads"
     19#include "kernel"
    2620#include "libhdr.h"
    2721
     
    2923#include "invoke.h"
    3024
    31 //-----------------------------------------------------------------------------
    32 // Global state variables
    33 
    34 // minimum feasible stack size in bytes
    35 #define MinStackSize 1000
    36 static size_t pageSize = 0;                             // architecture pagesize HACK, should go in proper runtime singleton
    37 
    38 //Extra private desctructor for the main
    39 //FIXME the main should not actually allocate a stack
    40 //Since the main is never resumed the extra stack does not cause
    41 //any problem but it is wasted memory
    42 void ?{}(coStack_t* this, size_t size);
    43 void ?{}(coroutine* this, size_t size);
    44 
    45 //Main coroutine
    46 //FIXME do not construct a stack for the main
    47 coroutine main_coroutine = { 1000 };
    48 
    49 //Current coroutine
    50 //Will need to be in TLS when multi-threading is added
    51 coroutine* current_coroutine = &main_coroutine;
     25#include <stdlib>
    5226
    5327//-----------------------------------------------------------------------------
    54 // Coroutine ctors and dtors
    55 void ?{}(coStack_t* this) {
    56         this->size              = 10240;        // size of stack
    57         this->storage   = NULL; // pointer to stack
    58         this->limit             = NULL; // stack grows towards stack limit
    59         this->base              = NULL; // base of stack
    60         this->context   = NULL; // address of cfa_context_t
    61         this->top               = NULL; // address of top of storage
    62         this->userStack = false;       
     28// Forward declarations
     29forall(otype T | is_thread(T) )
     30void start( thread(T)* this );
     31
     32forall(otype T | is_thread(T) )
     33void stop( thread(T)* this );
     34
     35//-----------------------------------------------------------------------------
     36// Thread ctors and dtors
     37
     38void ?{}(thread_h* this) {
     39        (&this->c){};
    6340}
    6441
    65 void ?{}(coStack_t* this, size_t size) {
    66         this{};
    67         this->size = size;
    68 
    69         create_stack(this, this->size);
     42void ^?{}(thread_h* this) {
     43        ^(&this->c){};
    7044}
    7145
    72 void ?{}(coroutine* this) {
    73         this->name = "Anonymous Coroutine";
    74         this->errno_ = 0;
    75         this->state = Start;
    76       this->notHalted = true;
    77         this->starter = NULL;
    78         this->last = NULL;
     46forall(otype T | is_thread(T) )
     47void ?{}( thread(T)* this ) {
     48        printf("thread() ctor\n");
     49        (&this->handle){};
     50        start(this);
    7951}
    8052
    81 void ?{}(coroutine* this, size_t size) {
    82         this{};
    83         (&this->stack){size};
     53forall(otype T, ttype P | is_thread(T) | { void ?{}(T*, P); } )
     54void ?{}( thread(T)* this, P params ) {
     55        (&this->handle){ params };
     56        start(this);
    8457}
    8558
    86 void ^?{}(coStack_t* this) {
    87         if ( ! this->userStack ) {
    88                 LIB_DEBUG_DO(
    89                         if ( mprotect( this->storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) {
    90                                 abortf( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", this, errno, strerror( errno ) );
    91                         }
    92                 );
    93                 free( this->storage );
    94         }
     59forall(otype T | is_thread(T) )
     60void ^?{}( thread(T)* this ) {
     61        stop(this);
     62        ^(&this->handle){};
    9563}
    9664
    97 void ^?{}(coroutine* this) {}
    98 
    99 // Part of the Public API
    100 // Not inline since only ever called once per coroutine
    101 forall(dtype T | is_coroutine(T))
    102 void prime(T* cor) {
    103         coroutine* this = get_coroutine(cor);
    104         assert(this->state == Start);
    105 
    106         this->state = Primed;
    107         resume(cor);
     65//-----------------------------------------------------------------------------
     66// Starting and stopping threads
     67extern "C" {
     68      forall(dtype T | is_thread(T))
     69      void CtxInvokeThread(T * this);
    10870}
    10971
    110 // We need to call suspend from invoke.c, so we expose this wrapper that
    111 // is not inline (We can't inline Cforall in C)
    112 void suspend_no_inline(void) {
    113         suspend();
     72forall(otype T | is_thread(T))
     73void start( thread(T)* this ) {
     74        T* handle  = &this->handle;
     75        coroutine* thrd_c = get_coroutine(handle);
     76        thread_h*  thrd_h = get_thread   (handle);
     77        thrd_c->last = this_coroutine();
     78        current_coroutine = thrd_c;
     79
     80        // LIB_DEBUG_PRINTF("Thread start : %p (t %p, c %p)\n", handle, thrd_c, thrd_h);
     81
     82        create_stack(&thrd_c->stack, thrd_c->stack.size);
     83        CtxStart(handle, CtxInvokeThread);
     84        CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context );
     85
     86        scheduler_add(thrd_h);
    11487}
    11588
    116 void corCxtSw(coroutine* src, coroutine* dst) {
    117         // THREAD_GETMEM( This )->disableInterrupts();
     89forall(otype T | is_thread(T) )
     90void stop( thread(T)* this ) {
    11891
    119         // set state of current coroutine to inactive
    120         src->state = Inactive;
    121 
    122         // set new coroutine that task is executing
    123         current_coroutine = dst;                       
    124 
    125         // context switch to specified coroutine
    126         CtxSwitch( src->stack.context, dst->stack.context );
    127         // when CtxSwitch returns we are back in the src coroutine             
    128 
    129         // set state of new coroutine to active
    130         src->state = Active;
    131 
    132         // THREAD_GETMEM( This )->enableInterrupts();
    133 } //ctxSwitchDirect
    134 
    135 void create_stack( coStack_t* this, unsigned int storageSize ) {
    136         //TEMP HACK do this on proper kernel startup
    137         if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
    138 
    139         size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
    140 
    141         if ( (intptr_t)this->storage == 0 ) {
    142                 this->userStack = false;
    143                 this->size = libCeiling( storageSize, 16 );
    144                 // use malloc/memalign because "new" raises an exception for out-of-memory
    145                
    146                 // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
    147                 LIB_DEBUG_DO( this->storage = memalign( pageSize, cxtSize + this->size + pageSize ) );
    148                 LIB_NO_DEBUG_DO( this->storage = malloc( cxtSize + this->size + 8 ) );
    149 
    150                 LIB_DEBUG_DO(
    151                         if ( mprotect( this->storage, pageSize, PROT_NONE ) == -1 ) {
    152                                 abortf( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
    153                         } // if
    154                 );
    155 
    156                 if ( (intptr_t)this->storage == 0 ) {
    157                         abortf( "Attempt to allocate %d bytes of storage for coroutine or task execution-state but insufficient memory available.", this->size );
    158                 } // if
    159 
    160                 LIB_DEBUG_DO( this->limit = (char *)this->storage + pageSize );
    161                 LIB_NO_DEBUG_DO( this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ) ); // minimum alignment
    162 
    163         } else {
    164                 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() );
    165                 this->userStack = true;
    166                 this->size = storageSize - cxtSize;
    167 
    168                 if ( this->size % 16 != 0u ) this->size -= 8;
    169 
    170                 this->limit = (char *)libCeiling( (unsigned long)this->storage, 16 ); // minimum alignment
    171         } // if
    172         assertf( this->size >= MinStackSize, "Stack size %d provides less than minimum of %d bytes for a stack.", this->size, MinStackSize );
    173 
    174         this->base = (char *)this->limit + this->size;
    175         this->context = this->base;
    176         this->top = (char *)this->context + cxtSize;
    17792}
    17893
Note: See TracChangeset for help on using the changeset viewer.