Changes in / [4a9ccc3:ad6343e]


Ignore:
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/concurrency/thePlan.md

    r4a9ccc3 rad6343e  
    44done - SimpleBlockingLock.
    55done - Synchronisation points in thread destructors.
    6 Processors & SpinLock.
     6done - Processors & SpinLock.
    77
    88_Phase 2_ : Minimum Viable Product
    9 Basic monitors for synchronisation (No internal/external scheduling).
    10 Non-thrash scheduler.
    11 Clusters.
     9Monitor type and enter/leave mutex member routines
     10Monitors as a language feature (not calling enter/leave by hand)
     11Internal scheduling
    1212
    1313_Phase 3_ : Kernel features
    14 Threads features ex: detach
    15 Internal scheduling
     14Detach thread
     15Cluster migration
     16Preemption
    1617
    1718_Phase 4_ : Monitor features
  • src/driver/cfa.cc

    r4a9ccc3 rad6343e  
    267267                }
    268268                nargs += 1;
     269                args[nargs] = "-lpthread";
     270                nargs += 1;
    269271        } // if
    270272#endif //HAVE_LIBCFA
  • src/examples/thread.c

    r4a9ccc3 rad6343e  
     1#line 1 "thread.c"
    12#include <fstream>
     3#include <kernel>
    24#include <stdlib>
    35#include <threads>
     
    1012};
    1113
    12 // DECL_THREAD(MyThread)
     14DECL_THREAD(MyThread)
     15
     16void ?{}( MyThread * this ) {
     17}
    1318
    1419void ?{}( MyThread * this, unsigned id, unsigned count ) {
     
    1722}
    1823
    19 // void main(MyThread* this) {
    20 //      sout | "Thread" | this->id | " : Suspending" | this->count | "times" | endl;
    21 //      yield();
     24void main(MyThread* this) {
     25        sout | "Thread" | this->id | " : Suspending" | this->count | "times" | endl;
     26        yield();
    2227
    23 //      for(int i = 0; i < this->count; i++) {
    24 //              sout | "Thread" | this->id | " : Suspend No." | i + 1 | endl;
    25 //              yield();
    26 //      }
    27 // }
     28        for(int i = 0; i < this->count; i++) {
     29                sout | "Thread" | this->id | " : Suspend No." | i + 1 | endl;
     30                yield();
     31        }
     32}
    2833
    2934int main(int argc, char* argv[]) {
    3035
    31         // unsigned itterations = 10u;
    32         // if(argc == 2) {
    33         //      int val = ato(argv[1]);
    34         //      assert(val >= 0);
    35         //      itterations = val;
    36         // }
     36        unsigned itterations = 10u;
     37        if(argc == 2) {
     38                int val = ato(argv[1]);
     39                assert(val >= 0);
     40                itterations = val;
     41        }
    3742
    3843        sout | "User main begin" | endl;
    3944
    40         // {
    41         //      thread(MyThread) thread1 = { 1u, itterations };
    42         //      thread(MyThread) thread2 = { 2u, itterations };
    43         // }
     45        {
     46                processor p;
     47                {
     48                        thread(MyThread) thread1 = { 1u, itterations };
     49                        thread(MyThread) thread2 = { 2u, itterations };
     50                }
     51        }
    4452
    4553        sout | "User main end" | endl;
  • src/libcfa/concurrency/coroutines

    r4a9ccc3 rad6343e  
    7373
    7474        assertf( src->last != 0,
    75                 "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n"
     75                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
    7676                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    7777                src->name, src );
    7878        assertf( src->last->notHalted,
    79                 "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n"
     79                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
    8080                "Possible cause is terminated coroutine's main routine has already returned.",
    8181                src->name, src, src->last->name, src->last );
  • src/libcfa/concurrency/coroutines.c

    r4a9ccc3 rad6343e  
     1//                              -*- Mode: CFA -*-
    12//
    23// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
     
    3132#include "invoke.h"
    3233
    33 /*thread_local*/ extern processor * this_processor;
     34extern processor * get_this_processor();
    3435
    3536//-----------------------------------------------------------------------------
     
    110111
    111112        // set new coroutine that task is executing
    112         this_processor->current_coroutine = dst;                       
     113        get_this_processor()->current_coroutine = dst;                 
    113114
    114115        // context switch to specified coroutine
  • src/libcfa/concurrency/invoke.c

    r4a9ccc3 rad6343e  
     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// invoke.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//
    116
    217#include <stdbool.h>
  • src/libcfa/concurrency/invoke.h

    r4a9ccc3 rad6343e  
     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// invoke.h --
     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
    117#include <stdbool.h>
    218#include <stdint.h>
     
    1127
    1228      #define unlikely(x)    __builtin_expect(!!(x), 0)
     29      #define thread_local _Thread_local
    1330      #define SCHEDULER_CAPACITY 10
    1431
  • src/libcfa/concurrency/kernel

    r4a9ccc3 rad6343e  
    2222#include "invoke.h"
    2323
     24extern "C" {
     25#include <pthread.h>
     26}
     27
    2428//-----------------------------------------------------------------------------
    2529// Cluster
    2630struct cluster {
    2731        simple_thread_list ready_queue;
     32        pthread_spinlock_t lock;
    2833};
    2934
     
    3843        coroutine * current_coroutine;
    3944        thread_h * current_thread;
    40         bool terminated;
     45        pthread_t kernel_thread;
     46        simple_lock lock;
     47        volatile bool terminated;
    4148};
    4249
     50void ?{}(processor * this);
    4351void ?{}(processor * this, cluster * cltr);
    4452void ^?{}(processor * this);
     
    5462void unlock( simple_lock * );
    5563
     64struct pthread_spinlock_guard {
     65        pthread_spinlock_t * lock;
     66};
     67
     68static inline void ?{}( pthread_spinlock_guard * this, pthread_spinlock_t * lock ) {
     69        this->lock = lock;
     70        pthread_spin_lock( this->lock );
     71}
     72
     73static inline void ^?{}( pthread_spinlock_guard * this ) {
     74        pthread_spin_unlock( this->lock );
     75}
     76
     77// //Simple spinlock implementation from
     78// //http://stackoverflow.com/questions/1383363/is-my-spin-lock-implementation-correct-and-optimal
     79// //Not optimal but correct
     80// #define VOL
     81
     82// struct simple_spinlock {
     83//      VOL int lock;
     84// };
     85
     86// extern VOL int __sync_lock_test_and_set( VOL int *, VOL int);
     87// extern void __sync_synchronize();
     88
     89// static inline void lock( simple_spinlock * this ) {
     90//     while (__sync_lock_test_and_set(&this->lock, 1)) {
     91//         // Do nothing. This GCC builtin instruction
     92//         // ensures memory barrier.
     93//     }
     94// }
     95
     96// static inline void unlock( simple_spinlock * this ) {
     97//     __sync_synchronize(); // Memory barrier.
     98//     this->lock = 0;
     99// }
     100
    56101#endif //KERNEL_H
    57102
  • src/libcfa/concurrency/kernel.c

    r4a9ccc3 rad6343e  
    3232#include "invoke.h"
    3333
    34 cluster * systemCluster;
    35 processor * systemProcessor;
    36 thread_h * mainThread;
    37 
    38 void kernel_startup(void)  __attribute__((constructor(101)));
    39 void kernel_shutdown(void) __attribute__((destructor(101)));
    40 
    41 void ?{}(processor * this, cluster * cltr) {
    42         this->ctx = NULL;
    43         this->cltr = cltr;
    44         this->terminated = false;
    45 }
    46 
    47 void ^?{}(processor * this) {}
    48 
    49 void ?{}(cluster * this) {
    50         ( &this->ready_queue ){};
    51 }
    52 
    53 void ^?{}(cluster * this) {}
    54 
    55 //-----------------------------------------------------------------------------
    56 // Global state
    57 
    58 /*thread_local*/ processor * this_processor;
    59 
    60 coroutine * this_coroutine(void) {
    61         return this_processor->current_coroutine;
    62 }
    63 
    64 thread_h * this_thread(void) {
    65         return this_processor->current_thread;
    66 }
    67 
    68 //-----------------------------------------------------------------------------
    69 // Processor coroutine
     34//-----------------------------------------------------------------------------
     35// Kernel storage
    7036struct processorCtx_t {
    7137        processor * proc;
     
    7541DECL_COROUTINE(processorCtx_t)
    7642
     43#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
     44
     45KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
     46KERNEL_STORAGE(cluster, systemCluster);
     47KERNEL_STORAGE(processor, systemProcessor);
     48KERNEL_STORAGE(thread_h, mainThread);
     49KERNEL_STORAGE(machine_context_t, mainThread_context);
     50
     51cluster * systemCluster;
     52processor * systemProcessor;
     53thread_h * mainThread;
     54
     55void kernel_startup(void)  __attribute__((constructor(101)));
     56void kernel_shutdown(void) __attribute__((destructor(101)));
     57
     58//-----------------------------------------------------------------------------
     59// Global state
     60
     61thread_local processor * this_processor;
     62
     63processor * get_this_processor() {
     64        return this_processor;
     65}
     66
     67coroutine * this_coroutine(void) {
     68        return this_processor->current_coroutine;
     69}
     70
     71thread_h * this_thread(void) {
     72        return this_processor->current_thread;
     73}
     74
     75//-----------------------------------------------------------------------------
     76// Main thread construction
     77struct current_stack_info_t {
     78        machine_context_t ctx; 
     79        unsigned int size;              // size of stack
     80        void *base;                             // base of stack
     81        void *storage;                  // pointer to stack
     82        void *limit;                    // stack grows towards stack limit
     83        void *context;                  // address of cfa_context_t
     84        void *top;                              // address of top of storage
     85};
     86
     87void ?{}( current_stack_info_t * this ) {
     88        CtxGet( &this->ctx );
     89        this->base = this->ctx.FP;
     90        this->storage = this->ctx.SP;
     91
     92        rlimit r;
     93        int ret = getrlimit( RLIMIT_STACK, &r);
     94        this->size = r.rlim_cur;
     95
     96        this->limit = (void *)(((intptr_t)this->base) - this->size);
     97        this->context = &mainThread_context_storage;
     98        this->top = this->base;
     99}
     100
     101void ?{}( coStack_t * this, current_stack_info_t * info) {
     102        this->size = info->size;
     103        this->storage = info->storage;
     104        this->limit = info->limit;
     105        this->base = info->base;
     106        this->context = info->context;
     107        this->top = info->top;
     108        this->userStack = true;
     109}
     110
     111void ?{}( coroutine * this, current_stack_info_t * info) {
     112        (&this->stack){ info };
     113        this->name = "Main Thread";
     114        this->errno_ = 0;
     115        this->state = Inactive;
     116        this->notHalted = true;
     117}
     118
     119void ?{}( thread_h * this, current_stack_info_t * info) {
     120        (&this->c){ info };
     121}
     122
     123//-----------------------------------------------------------------------------
     124// Processor coroutine
    77125void ?{}(processorCtx_t * this, processor * proc) {
    78126        (&this->c){};
    79127        this->proc = proc;
    80 }
    81 
    82 void CtxInvokeProcessor(processor * proc) {
    83         processorCtx_t proc_cor_storage = {proc};
    84         resume( &proc_cor_storage );
     128        proc->ctx = this;
     129}
     130
     131void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) {
     132        (&this->c){ info };
     133        this->proc = proc;
     134        proc->ctx = this;
     135}
     136
     137void start(processor * this);
     138
     139void ?{}(processor * this) {
     140        this{ systemCluster };
     141}
     142
     143void ?{}(processor * this, cluster * cltr) {
     144        this->cltr = cltr;
     145        this->current_coroutine = NULL;
     146        this->current_thread = NULL;
     147        (&this->lock){};
     148        this->terminated = false;
     149
     150        start( this );
     151}
     152
     153void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {
     154        this->cltr = cltr;
     155        this->current_coroutine = NULL;
     156        this->current_thread = NULL;
     157        (&this->lock){};
     158        this->terminated = false;
     159
     160        this->ctx = ctx;
     161        LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", ctx);
     162        ctx{ this };
     163}
     164
     165void ^?{}(processor * this) {
     166        if( ! this->terminated ) {
     167                LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this);
     168                this->terminated = true;
     169                lock( &this->lock );
     170        }
     171}
     172
     173void ?{}(cluster * this) {
     174        ( &this->ready_queue ){};
     175        pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
     176}
     177
     178void ^?{}(cluster * this) {
     179        pthread_spin_destroy( &this->lock );
    85180}
    86181
     
    109204        }
    110205
     206        LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
     207        unlock( &this->lock );
    111208        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
    112209}
     
    133230}
    134231
     232void * CtxInvokeProcessor(void * arg) {
     233        processor * proc = (processor *) arg;
     234        this_processor = proc;
     235        // SKULLDUGGERY: We want to create a context for the processor coroutine
     236        // which is needed for the 2-step context switch. However, there is no reason
     237        // to waste the perfectly valid stack create by pthread.
     238        current_stack_info_t info;
     239        machine_context_t ctx;
     240        info.context = &ctx;
     241        processorCtx_t proc_cor_storage = { proc, &info };
     242
     243        proc->current_coroutine = &proc->ctx->c;
     244        proc->current_thread = NULL;
     245
     246        LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx);
     247
     248        // LIB_DEBUG_PRINTF("Kernel : core    base : %p \n", info.base );
     249        // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
     250        // LIB_DEBUG_PRINTF("Kernel : core    size : %x \n", info.size );
     251        // LIB_DEBUG_PRINTF("Kernel : core   limit : %p \n", info.limit );
     252        // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
     253        // LIB_DEBUG_PRINTF("Kernel : core     top : %p \n", info.top );
     254
     255        //We now have a proper context from which to schedule threads
     256
     257        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     258        // resume it to start it like it normally would, it will just context switch
     259        // back to here. Instead directly call the main since we already are on the
     260        // appropriate stack.
     261        proc_cor_storage.c.state = Active;
     262      main( &proc_cor_storage );
     263      proc_cor_storage.c.state = Halt;
     264      proc_cor_storage.c.notHalted = false;
     265
     266        LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx);       
     267
     268        return NULL;
     269}
     270
     271void start(processor * this) {
     272        LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this);
     273       
     274        pthread_attr_t attributes;
     275        pthread_attr_init( &attributes );
     276
     277        pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );
     278
     279        pthread_attr_destroy( &attributes );
     280
     281        LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);   
     282}
     283
    135284//-----------------------------------------------------------------------------
    136285// Scheduler routines
    137286void thread_schedule( thread_h * thrd ) {
    138287        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
     288       
     289        pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };
    139290        append( &systemProcessor->cltr->ready_queue, thrd );
    140291}
    141292
    142293thread_h * nextThread(cluster * this) {
     294        pthread_spinlock_guard guard = { &this->lock };
    143295        return pop_head( &this->ready_queue );
    144 }
    145 
    146 //-----------------------------------------------------------------------------
    147 // Kernel storage
    148 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    149 
    150 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
    151 KERNEL_STORAGE(cluster, systemCluster);
    152 KERNEL_STORAGE(processor, systemProcessor);
    153 KERNEL_STORAGE(thread_h, mainThread);
    154 KERNEL_STORAGE(machine_context_t, mainThread_context);
    155 
    156 //-----------------------------------------------------------------------------
    157 // Main thread construction
    158 struct mainThread_info_t {
    159         machine_context_t ctx; 
    160         unsigned int size;              // size of stack
    161         void *base;                             // base of stack
    162         void *storage;                  // pointer to stack
    163         void *limit;                    // stack grows towards stack limit
    164         void *context;                  // address of cfa_context_t
    165         void *top;                              // address of top of storage
    166 };
    167 
    168 void ?{}( mainThread_info_t * this ) {
    169         CtxGet( &this->ctx );
    170         this->base = this->ctx.FP;
    171         this->storage = this->ctx.SP;
    172 
    173         rlimit r;
    174         int ret = getrlimit( RLIMIT_STACK, &r);
    175         this->size = r.rlim_cur;
    176 
    177         this->limit = (void *)(((intptr_t)this->base) - this->size);
    178         this->context = &mainThread_context_storage;
    179         this->top = this->base;
    180 }
    181 
    182 void ?{}( coStack_t * this, mainThread_info_t * info) {
    183         this->size = info->size;
    184         this->storage = info->storage;
    185         this->limit = info->limit;
    186         this->base = info->base;
    187         this->context = info->context;
    188         this->top = info->top;
    189         this->userStack = true;
    190 }
    191 
    192 void ?{}( coroutine * this, mainThread_info_t * info) {
    193         (&this->stack){ info };
    194         this->name = "Main Thread";
    195         this->errno_ = 0;
    196         this->state = Inactive;
    197         this->notHalted = true;
    198 }
    199 
    200 void ?{}( thread_h * this, mainThread_info_t * info) {
    201         (&this->c){ info };
    202296}
    203297
     
    210304        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
    211305
    212         mainThread_info_t ctx;
     306        current_stack_info_t info;
     307
     308        // LIB_DEBUG_PRINTF("Kernel : core    base : %p \n", info.base );
     309        // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
     310        // LIB_DEBUG_PRINTF("Kernel : core    size : %x \n", info.size );
     311        // LIB_DEBUG_PRINTF("Kernel : core   limit : %p \n", info.limit );
     312        // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
     313        // LIB_DEBUG_PRINTF("Kernel : core     top : %p \n", info.top );
    213314
    214315        // Start by initializing the main thread
    215316        mainThread = (thread_h *)&mainThread_storage;
    216         mainThread{ &ctx };
     317        mainThread{ &info };
    217318
    218319        // Initialize the system cluster
     
    220321        systemCluster{};
    221322
    222         // Initialize the system processor
     323        // Initialize the system processor and the system processor ctx
     324        // (the coroutine that contains the processing control flow)
    223325        systemProcessor = (processor *)&systemProcessor_storage;
    224         systemProcessor{ systemCluster };
    225 
    226         // Initialize the system processor ctx
    227         // (the coroutine that contains the processing control flow)
    228         systemProcessor->ctx = (processorCtx_t *)&systemProcessorCtx_storage;
    229         systemProcessor->ctx{ systemProcessor };
     326        systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
    230327
    231328        // Add the main thread to the ready queue
     
    286383
    287384void lock( simple_lock * this ) {
    288         append( &this->blocked, this_thread() );
     385        {
     386                pthread_spinlock_guard guard = { &systemCluster->lock };        //HUGE TEMP HACK which only works if we have a single cluster and is stupid
     387                append( &this->blocked, this_thread() );
     388        }
    289389        suspend();
    290390}
  • src/libcfa/concurrency/threads

    r4a9ccc3 rad6343e  
    2727// Anything that implements this trait can be resumed.
    2828// Anything that is resumed is a coroutine.
    29 trait is_thread(dtype T /*| sized(T)*/) {
     29trait is_thread(dtype T | sized(T)) {
    3030      void main(T* this);
    3131      thread_h* get_thread(T* this);
    32         /*void ?{}(T*);
    33         void ^?{}(T*);*/
    3432};
    3533
    3634#define DECL_THREAD(X) static inline thread_h* get_thread(X* this) { return &this->t; } void main(X* this);
    3735
    38 forall(otype T | is_thread(T) )
     36forall( dtype T | sized(T) | is_thread(T) )
    3937static inline coroutine* get_coroutine(T* this) {
    4038        return &get_thread(this)->c;
     
    5553// thread runner
    5654// Structure that actually start and stop threads
    57 forall(otype T | is_thread(T) )
     55forall( dtype T | sized(T) | is_thread(T) )
    5856struct thread {
    5957        T handle;
    6058};
    6159
    62 forall(otype T | is_thread(T) )
     60forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T*); } )
    6361void ?{}( thread(T)* this );
    6462
    65 forall(otype T, ttype P | is_thread(T) | { void ?{}(T*, P); } )
     63forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T*, P); } )
    6664void ?{}( thread(T)* this, P params );
    6765
    68 forall(otype T | is_thread(T) )
     66forall( dtype T | sized(T) | is_thread(T) | { void ^?{}(T*); } )
    6967void ^?{}( thread(T)* this );
    7068
  • src/libcfa/concurrency/threads.c

    r4a9ccc3 rad6343e  
    2727}
    2828
    29 /*thread_local*/ extern processor * this_processor;
     29extern processor * get_this_processor();
    3030
    3131//-----------------------------------------------------------------------------
    3232// Forward declarations
    33 forall(otype T | is_thread(T) )
     33forall( dtype T | sized(T) | is_thread(T) )
    3434void start( T* this );
    3535
    36 forall(otype T | is_thread(T) )
     36forall( dtype T | sized(T) | is_thread(T) )
    3737void stop( T* this );
    3838
     
    4242void ?{}(thread_h* this) {
    4343        (&this->c){};
     44        this->c.name = "Anonymous Coroutine";
    4445        (&this->lock){};
    4546        this->next = NULL;
     
    5051}
    5152
    52 forall(otype T | is_thread(T) )
     53forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T*); } )
    5354void ?{}( thread(T)* this ) {
    5455        (&this->handle){};
     
    5657}
    5758
    58 forall(otype T, ttype P | is_thread(T) | { void ?{}(T*, P); } )
     59forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T*, P); } )
    5960void ?{}( thread(T)* this, P params ) {
    6061        (&this->handle){ params };
     
    6263}
    6364
    64 forall(otype T | is_thread(T) )
     65forall( dtype T | sized(T) | is_thread(T) | { void ^?{}(T*); } )
    6566void ^?{}( thread(T)* this ) {
    6667        stop(&this->handle);
     
    7778extern void thread_schedule( thread_h * );
    7879
    79 forall(otype T | is_thread(T))
     80forall( dtype T | sized(T) | is_thread(T) )
    8081void start( T* this ) {
    8182        coroutine* thrd_c = get_coroutine(this);
    8283        thread_h*  thrd_h = get_thread   (this);
    8384        thrd_c->last = this_coroutine();
    84         this_processor->current_coroutine = thrd_c;
     85        get_this_processor()->current_coroutine = thrd_c;
    8586
    8687        // LIB_DEBUG_PRINTF("Thread start : %p (t %p, c %p)\n", handle, thrd_c, thrd_h);
     
    9394}
    9495
    95 forall(otype T | is_thread(T) )
     96forall( dtype T | sized(T) | is_thread(T) )
    9697void stop( T* this ) {
    9798        thread_h*  thrd = get_thread(this);
Note: See TracChangeset for help on using the changeset viewer.