Changeset ad6343e
- Timestamp:
- Jan 25, 2017, 1:09:20 PM (8 years ago)
- 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:
- ad56482
- Parents:
- 4a9ccc3 (diff), 2cdf6dc (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. - Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/concurrency/thePlan.md
r4a9ccc3 rad6343e 4 4 done - SimpleBlockingLock. 5 5 done - Synchronisation points in thread destructors. 6 Processors & SpinLock.6 done - Processors & SpinLock. 7 7 8 8 _Phase 2_ : Minimum Viable Product 9 Basic monitors for synchronisation (No internal/external scheduling). 10 Non-thrash scheduler. 11 Clusters. 9 Monitor type and enter/leave mutex member routines 10 Monitors as a language feature (not calling enter/leave by hand) 11 Internal scheduling 12 12 13 13 _Phase 3_ : Kernel features 14 Threads features ex: detach 15 Internal scheduling 14 Detach thread 15 Cluster migration 16 Preemption 16 17 17 18 _Phase 4_ : Monitor features -
src/driver/cfa.cc
r4a9ccc3 rad6343e 267 267 } 268 268 nargs += 1; 269 args[nargs] = "-lpthread"; 270 nargs += 1; 269 271 } // if 270 272 #endif //HAVE_LIBCFA -
src/examples/thread.c
r4a9ccc3 rad6343e 1 #line 1 "thread.c" 1 2 #include <fstream> 3 #include <kernel> 2 4 #include <stdlib> 3 5 #include <threads> … … 10 12 }; 11 13 12 // DECL_THREAD(MyThread) 14 DECL_THREAD(MyThread) 15 16 void ?{}( MyThread * this ) { 17 } 13 18 14 19 void ?{}( MyThread * this, unsigned id, unsigned count ) { … … 17 22 } 18 23 19 //void main(MyThread* this) {20 //sout | "Thread" | this->id | " : Suspending" | this->count | "times" | endl;21 //yield();24 void main(MyThread* this) { 25 sout | "Thread" | this->id | " : Suspending" | this->count | "times" | endl; 26 yield(); 22 27 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 } 28 33 29 34 int main(int argc, char* argv[]) { 30 35 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 } 37 42 38 43 sout | "User main begin" | endl; 39 44 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 } 44 52 45 53 sout | "User main end" | endl; -
src/libcfa/concurrency/coroutines
r4a9ccc3 rad6343e 73 73 74 74 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" 76 76 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 77 77 src->name, src ); 78 78 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" 80 80 "Possible cause is terminated coroutine's main routine has already returned.", 81 81 src->name, src, src->last->name, src->last ); -
src/libcfa/concurrency/coroutines.c
r4a9ccc3 rad6343e 1 // -*- Mode: CFA -*- 1 2 // 2 3 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo … … 31 32 #include "invoke.h" 32 33 33 /*thread_local*/ extern processor * this_processor;34 extern processor * get_this_processor(); 34 35 35 36 //----------------------------------------------------------------------------- … … 110 111 111 112 // set new coroutine that task is executing 112 this_processor->current_coroutine = dst;113 get_this_processor()->current_coroutine = dst; 113 114 114 115 // 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 // 1 16 2 17 #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 1 17 #include <stdbool.h> 2 18 #include <stdint.h> … … 11 27 12 28 #define unlikely(x) __builtin_expect(!!(x), 0) 29 #define thread_local _Thread_local 13 30 #define SCHEDULER_CAPACITY 10 14 31 -
src/libcfa/concurrency/kernel
r4a9ccc3 rad6343e 22 22 #include "invoke.h" 23 23 24 extern "C" { 25 #include <pthread.h> 26 } 27 24 28 //----------------------------------------------------------------------------- 25 29 // Cluster 26 30 struct cluster { 27 31 simple_thread_list ready_queue; 32 pthread_spinlock_t lock; 28 33 }; 29 34 … … 38 43 coroutine * current_coroutine; 39 44 thread_h * current_thread; 40 bool terminated; 45 pthread_t kernel_thread; 46 simple_lock lock; 47 volatile bool terminated; 41 48 }; 42 49 50 void ?{}(processor * this); 43 51 void ?{}(processor * this, cluster * cltr); 44 52 void ^?{}(processor * this); … … 54 62 void unlock( simple_lock * ); 55 63 64 struct pthread_spinlock_guard { 65 pthread_spinlock_t * lock; 66 }; 67 68 static inline void ?{}( pthread_spinlock_guard * this, pthread_spinlock_t * lock ) { 69 this->lock = lock; 70 pthread_spin_lock( this->lock ); 71 } 72 73 static 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 56 101 #endif //KERNEL_H 57 102 -
src/libcfa/concurrency/kernel.c
r4a9ccc3 rad6343e 32 32 #include "invoke.h" 33 33 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 70 36 struct processorCtx_t { 71 37 processor * proc; … … 75 41 DECL_COROUTINE(processorCtx_t) 76 42 43 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)] 44 45 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx); 46 KERNEL_STORAGE(cluster, systemCluster); 47 KERNEL_STORAGE(processor, systemProcessor); 48 KERNEL_STORAGE(thread_h, mainThread); 49 KERNEL_STORAGE(machine_context_t, mainThread_context); 50 51 cluster * systemCluster; 52 processor * systemProcessor; 53 thread_h * mainThread; 54 55 void kernel_startup(void) __attribute__((constructor(101))); 56 void kernel_shutdown(void) __attribute__((destructor(101))); 57 58 //----------------------------------------------------------------------------- 59 // Global state 60 61 thread_local processor * this_processor; 62 63 processor * get_this_processor() { 64 return this_processor; 65 } 66 67 coroutine * this_coroutine(void) { 68 return this_processor->current_coroutine; 69 } 70 71 thread_h * this_thread(void) { 72 return this_processor->current_thread; 73 } 74 75 //----------------------------------------------------------------------------- 76 // Main thread construction 77 struct 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 87 void ?{}( 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 101 void ?{}( 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 111 void ?{}( 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 119 void ?{}( thread_h * this, current_stack_info_t * info) { 120 (&this->c){ info }; 121 } 122 123 //----------------------------------------------------------------------------- 124 // Processor coroutine 77 125 void ?{}(processorCtx_t * this, processor * proc) { 78 126 (&this->c){}; 79 127 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 131 void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) { 132 (&this->c){ info }; 133 this->proc = proc; 134 proc->ctx = this; 135 } 136 137 void start(processor * this); 138 139 void ?{}(processor * this) { 140 this{ systemCluster }; 141 } 142 143 void ?{}(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 153 void ?{}(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 165 void ^?{}(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 173 void ?{}(cluster * this) { 174 ( &this->ready_queue ){}; 175 pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE ); 176 } 177 178 void ^?{}(cluster * this) { 179 pthread_spin_destroy( &this->lock ); 85 180 } 86 181 … … 109 204 } 110 205 206 LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this); 207 unlock( &this->lock ); 111 208 LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this); 112 209 } … … 133 230 } 134 231 232 void * 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 271 void 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 135 284 //----------------------------------------------------------------------------- 136 285 // Scheduler routines 137 286 void thread_schedule( thread_h * thrd ) { 138 287 assertf( thrd->next == NULL, "Expected null got %p", thrd->next ); 288 289 pthread_spinlock_guard guard = { &systemProcessor->cltr->lock }; 139 290 append( &systemProcessor->cltr->ready_queue, thrd ); 140 291 } 141 292 142 293 thread_h * nextThread(cluster * this) { 294 pthread_spinlock_guard guard = { &this->lock }; 143 295 return pop_head( &this->ready_queue ); 144 }145 146 //-----------------------------------------------------------------------------147 // Kernel storage148 #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 construction158 struct mainThread_info_t {159 machine_context_t ctx;160 unsigned int size; // size of stack161 void *base; // base of stack162 void *storage; // pointer to stack163 void *limit; // stack grows towards stack limit164 void *context; // address of cfa_context_t165 void *top; // address of top of storage166 };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 };202 296 } 203 297 … … 210 304 LIB_DEBUG_PRINTF("Kernel : Starting\n"); 211 305 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 ); 213 314 214 315 // Start by initializing the main thread 215 316 mainThread = (thread_h *)&mainThread_storage; 216 mainThread{ & ctx};317 mainThread{ &info }; 217 318 218 319 // Initialize the system cluster … … 220 321 systemCluster{}; 221 322 222 // Initialize the system processor 323 // Initialize the system processor and the system processor ctx 324 // (the coroutine that contains the processing control flow) 223 325 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 }; 230 327 231 328 // Add the main thread to the ready queue … … 286 383 287 384 void 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 } 289 389 suspend(); 290 390 } -
src/libcfa/concurrency/threads
r4a9ccc3 rad6343e 27 27 // Anything that implements this trait can be resumed. 28 28 // Anything that is resumed is a coroutine. 29 trait is_thread(dtype T /*| sized(T)*/) {29 trait is_thread(dtype T | sized(T)) { 30 30 void main(T* this); 31 31 thread_h* get_thread(T* this); 32 /*void ?{}(T*);33 void ^?{}(T*);*/34 32 }; 35 33 36 34 #define DECL_THREAD(X) static inline thread_h* get_thread(X* this) { return &this->t; } void main(X* this); 37 35 38 forall( otype T| is_thread(T) )36 forall( dtype T | sized(T) | is_thread(T) ) 39 37 static inline coroutine* get_coroutine(T* this) { 40 38 return &get_thread(this)->c; … … 55 53 // thread runner 56 54 // Structure that actually start and stop threads 57 forall( otype T| is_thread(T) )55 forall( dtype T | sized(T) | is_thread(T) ) 58 56 struct thread { 59 57 T handle; 60 58 }; 61 59 62 forall( otype T | is_thread(T))60 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T*); } ) 63 61 void ?{}( thread(T)* this ); 64 62 65 forall( otype T, ttype P| is_thread(T) | { void ?{}(T*, P); } )63 forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T*, P); } ) 66 64 void ?{}( thread(T)* this, P params ); 67 65 68 forall( otype T | is_thread(T))66 forall( dtype T | sized(T) | is_thread(T) | { void ^?{}(T*); } ) 69 67 void ^?{}( thread(T)* this ); 70 68 -
src/libcfa/concurrency/threads.c
r4a9ccc3 rad6343e 27 27 } 28 28 29 /*thread_local*/ extern processor * this_processor;29 extern processor * get_this_processor(); 30 30 31 31 //----------------------------------------------------------------------------- 32 32 // Forward declarations 33 forall( otype T| is_thread(T) )33 forall( dtype T | sized(T) | is_thread(T) ) 34 34 void start( T* this ); 35 35 36 forall( otype T| is_thread(T) )36 forall( dtype T | sized(T) | is_thread(T) ) 37 37 void stop( T* this ); 38 38 … … 42 42 void ?{}(thread_h* this) { 43 43 (&this->c){}; 44 this->c.name = "Anonymous Coroutine"; 44 45 (&this->lock){}; 45 46 this->next = NULL; … … 50 51 } 51 52 52 forall( otype T | is_thread(T))53 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T*); } ) 53 54 void ?{}( thread(T)* this ) { 54 55 (&this->handle){}; … … 56 57 } 57 58 58 forall( otype T, ttype P| is_thread(T) | { void ?{}(T*, P); } )59 forall( dtype T, ttype P | sized(T) | is_thread(T) | { void ?{}(T*, P); } ) 59 60 void ?{}( thread(T)* this, P params ) { 60 61 (&this->handle){ params }; … … 62 63 } 63 64 64 forall( otype T | is_thread(T))65 forall( dtype T | sized(T) | is_thread(T) | { void ^?{}(T*); } ) 65 66 void ^?{}( thread(T)* this ) { 66 67 stop(&this->handle); … … 77 78 extern void thread_schedule( thread_h * ); 78 79 79 forall( otype T | is_thread(T))80 forall( dtype T | sized(T) | is_thread(T) ) 80 81 void start( T* this ) { 81 82 coroutine* thrd_c = get_coroutine(this); 82 83 thread_h* thrd_h = get_thread (this); 83 84 thrd_c->last = this_coroutine(); 84 this_processor->current_coroutine = thrd_c;85 get_this_processor()->current_coroutine = thrd_c; 85 86 86 87 // LIB_DEBUG_PRINTF("Thread start : %p (t %p, c %p)\n", handle, thrd_c, thrd_h); … … 93 94 } 94 95 95 forall( otype T| is_thread(T) )96 forall( dtype T | sized(T) | is_thread(T) ) 96 97 void stop( T* this ) { 97 98 thread_h* thrd = get_thread(this);
Note: See TracChangeset
for help on using the changeset viewer.