Changes in / [8c3a0336:8f194ee]
- Files:
-
- 11 edited
-
libcfa/src/concurrency/CtxSwitch-i386.S (modified) (4 diffs)
-
libcfa/src/concurrency/CtxSwitch-x86_64.S (modified) (2 diffs)
-
libcfa/src/concurrency/coroutine.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/invoke.c (modified) (8 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (4 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (14 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (1 diff)
-
tests/Makefile.am (modified) (1 diff)
-
tests/Makefile.in (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/CtxSwitch-i386.S
r8c3a0336 r8f194ee 41 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 42 42 43 .text43 .text 44 44 .align 2 45 .globl CtxSwitch 46 .type CtxSwitch, @function 45 .globl CtxSwitch 47 46 CtxSwitch: 48 47 … … 51 50 52 51 movl 4(%esp),%eax 52 53 // Save floating & SSE control words on the stack. 54 55 sub $8,%esp 56 stmxcsr 0(%esp) // 4 bytes 57 fnstcw 4(%esp) // 2 bytes 53 58 54 59 // Save volatile registers on the stack. … … 62 67 movl %esp,SP_OFFSET(%eax) 63 68 movl %ebp,FP_OFFSET(%eax) 69 // movl 4(%ebp),%ebx // save previous eip for debugger 70 // movl %ebx,PC_OFFSET(%eax) 64 71 65 72 // Copy the "to" context argument from the stack to register eax … … 80 87 popl %ebx 81 88 89 // Load floating & SSE control words from the stack. 90 91 fldcw 4(%esp) 92 ldmxcsr 0(%esp) 93 add $8,%esp 94 82 95 // Return to thread. 83 96 84 97 ret 85 .size CtxSwitch, .-CtxSwitch86 98 87 99 // Local Variables: // -
libcfa/src/concurrency/CtxSwitch-x86_64.S
r8c3a0336 r8f194ee 39 39 #define SP_OFFSET ( 0 * PTR_BYTE ) 40 40 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 41 42 42 .text43 .text 43 44 .align 2 44 .globl CtxSwitch 45 .type CtxSwitch, @function 45 .globl CtxSwitch 46 46 CtxSwitch: 47 48 // Save floating & SSE control words on the stack. 49 50 subq $8,%rsp 51 stmxcsr 0(%rsp) // 4 bytes 52 fnstcw 4(%rsp) // 2 bytes 47 53 48 54 // Save volatile registers on the stack. … … 72 78 popq %r15 73 79 80 // Load floating & SSE control words from the stack. 81 82 fldcw 4(%rsp) 83 ldmxcsr 0(%rsp) 84 addq $8,%rsp 85 74 86 // Return to thread. 75 87 76 88 ret 77 .size CtxSwitch, .-CtxSwitch 89 90 //.text 91 // .align 2 92 //.globl CtxStore 93 //CtxStore: 94 // // Save floating & SSE control words on the stack. 95 // 96 // subq $8,%rsp 97 // stmxcsr 0(%rsp) // 4 bytes 98 // fnstcw 4(%rsp) // 2 bytes 99 // 100 // // Save volatile registers on the stack. 101 // 102 // pushq %r15 103 // pushq %r14 104 // pushq %r13 105 // pushq %r12 106 // pushq %rbx 107 // 108 // // Save old context in the "from" area. 109 // 110 // movq %rsp,SP_OFFSET(%rdi) 111 // movq %rbp,FP_OFFSET(%rdi) 112 // 113 // // Return to thread 114 // 115 // ret 116 // 117 //.text 118 // .align 2 119 //.globl CtxRet 120 //CtxRet: 121 // // Load new context from the "to" area. 122 // 123 // movq SP_OFFSET(%rdi),%rsp 124 // movq FP_OFFSET(%rdi),%rbp 125 // 126 // // Load volatile registers from the stack. 127 // 128 // popq %rbx 129 // popq %r12 130 // popq %r13 131 // popq %r14 132 // popq %r15 133 // 134 // // Load floating & SSE control words from the stack. 135 // 136 // fldcw 4(%rsp) 137 // ldmxcsr 0(%rsp) 138 // addq $8,%rsp 139 // 140 // // Return to thread. 141 // 142 // ret 143 78 144 79 145 .text -
libcfa/src/concurrency/coroutine.cfa
r8c3a0336 r8f194ee 35 35 36 36 extern "C" { 37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));38 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {40 abort();41 }37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__)); 38 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__)); 39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) { 40 abort(); 41 } 42 42 } 43 43 … … 47 47 // minimum feasible stack size in bytes 48 48 #define MinStackSize 1000 49 extern size_t __page_size; // architecture pagesize HACK, should go in proper runtime singleton 50 51 void __stack_prepare( __stack_info_t * this, size_t create_size ); 49 static size_t pageSize = 0; // architecture pagesize HACK, should go in proper runtime singleton 52 50 53 51 //----------------------------------------------------------------------------- 54 52 // Coroutine ctors and dtors 55 void ?{}( __stack_info_t & this, void * storage, size_t storageSize ) { 56 this.storage = (__stack_t *)storage; 57 58 // Did we get a piece of storage ? 59 if (this.storage || storageSize != 0) { 60 // We either got a piece of storage or the user asked for a specific size 61 // Immediately create the stack 62 // (This is slightly unintuitive that non-default sized coroutines create are eagerly created 63 // but it avoids that all coroutines carry an unnecessary size) 64 verify( storageSize != 0 ); 65 __stack_prepare( &this, storageSize ); 66 } 67 } 68 69 void ^?{}(__stack_info_t & this) { 70 bool userStack = ((intptr_t)this.storage & 0x1) != 0; 71 if ( ! userStack && this.storage ) { 72 *((intptr_t*)&this.storage) &= (intptr_t)-1; 73 void * storage = this.storage->limit; 74 __cfaabi_dbg_debug_do( 75 storage = (char*)(storage) - __page_size; 76 if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) { 77 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 78 } 79 ); 80 __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage); 81 free( storage ); 82 } 53 void ?{}( coStack_t & this, void * storage, size_t storageSize ) with( this ) { 54 size = storageSize == 0 ? 65000 : storageSize; // size of stack 55 this.storage = storage; // pointer to stack 56 limit = NULL; // stack grows towards stack limit 57 base = NULL; // base of stack 58 context = NULL; // address of cfa_context_t 59 top = NULL; // address of top of storage 60 userStack = storage != NULL; 61 } 62 63 void ^?{}(coStack_t & this) { 64 if ( ! this.userStack && this.storage ) { 65 __cfaabi_dbg_debug_do( 66 if ( mprotect( this.storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) { 67 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 68 } 69 ); 70 free( this.storage ); 71 } 83 72 } 84 73 85 74 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) { 86 (this.context){NULL, NULL};87 (this.stack){storage, storageSize};88 this.name = name;89 state = Start;90 starter = NULL;91 last = NULL;92 cancellation = NULL;75 (this.stack){storage, storageSize}; 76 this.name = name; 77 errno_ = 0; 78 state = Start; 79 starter = NULL; 80 last = NULL; 81 cancellation = NULL; 93 82 } 94 83 95 84 void ^?{}(coroutine_desc& this) { 96 if(this.state != Halted && this.state != Start) {97 coroutine_desc * src = TL_GET( this_thread )->curr_cor;98 coroutine_desc * dst = &this;99 100 struct _Unwind_Exception storage;101 storage.exception_class = -1;102 storage.exception_cleanup = _CtxCoroutine_UnwindCleanup;103 this.cancellation = &storage;104 this.last = src;105 106 // not resuming self ?107 if ( src == dst ) {108 abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src );109 }110 111 CoroutineCtxSwitch( src, dst );112 }85 if(this.state != Halted && this.state != Start) { 86 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 87 coroutine_desc * dst = &this; 88 89 struct _Unwind_Exception storage; 90 storage.exception_class = -1; 91 storage.exception_cleanup = _CtxCoroutine_UnwindCleanup; 92 this.cancellation = &storage; 93 this.last = src; 94 95 // not resuming self ? 96 if ( src == dst ) { 97 abort( "Attempt by coroutine %.256s (%p) to terminate itself.\n", src->name, src ); 98 } 99 100 CoroutineCtxSwitch( src, dst ); 101 } 113 102 } 114 103 … … 117 106 forall(dtype T | is_coroutine(T)) 118 107 void prime(T& cor) { 119 coroutine_desc* this = get_coroutine(cor); 120 assert(this->state == Start); 121 122 this->state = Primed; 123 resume(cor); 124 } 125 126 [void *, size_t] __stack_alloc( size_t storageSize ) { 127 static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 128 assert(__page_size != 0l); 129 size_t size = libCeiling( storageSize, 16 ) + stack_data_size; 130 131 // If we are running debug, we also need to allocate a guardpage to catch stack overflows. 132 void * storage; 133 __cfaabi_dbg_debug_do( 134 storage = memalign( __page_size, size + __page_size ); 135 ); 136 __cfaabi_dbg_no_debug_do( 137 storage = (void*)malloc(size); 138 ); 139 140 __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size); 141 __cfaabi_dbg_debug_do( 142 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) { 143 abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 144 } 145 storage = (void *)(((intptr_t)storage) + __page_size); 146 ); 147 148 verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul ); 149 return [storage, size]; 150 } 151 152 void __stack_prepare( __stack_info_t * this, size_t create_size ) { 153 static const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 154 bool userStack; 155 void * storage; 156 size_t size; 157 if ( !this->storage ) { 158 userStack = false; 159 [storage, size] = __stack_alloc( create_size ); 160 } else { 161 userStack = true; 162 __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%zd bytes)\n", this, this->storage, (intptr_t)this->storage->limit - (intptr_t)this->storage->base); 163 164 // The stack must be aligned, advance the pointer to the next align data 165 storage = (void*)libCeiling( (intptr_t)this->storage, libAlign()); 166 167 // The size needs to be shrinked to fit all the extra data structure and be aligned 168 ptrdiff_t diff = (intptr_t)storage - (intptr_t)this->storage; 169 size = libFloor(create_size - stack_data_size - diff, libAlign()); 170 } // if 171 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize ); 172 173 this->storage = (__stack_t *)((intptr_t)storage + size); 174 this->storage->limit = storage; 175 this->storage->base = (void*)((intptr_t)storage + size); 176 *((intptr_t*)&this->storage) |= userStack ? 0x1 : 0x0; 108 coroutine_desc* this = get_coroutine(cor); 109 assert(this->state == Start); 110 111 this->state = Primed; 112 resume(cor); 113 } 114 115 // Wrapper for co 116 void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 117 // Safety note : Preemption must be disabled since there is a race condition 118 // kernelTLS.this_thread->curr_cor and $rsp/$rbp must agree at all times 119 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 120 disable_interrupts(); 121 122 // set state of current coroutine to inactive 123 src->state = src->state == Halted ? Halted : Inactive; 124 125 // set new coroutine that task is executing 126 TL_GET( this_thread )->curr_cor = dst; 127 128 // context switch to specified coroutine 129 assert( src->stack.context ); 130 CtxSwitch( src->stack.context, dst->stack.context ); 131 // when CtxSwitch returns we are back in the src coroutine 132 133 // set state of new coroutine to active 134 src->state = Active; 135 136 enable_interrupts( __cfaabi_dbg_ctx ); 137 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 138 139 140 if( unlikely(src->cancellation != NULL) ) { 141 _CtxCoroutine_Unwind(src->cancellation, src); 142 } 143 } //ctxSwitchDirect 144 145 void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ) { 146 //TEMP HACK do this on proper kernel startup 147 if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE ); 148 149 size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment 150 151 if ( !storage ) { 152 __cfaabi_dbg_print_safe("Kernel : Creating stack of size %zu for stack obj %p\n", cxtSize + size + 8, this); 153 154 userStack = false; 155 size = libCeiling( storageSize, 16 ); 156 // use malloc/memalign because "new" raises an exception for out-of-memory 157 158 // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment 159 __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize + size + pageSize ) ); 160 __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize + size + 8 ) ); 161 162 __cfaabi_dbg_debug_do( 163 if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) { 164 abort( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) ); 165 } // if 166 ); 167 168 if ( (intptr_t)storage == 0 ) { 169 abort( "Attempt to allocate %zd bytes of storage for coroutine or task execution-state but insufficient memory available.", size ); 170 } // if 171 172 __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize ); 173 __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment 174 175 } else { 176 __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%u bytes)\n", this, storage, storageSize); 177 178 assertf( ((size_t)storage & (libAlign() - 1)) == 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", storage, (int)libAlign() ); 179 userStack = true; 180 size = storageSize - cxtSize; 181 182 if ( size % 16 != 0u ) size -= 8; 183 184 limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment 185 } // if 186 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize ); 187 188 base = (char *)limit + size; 189 context = base; 190 top = (char *)context + cxtSize; 177 191 } 178 192 … … 180 194 // is not inline (We can't inline Cforall in C) 181 195 extern "C" { 182 void __suspend_internal(void) {183 suspend();184 }185 186 void __leave_coroutine( coroutine_desc * src ) {187 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;188 189 src->state = Halted;190 191 assertf( starter != 0,192 "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"193 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",194 src->name, src );195 assertf( starter->state != Halted,196 "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"197 "Possible cause is terminated coroutine's main routine has already returned.",198 src->name, src, starter->name, starter );199 200 CoroutineCtxSwitch( src, starter );201 }196 void __suspend_internal(void) { 197 suspend(); 198 } 199 200 void __leave_coroutine( coroutine_desc * src ) { 201 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter; 202 203 src->state = Halted; 204 205 assertf( starter != 0, 206 "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n" 207 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 208 src->name, src ); 209 assertf( starter->state != Halted, 210 "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n" 211 "Possible cause is terminated coroutine's main routine has already returned.", 212 src->name, src, starter->name, starter ); 213 214 CoroutineCtxSwitch( src, starter ); 215 } 202 216 } 203 217 -
libcfa/src/concurrency/coroutine.hfa
r8c3a0336 r8f194ee 64 64 forall(dtype T | is_coroutine(T)) 65 65 void CtxStart(T * this, void ( *invoke)(T *)); 66 67 extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));68 69 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");70 // void CtxStore ( void * this ) asm ("CtxStore");71 // void CtxRet ( void * dst ) asm ("CtxRet");72 66 } 73 67 74 68 // Private wrappers for context switch and stack creation 75 // Wrapper for co 76 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 77 // set state of current coroutine to inactive 78 src->state = src->state == Halted ? Halted : Inactive; 79 80 // set new coroutine that task is executing 81 TL_GET( this_thread )->curr_cor = dst; 82 83 // context switch to specified coroutine 84 verify( dst->context.SP ); 85 CtxSwitch( &src->context, &dst->context ); 86 // when CtxSwitch returns we are back in the src coroutine 87 88 // set state of new coroutine to active 89 src->state = Active; 90 91 if( unlikely(src->cancellation != NULL) ) { 92 _CtxCoroutine_Unwind(src->cancellation, src); 93 } 94 } 95 96 extern void __stack_prepare ( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 70 extern void create_stack( coStack_t * this, unsigned int storageSize ); 97 71 98 72 // Suspend implementation inlined for performance … … 128 102 coroutine_desc * dst = get_coroutine(cor); 129 103 130 if( unlikely( dst->context.SP == NULL) ) {131 __stack_prepare(&dst->stack, 65000);104 if( unlikely(!dst->stack.base) ) { 105 create_stack(&dst->stack, dst->stack.size); 132 106 CtxStart(&cor, CtxInvokeCoroutine); 133 107 } -
libcfa/src/concurrency/invoke.c
r8c3a0336 r8f194ee 29 29 extern void __suspend_internal(void); 30 30 extern void __leave_coroutine( struct coroutine_desc * ); 31 extern void __finish_creation( struct thread_desc * );31 extern void __finish_creation( struct coroutine_desc * ); 32 32 extern void __leave_thread_monitor( struct thread_desc * this ); 33 33 extern void disable_interrupts(); … … 46 46 47 47 cor->state = Active; 48 49 enable_interrupts( __cfaabi_dbg_ctx ); 48 50 49 51 main( this ); … … 91 93 // First suspend, once the thread arrives here, 92 94 // the function pointer to main can be invalidated without risk 93 __finish_creation( thrd ); 95 __finish_creation(&thrd->self_cor); 96 97 // Restore the last to NULL, we clobbered because of the thunk problem 98 thrd->self_cor.last = NULL; 94 99 95 100 // Officially start the thread by enabling preemption … … 117 122 void (*invoke)(void *) 118 123 ) { 119 struct coroutine_desc * cor = get_coroutine( this ); 120 struct __stack_t * stack = cor->stack.storage; 124 struct coStack_t* stack = &get_coroutine( this )->stack; 121 125 122 126 #if defined( __i386 ) … … 124 128 struct FakeStack { 125 129 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 130 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls) 131 uint16_t fcw; // X97 FPU control word (preserved across function calls) 126 132 void *rturn; // where to go on return from uSwitch 127 133 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke … … 130 136 }; 131 137 132 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );133 cor->context.FP = NULL; // terminate stack with NULL fp138 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack ); 139 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp 134 140 135 struct FakeStack *fs = (struct FakeStack *)cor->context.SP;136 137 fs->dummyReturn = NULL;138 fs->argument[0] = this; // argument to invoke139 fs->rturn = invoke;141 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL; 142 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = this; // argument to invoke 143 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke; 144 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 145 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 140 146 141 147 #elif defined( __x86_64 ) … … 143 149 struct FakeStack { 144 150 void *fixedRegisters[5]; // fixed registers rbx, r12, r13, r14, r15 151 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls) 152 uint16_t fcw; // X97 FPU control word (preserved across function calls) 145 153 void *rturn; // where to go on return from uSwitch 146 154 void *dummyReturn; // NULL return address to provide proper alignment 147 155 }; 148 156 149 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );150 cor->context.FP = NULL; // terminate stack with NULL fp157 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack ); 158 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp 151 159 152 struct FakeStack *fs = (struct FakeStack *)cor->context.SP;153 154 fs->dummyReturn = NULL;155 fs->rturn = CtxInvokeStub;156 fs->fixedRegisters[0] = this;157 fs->fixedRegisters[1] = invoke;160 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL; 161 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = CtxInvokeStub; 162 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = this; 163 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke; 164 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520 165 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7 158 166 159 167 #elif defined( __ARM_ARCH ) … … 165 173 }; 166 174 167 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack );168 cor->context.FP = NULL;175 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack ); 176 ((struct machine_context_t *)stack->context)->FP = NULL; 169 177 170 struct FakeStack *fs = (struct FakeStack *) cor->context.SP;178 struct FakeStack *fs = (struct FakeStack *)((struct machine_context_t *)stack->context)->SP; 171 179 172 180 fs->intRegs[8] = CtxInvokeStub; -
libcfa/src/concurrency/invoke.h
r8c3a0336 r8f194ee 62 62 #endif 63 63 64 struct __stack_context_t { 65 void * SP; 66 void * FP; 67 }; 68 69 // low adresses : +----------------------+ <- start of allocation 70 // | optional guard page | 71 // +----------------------+ <- __stack_t.limit 72 // | | 73 // | /\ /\ /\ | 74 // | || || || | 75 // | | 76 // | program stack | 77 // | | 78 // __stack_info_t.storage -> +----------------------+ <- __stack_t.base 79 // | __stack_t | 80 // high adresses : +----------------------+ <- end of allocation 81 82 struct __stack_t { 83 // stack grows towards stack limit 84 void * limit; 85 86 // base of stack 87 void * base; 88 }; 89 90 struct __stack_info_t { 91 // pointer to stack 92 struct __stack_t * storage; 64 struct coStack_t { 65 size_t size; // size of stack 66 void * storage; // pointer to stack 67 void * limit; // stack grows towards stack limit 68 void * base; // base of stack 69 void * context; // address of cfa_context_t 70 void * top; // address of top of storage 71 bool userStack; // whether or not the user allocated the stack 93 72 }; 94 73 … … 96 75 97 76 struct coroutine_desc { 98 // context that is switch during a CtxSwitch99 struct __stack_context_t context;100 101 77 // stack information of the coroutine 102 struct __stack_info_t stack;103 104 // textual name for coroutine/task 78 struct coStack_t stack; 79 80 // textual name for coroutine/task, initialized by uC++ generated code 105 81 const char * name; 82 83 // copy of global UNIX variable errno 84 int errno_; 106 85 107 86 // current execution status for coroutine 108 87 enum coroutine_state state; 109 110 88 // first coroutine to resume this one 111 89 struct coroutine_desc * starter; … … 161 139 struct thread_desc { 162 140 // Core threading fields 163 // context that is switch during a CtxSwitch164 struct __stack_context_t context;165 166 // current execution status for coroutine167 enum coroutine_state state;168 169 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it170 171 141 // coroutine body used to store context 172 142 struct coroutine_desc self_cor; … … 260 230 // assembler routines that performs the context switch 261 231 extern void CtxInvokeStub( void ); 262 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t* to ) asm ("CtxSwitch");232 void CtxSwitch( void * from, void * to ) asm ("CtxSwitch"); 263 233 // void CtxStore ( void * this ) asm ("CtxStore"); 264 234 // void CtxRet ( void * dst ) asm ("CtxRet"); 235 236 #if defined( __i386 ) 237 #define CtxGet( ctx ) __asm__ ( \ 238 "movl %%esp,%0\n" \ 239 "movl %%ebp,%1\n" \ 240 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 241 #elif defined( __x86_64 ) 242 #define CtxGet( ctx ) __asm__ ( \ 243 "movq %%rsp,%0\n" \ 244 "movq %%rbp,%1\n" \ 245 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 246 #elif defined( __ARM_ARCH ) 247 #define CtxGet( ctx ) __asm__ ( \ 248 "mov %0,%%sp\n" \ 249 "mov %1,%%r11\n" \ 250 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 251 #else 252 #error unknown hardware architecture 253 #endif 265 254 266 255 #endif //_INVOKE_PRIVATE_H_ -
libcfa/src/concurrency/kernel.cfa
r8c3a0336 r8f194ee 36 36 #include "invoke.h" 37 37 38 //-----------------------------------------------------------------------------39 // Some assembly required40 #if defined( __i386 )41 #define CtxGet( ctx ) \42 __asm__ volatile ( \43 "movl %%esp,%0\n"\44 "movl %%ebp,%1\n"\45 : "=rm" (ctx.SP),\46 "=rm" (ctx.FP) \47 )48 49 // mxcr : SSE Status and Control bits (control bits are preserved across function calls)50 // fcw : X87 FPU control word (preserved across function calls)51 #define __x87_store \52 uint32_t __mxcr; \53 uint16_t __fcw; \54 __asm__ volatile ( \55 "stmxcsr %0\n" \56 "fnstcw %1\n" \57 : "=m" (__mxcr),\58 "=m" (__fcw) \59 )60 61 #define __x87_load \62 __asm__ volatile ( \63 "fldcw %1\n" \64 "ldmxcsr %0\n" \65 ::"m" (__mxcr),\66 "m" (__fcw) \67 )68 69 #elif defined( __x86_64 )70 #define CtxGet( ctx ) \71 __asm__ volatile ( \72 "movq %%rsp,%0\n"\73 "movq %%rbp,%1\n"\74 : "=rm" (ctx.SP),\75 "=rm" (ctx.FP) \76 )77 78 #define __x87_store \79 uint32_t __mxcr; \80 uint16_t __fcw; \81 __asm__ volatile ( \82 "stmxcsr %0\n" \83 "fnstcw %1\n" \84 : "=m" (__mxcr),\85 "=m" (__fcw) \86 )87 88 #define __x87_load \89 __asm__ volatile ( \90 "fldcw %1\n" \91 "ldmxcsr %0\n" \92 :: "m" (__mxcr),\93 "m" (__fcw) \94 )95 96 97 #elif defined( __ARM_ARCH )98 #define CtxGet( ctx ) __asm__ ( \99 "mov %0,%%sp\n" \100 "mov %1,%%r11\n" \101 : "=rm" (ctx.SP), "=rm" (ctx.FP) )102 #else103 #error unknown hardware architecture104 #endif105 106 //-----------------------------------------------------------------------------107 38 //Start and stop routine for the kernel, declared first to make sure they run first 108 39 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); … … 111 42 //----------------------------------------------------------------------------- 112 43 // Kernel storage 113 KERNEL_STORAGE(cluster, mainCluster);114 KERNEL_STORAGE(processor, mainProcessor);115 KERNEL_STORAGE(thread_desc, mainThread);116 KERNEL_STORAGE( __stack_t,mainThreadCtx);44 KERNEL_STORAGE(cluster, mainCluster); 45 KERNEL_STORAGE(processor, mainProcessor); 46 KERNEL_STORAGE(thread_desc, mainThread); 47 KERNEL_STORAGE(machine_context_t, mainThreadCtx); 117 48 118 49 cluster * mainCluster; … … 123 54 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 124 55 } 125 126 size_t __page_size = 0;127 56 128 57 //----------------------------------------------------------------------------- … … 137 66 // Struct to steal stack 138 67 struct current_stack_info_t { 139 __stack_t * storage; // pointer to stack object 68 machine_context_t ctx; 69 unsigned int size; // size of stack 140 70 void *base; // base of stack 71 void *storage; // pointer to stack 141 72 void *limit; // stack grows towards stack limit 142 73 void *context; // address of cfa_context_t 74 void *top; // address of top of storage 143 75 }; 144 76 145 77 void ?{}( current_stack_info_t & this ) { 146 __stack_context_t ctx;147 CtxGet( ctx );148 this. base = ctx.FP;78 CtxGet( this.ctx ); 79 this.base = this.ctx.FP; 80 this.storage = this.ctx.SP; 149 81 150 82 rlimit r; 151 83 getrlimit( RLIMIT_STACK, &r); 152 size_tsize = r.rlim_cur;153 154 this.limit = (void *)(((intptr_t)this.base) - size);84 this.size = r.rlim_cur; 85 86 this.limit = (void *)(((intptr_t)this.base) - this.size); 155 87 this.context = &storage_mainThreadCtx; 88 this.top = this.base; 156 89 } 157 90 158 91 //----------------------------------------------------------------------------- 159 92 // Main thread construction 93 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) { 94 size = info->size; 95 storage = info->storage; 96 limit = info->limit; 97 base = info->base; 98 context = info->context; 99 top = info->top; 100 userStack = true; 101 } 160 102 161 103 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 162 stack.storage = info->storage; 163 with(*stack.storage) { 164 limit = info->limit; 165 base = info->base; 166 } 167 *((intptr_t*)&stack.storage) |= 0x1; 104 stack{ info }; 168 105 name = "Main Thread"; 106 errno_ = 0; 169 107 state = Start; 170 108 starter = NULL; 171 last = NULL;172 cancellation = NULL;173 109 } 174 110 175 111 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 176 state = Start;177 112 self_cor{ info }; 178 113 curr_cor = &self_cor; … … 305 240 } 306 241 307 static int * __volatile_errno() __attribute__((noinline));308 static int * __volatile_errno() { asm(""); return &errno; }309 310 242 // KERNEL ONLY 311 243 // runThread runs a thread by context switching 312 244 // from the processor coroutine to the target thread 313 static void runThread(processor * this, thread_desc * thrd_dst) { 245 static void runThread(processor * this, thread_desc * dst) { 246 assert(dst->curr_cor); 314 247 coroutine_desc * proc_cor = get_coroutine(this->runner); 248 coroutine_desc * thrd_cor = dst->curr_cor; 315 249 316 250 // Reset the terminating actions here … … 318 252 319 253 // Update global state 320 kernelTLS.this_thread = thrd_dst; 321 322 // set state of processor coroutine to inactive and the thread to active 323 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 324 thrd_dst->state = Active; 325 326 // set context switch to the thread that the processor is executing 327 verify( thrd_dst->context.SP ); 328 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 329 // when CtxSwitch returns we are back in the processor coroutine 330 331 // set state of processor coroutine to active and the thread to inactive 332 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 333 proc_cor->state = Active; 254 kernelTLS.this_thread = dst; 255 256 // Context Switch to the thread 257 ThreadCtxSwitch(proc_cor, thrd_cor); 258 // when ThreadCtxSwitch returns we are back in the processor coroutine 334 259 } 335 260 … … 337 262 static void returnToKernel() { 338 263 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 339 thread_desc * thrd_src = kernelTLS.this_thread; 340 341 // set state of current coroutine to inactive 342 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 343 proc_cor->state = Active; 344 int local_errno = *__volatile_errno(); 345 #if defined( __i386 ) || defined( __x86_64 ) 346 __x87_store; 347 #endif 348 349 // set new coroutine that the processor is executing 350 // and context switch to it 351 verify( proc_cor->context.SP ); 352 CtxSwitch( &thrd_src->context, &proc_cor->context ); 353 354 // set state of new coroutine to active 355 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 356 thrd_src->state = Active; 357 358 #if defined( __i386 ) || defined( __x86_64 ) 359 __x87_load; 360 #endif 361 *__volatile_errno() = local_errno; 264 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor; 265 ThreadCtxSwitch(thrd_cor, proc_cor); 362 266 } 363 267 … … 408 312 // to waste the perfectly valid stack create by pthread. 409 313 current_stack_info_t info; 410 __stack_t ctx;411 info. storage= &ctx;314 machine_context_t ctx; 315 info.context = &ctx; 412 316 (proc->runner){ proc, &info }; 413 317 414 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack. storage);318 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.base); 415 319 416 320 //Set global state … … 443 347 444 348 // KERNEL_ONLY 445 void kernel_first_resume( processor * this) {446 thread_desc * src = mainThread;349 void kernel_first_resume(processor * this) { 350 coroutine_desc * src = mainThread->curr_cor; 447 351 coroutine_desc * dst = get_coroutine(this->runner); 448 352 449 353 verify( ! kernelTLS.preemption_state.enabled ); 450 354 451 __stack_prepare( &dst->stack, 65000);355 create_stack(&dst->stack, dst->stack.size); 452 356 CtxStart(&this->runner, CtxInvokeCoroutine); 453 357 454 358 verify( ! kernelTLS.preemption_state.enabled ); 455 359 456 dst->last = &src->self_cor;457 dst->starter = dst->starter ? dst->starter : &src->self_cor;360 dst->last = src; 361 dst->starter = dst->starter ? dst->starter : src; 458 362 459 363 // set state of current coroutine to inactive 460 364 src->state = src->state == Halted ? Halted : Inactive; 461 365 366 // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch. 367 // Therefore, when first creating a coroutine, interrupts are enable before calling the main. 368 // This is consistent with thread creation. However, when creating the main processor coroutine, 369 // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will 370 // stay disabled. 371 disable_interrupts(); 372 462 373 // context switch to specified coroutine 463 verify( dst->context.SP);464 CtxSwitch( &src->context, &dst->context );374 assert( src->stack.context ); 375 CtxSwitch( src->stack.context, dst->stack.context ); 465 376 // when CtxSwitch returns we are back in the src coroutine 466 377 … … 469 380 470 381 verify( ! kernelTLS.preemption_state.enabled ); 471 }472 473 // KERNEL_ONLY474 void kernel_last_resume( processor * this ) {475 coroutine_desc * src = &mainThread->self_cor;476 coroutine_desc * dst = get_coroutine(this->runner);477 478 verify( ! kernelTLS.preemption_state.enabled );479 verify( dst->starter == src );480 verify( dst->context.SP );481 482 // context switch to the processor483 CtxSwitch( &src->context, &dst->context );484 382 } 485 383 … … 490 388 void ScheduleThread( thread_desc * thrd ) { 491 389 verify( thrd ); 492 verify( thrd->s tate != Halted );390 verify( thrd->self_cor.state != Halted ); 493 391 494 392 verify( ! kernelTLS.preemption_state.enabled ); … … 647 545 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 648 546 649 __page_size = sysconf( _SC_PAGESIZE );650 651 547 __cfa_dbg_global_clusters.list{ __get }; 652 548 __cfa_dbg_global_clusters.lock{}; … … 663 559 mainThread = (thread_desc *)&storage_mainThread; 664 560 current_stack_info_t info; 665 info.storage = (__stack_t*)&storage_mainThreadCtx;666 561 (*mainThread){ &info }; 667 562 … … 732 627 // which is currently here 733 628 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 734 kernel_last_resume( kernelTLS.this_processor);629 returnToKernel(); 735 630 mainThread->self_cor.state = Halted; 736 631 -
libcfa/src/concurrency/thread.cfa
r8c3a0336 r8f194ee 31 31 // Thread ctors and dtors 32 32 void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) { 33 context{ NULL, NULL };34 33 self_cor{ name, storage, storageSize }; 35 state = Start;34 verify(&self_cor); 36 35 curr_cor = &self_cor; 37 36 self_mon.owner = &this; … … 74 73 forall( dtype T | is_thread(T) ) 75 74 void __thrd_start( T& this ) { 76 thread_desc * this_thrd = get_thread(this); 77 thread_desc * curr_thrd = TL_GET( this_thread ); 75 coroutine_desc* thrd_c = get_coroutine(this); 76 thread_desc * thrd_h = get_thread (this); 77 thrd_c->last = TL_GET( this_thread )->curr_cor; 78 79 // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); 78 80 79 81 disable_interrupts(); 82 create_stack(&thrd_c->stack, thrd_c->stack.size); 80 83 CtxStart(&this, CtxInvokeThread); 81 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 82 verify( this_thrd->context.SP ); 83 CtxSwitch( &curr_thrd->context, &this_thrd->context ); 84 assert( thrd_c->last->stack.context ); 85 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 84 86 85 ScheduleThread(th is_thrd);87 ScheduleThread(thrd_h); 86 88 enable_interrupts( __cfaabi_dbg_ctx ); 87 89 } … … 89 91 extern "C" { 90 92 // KERNEL ONLY 91 void __finish_creation(thread_desc * this) { 92 // set new coroutine that the processor is executing 93 // and context switch to it 94 verify( kernelTLS.this_thread != this ); 95 verify( kernelTLS.this_thread->context.SP ); 96 CtxSwitch( &this->context, &kernelTLS.this_thread->context ); 93 void __finish_creation(coroutine_desc * thrd_c) { 94 ThreadCtxSwitch( thrd_c, thrd_c->last ); 97 95 } 98 96 } … … 112 110 } 113 111 112 // KERNEL ONLY 113 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 114 // set state of current coroutine to inactive 115 src->state = src->state == Halted ? Halted : Inactive; 116 dst->state = Active; 117 118 // set new coroutine that the processor is executing 119 // and context switch to it 120 assert( src->stack.context ); 121 CtxSwitch( src->stack.context, dst->stack.context ); 122 123 // set state of new coroutine to active 124 dst->state = dst->state == Halted ? Halted : Inactive; 125 src->state = Active; 126 } 127 114 128 // Local Variables: // 115 129 // mode: c // -
libcfa/src/concurrency/thread.hfa
r8c3a0336 r8f194ee 61 61 void ^?{}(thread_desc & this); 62 62 63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; }63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; } 64 64 static inline void ?{}(thread_desc & this, size_t stackSize ) { this{ "Anonymous Thread", *mainCluster, NULL, stackSize }; } 65 65 static inline void ?{}(thread_desc & this, void * storage, size_t storageSize ) { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; } 66 static inline void ?{}(thread_desc & this, struct cluster & cl ) { this{ "Anonymous Thread", cl, NULL, 65000 }; }67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, NULL, stackSize }; }66 static inline void ?{}(thread_desc & this, struct cluster & cl ) { this{ "Anonymous Thread", cl, NULL, 0 }; } 67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, 0, stackSize }; } 68 68 static inline void ?{}(thread_desc & this, struct cluster & cl, void * storage, size_t storageSize ) { this{ "Anonymous Thread", cl, storage, storageSize }; } 69 static inline void ?{}(thread_desc & this, const char * const name) { this{ name, *mainCluster, NULL, 65000 }; }70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 65000 }; }69 static inline void ?{}(thread_desc & this, const char * const name) { this{ name, *mainCluster, NULL, 0 }; } 70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 0 }; } 71 71 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, NULL, stackSize }; } 72 72 -
tests/Makefile.am
r8c3a0336 r8f194ee 22 22 debug=yes 23 23 installed=no 24 25 INSTALL_FLAGS=-in-tree26 DEBUG_FLAGS=-debug -O027 24 28 25 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes -
tests/Makefile.in
r8c3a0336 r8f194ee 375 375 debug = yes 376 376 installed = no 377 INSTALL_FLAGS = -in-tree378 DEBUG_FLAGS = -debug -O0379 377 quick_test = avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes 380 378 concurrent =
Note:
See TracChangeset
for help on using the changeset viewer.