Changeset b067d9b for libcfa/src/concurrency
- Timestamp:
- Oct 29, 2019, 4:01:24 PM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 773db65, 9421f3d8
- Parents:
- 7951100 (diff), 8364209 (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. - Location:
- libcfa/src/concurrency
- Files:
-
- 3 added
- 20 moved
-
CtxSwitch-arm.S (moved) (moved from src/libcfa/concurrency/CtxSwitch-armv7l.S )
-
CtxSwitch-i386.S (moved) (moved from src/libcfa/concurrency/CtxSwitch-i386.S ) (5 diffs)
-
CtxSwitch-i686.S (moved) (moved from src/libcfa/concurrency/CtxSwitch-i686.S )
-
CtxSwitch-x64.S (added)
-
CtxSwitch-x86.S (added)
-
CtxSwitch-x86_64.S (moved) (moved from src/libcfa/concurrency/CtxSwitch-x86_64.S ) (2 diffs)
-
alarm.cfa (moved) (moved from src/libcfa/concurrency/alarm.c ) (2 diffs)
-
alarm.hfa (moved) (moved from src/libcfa/concurrency/alarm.h ) (2 diffs)
-
coroutine.cfa (added)
-
coroutine.hfa (moved) (moved from src/libcfa/concurrency/coroutine ) (8 diffs)
-
invoke.c (moved) (moved from src/libcfa/concurrency/invoke.c ) (7 diffs)
-
invoke.h (moved) (moved from src/libcfa/concurrency/invoke.h ) (10 diffs)
-
kernel.cfa (moved) (moved from src/libcfa/concurrency/kernel.c ) (33 diffs)
-
kernel.hfa (moved) (moved from src/libcfa/concurrency/kernel ) (7 diffs)
-
kernel_private.hfa (moved) (moved from src/libcfa/concurrency/kernel_private.h ) (7 diffs)
-
monitor.cfa (moved) (moved from src/libcfa/concurrency/monitor.c ) (1 diff)
-
monitor.hfa (moved) (moved from src/libcfa/concurrency/monitor ) (2 diffs)
-
mutex.cfa (moved) (moved from src/libcfa/concurrency/mutex.c ) (1 diff)
-
mutex.hfa (moved) (moved from src/libcfa/concurrency/mutex ) (1 diff)
-
preemption.cfa (moved) (moved from src/libcfa/concurrency/preemption.c ) (8 diffs)
-
preemption.hfa (moved) (moved from src/libcfa/concurrency/preemption.h ) (2 diffs)
-
thread.cfa (moved) (moved from src/libcfa/concurrency/thread.c ) (5 diffs)
-
thread.hfa (moved) (moved from src/libcfa/concurrency/thread ) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/CtxSwitch-i386.S
r7951100 rb067d9b 41 41 #define PC_OFFSET ( 2 * PTR_BYTE ) 42 42 43 .text43 .text 44 44 .align 2 45 .globl CtxSwitch 45 .globl CtxSwitch 46 .type CtxSwitch, @function 46 47 CtxSwitch: 47 48 … … 50 51 51 52 movl 4(%esp),%eax 52 53 // Save floating & SSE control words on the stack.54 55 sub $8,%esp56 stmxcsr 0(%esp) // 4 bytes57 fnstcw 4(%esp) // 2 bytes58 53 59 54 // Save volatile registers on the stack. … … 67 62 movl %esp,SP_OFFSET(%eax) 68 63 movl %ebp,FP_OFFSET(%eax) 69 // movl 4(%ebp),%ebx // save previous eip for debugger70 // movl %ebx,PC_OFFSET(%eax)71 64 72 65 // Copy the "to" context argument from the stack to register eax … … 74 67 // argument is now at 8 + 12 = 20(%esp) 75 68 76 movl 2 8(%esp),%eax69 movl 20(%esp),%eax 77 70 78 71 // Load new context from the "to" area. … … 87 80 popl %ebx 88 81 89 // Load floating & SSE control words from the stack.90 91 fldcw 4(%esp)92 ldmxcsr 0(%esp)93 add $8,%esp94 95 82 // Return to thread. 96 83 97 84 ret 85 .size CtxSwitch, .-CtxSwitch 98 86 99 87 // Local Variables: // -
libcfa/src/concurrency/CtxSwitch-x86_64.S
r7951100 rb067d9b 39 39 #define SP_OFFSET ( 0 * PTR_BYTE ) 40 40 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 #define PC_OFFSET ( 2 * PTR_BYTE )42 41 43 .text 42 //----------------------------------------------------------------------------- 43 // Regular context switch routine which enables switching from one context to anouther 44 .text 44 45 .align 2 45 .globl CtxSwitch 46 .globl CtxSwitch 47 .type CtxSwitch, @function 46 48 CtxSwitch: 47 48 // Save floating & SSE control words on the stack.49 50 subq $8,%rsp51 stmxcsr 0(%rsp) // 4 bytes52 fnstcw 4(%rsp) // 2 bytes53 49 54 50 // Save volatile registers on the stack. … … 78 74 popq %r15 79 75 80 // Load floating & SSE control words from the stack.81 82 fldcw 4(%rsp)83 ldmxcsr 0(%rsp)84 addq $8,%rsp85 86 76 // Return to thread. 87 77 88 78 ret 79 .size CtxSwitch, .-CtxSwitch 89 80 90 .text 81 //----------------------------------------------------------------------------- 82 // Stub used to create new stacks which are ready to be context switched to 83 .text 91 84 .align 2 92 .globl CtxInvokeStub 85 .globl CtxInvokeStub 86 .type CtxInvokeStub, @function 93 87 CtxInvokeStub: 94 88 movq %rbx, %rdi 95 89 jmp *%r12 90 .size CtxInvokeStub, .-CtxInvokeStub 96 91 97 92 // Local Variables: // -
libcfa/src/concurrency/alarm.cfa
r7951100 rb067d9b 14 14 // 15 15 16 #define __cforall_thread__ 17 16 18 extern "C" { 17 19 #include <errno.h> … … 22 24 } 23 25 24 #include "alarm.h "25 #include "kernel_private.h "26 #include "preemption.h "26 #include "alarm.hfa" 27 #include "kernel_private.hfa" 28 #include "preemption.hfa" 27 29 28 30 //============================================================================================= -
libcfa/src/concurrency/alarm.hfa
r7951100 rb067d9b 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // alarm.h --7 // alarm.hfa -- 8 8 // 9 9 // Author : Thierry Delisle … … 21 21 #include <assert.h> 22 22 23 #include "time "23 #include "time.hfa" 24 24 25 25 struct thread_desc; -
libcfa/src/concurrency/coroutine.hfa
r7951100 rb067d9b 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 30 18:23:45 201813 // Update Count : 812 // Last Modified On : Fri Jun 21 17:49:39 2019 13 // Update Count : 9 14 14 // 15 15 … … 46 46 //----------------------------------------------------------------------------- 47 47 // Public coroutine API 48 static inline void suspend( );48 static inline void suspend(void); 49 49 50 50 forall(dtype T | is_coroutine(T)) 51 static inline voidresume(T & cor);51 static inline T & resume(T & cor); 52 52 53 53 forall(dtype T | is_coroutine(T)) 54 54 void prime(T & cor); 55 56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 55 57 56 58 //----------------------------------------------------------------------------- … … 64 66 forall(dtype T | is_coroutine(T)) 65 67 void CtxStart(T * this, void ( *invoke)(T *)); 68 69 extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__)); 70 71 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch"); 66 72 } 67 73 68 74 // Private wrappers for context switch and stack creation 69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 70 extern void create_stack( coStack_t * this, unsigned int storageSize ); 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 */); 71 97 72 98 // Suspend implementation inlined for performance 73 static inline void suspend( ) {99 static inline void suspend(void) { 74 100 // optimization : read TLS once and reuse it 75 101 // Safety note: this is preemption safe since if … … 77 103 // will also migrate which means this value will 78 104 // stay in syn with the TLS 79 coroutine_desc * src = TL_GET( this_ coroutine );105 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 80 106 81 107 assertf( src->last != 0, … … 93 119 // Resume implementation inlined for performance 94 120 forall(dtype T | is_coroutine(T)) 95 static inline voidresume(T & cor) {121 static inline T & resume(T & cor) { 96 122 // optimization : read TLS once and reuse it 97 123 // Safety note: this is preemption safe since if … … 99 125 // will also migrate which means this value will 100 126 // stay in syn with the TLS 101 coroutine_desc * src = TL_GET( this_ coroutine );127 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 102 128 coroutine_desc * dst = get_coroutine(cor); 103 129 104 if( unlikely( !dst->stack.base) ) {105 create_stack(&dst->stack, dst->stack.size);130 if( unlikely(dst->context.SP == NULL) ) { 131 __stack_prepare(&dst->stack, 65000); 106 132 CtxStart(&cor, CtxInvokeCoroutine); 107 133 } … … 121 147 // always done for performance testing 122 148 CoroutineCtxSwitch( src, dst ); 149 150 return cor; 123 151 } 124 152 … … 129 157 // will also migrate which means this value will 130 158 // stay in syn with the TLS 131 coroutine_desc * src = TL_GET( this_ coroutine );159 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 132 160 133 161 // not resuming self ? -
libcfa/src/concurrency/invoke.c
r7951100 rb067d9b 14 14 // 15 15 16 #define __cforall_thread__ 17 16 18 #include <stdbool.h> 17 19 #include <stdlib.h> 18 20 #include <stdio.h> 21 #include <unwind.h> 19 22 20 23 #include "invoke.h" … … 27 30 28 31 extern void __suspend_internal(void); 29 extern void __leave_coroutine( void);30 extern void __finish_creation( void);32 extern void __leave_coroutine( struct coroutine_desc * ); 33 extern void __finish_creation( struct thread_desc * ); 31 34 extern void __leave_thread_monitor( struct thread_desc * this ); 32 extern void disable_interrupts() ;35 extern void disable_interrupts() OPTIONAL_THREAD; 33 36 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 34 37 … … 46 49 cor->state = Active; 47 50 48 enable_interrupts( __cfaabi_dbg_ctx );49 50 51 main( this ); 51 52 52 cor->state = Halted; 53 //Final suspend, should never return 54 __leave_coroutine( cor ); 55 __cabi_abort( "Resumed dead coroutine" ); 56 } 53 57 54 //Final suspend, should never return 55 __leave_coroutine(); 56 __cabi_abort( "Resumed dead coroutine" ); 58 static _Unwind_Reason_Code _CtxCoroutine_UnwindStop( 59 __attribute((__unused__)) int version, 60 _Unwind_Action actions, 61 __attribute((__unused__)) _Unwind_Exception_Class exceptionClass, 62 __attribute((__unused__)) struct _Unwind_Exception * unwind_exception, 63 __attribute((__unused__)) struct _Unwind_Context * context, 64 void * param 65 ) { 66 if( actions & _UA_END_OF_STACK ) { 67 // We finished unwinding the coroutine, 68 // leave it 69 __leave_coroutine( param ); 70 __cabi_abort( "Resumed dead coroutine" ); 71 } 72 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 73 74 return _URC_FATAL_PHASE2_ERROR; 75 } 76 77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__)); 78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) { 79 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor ); 80 printf("UNWIND ERROR %d after force unwind\n", ret); 81 abort(); 57 82 } 58 83 … … 63 88 void *this 64 89 ) { 90 // Fetch the thread handle from the user defined thread structure 91 struct thread_desc* thrd = get_thread( this ); 92 65 93 // First suspend, once the thread arrives here, 66 94 // the function pointer to main can be invalidated without risk 67 __finish_creation(); 68 69 // Fetch the thread handle from the user defined thread structure 70 struct thread_desc* thrd = get_thread( this ); 71 thrd->self_cor.last = NULL; 95 __finish_creation( thrd ); 72 96 73 97 // Officially start the thread by enabling preemption … … 95 119 void (*invoke)(void *) 96 120 ) { 97 struct coStack_t* stack = &get_coroutine( this )->stack; 121 struct coroutine_desc * cor = get_coroutine( this ); 122 struct __stack_t * stack = cor->stack.storage; 98 123 99 124 #if defined( __i386 ) 100 125 101 126 struct FakeStack { 102 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 103 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls) 104 uint16_t fcw; // X97 FPU control word (preserved across function calls) 127 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 105 128 void *rturn; // where to go on return from uSwitch 106 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke107 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here108 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned129 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke 130 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here 131 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned 109 132 }; 110 133 111 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );112 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp134 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 135 cor->context.FP = NULL; // terminate stack with NULL fp 113 136 114 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;115 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = this; // argument to invoke 116 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke;117 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520118 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7137 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 138 139 fs->dummyReturn = NULL; 140 fs->argument[0] = this; // argument to invoke 141 fs->rturn = invoke; 119 142 120 143 #elif defined( __x86_64 ) … … 122 145 struct FakeStack { 123 146 void *fixedRegisters[5]; // fixed registers rbx, r12, r13, r14, r15 124 uint32_t mxcr; // SSE Status and Control bits (control bits are preserved across function calls)125 uint16_t fcw; // X97 FPU control word (preserved across function calls)126 147 void *rturn; // where to go on return from uSwitch 127 148 void *dummyReturn; // NULL return address to provide proper alignment 128 149 }; 129 150 130 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );131 ((struct machine_context_t *)stack->context)->FP = NULL; // terminate stack with NULL fp151 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 152 cor->context.FP = NULL; // terminate stack with NULL fp 132 153 133 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL;134 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = CtxInvokeStub; 135 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = this;136 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke;137 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->mxcr = 0x1F80; //Vol. 2A 3-520138 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fcw = 0x037F; //Vol. 1 8-7154 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 155 156 fs->dummyReturn = NULL; 157 fs->rturn = CtxInvokeStub; 158 fs->fixedRegisters[0] = this; 159 fs->fixedRegisters[1] = invoke; 139 160 140 161 #elif defined( __ARM_ARCH ) … … 146 167 }; 147 168 148 ((struct machine_context_t *)stack->context)->SP = (char *)stack->base - sizeof( struct FakeStack );149 ((struct machine_context_t *)stack->context)->FP = NULL;169 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 170 cor->context.FP = NULL; 150 171 151 struct FakeStack *fs = (struct FakeStack *) ((struct machine_context_t *)stack->context)->SP;172 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 152 173 153 174 fs->intRegs[8] = CtxInvokeStub; -
libcfa/src/concurrency/invoke.h
r7951100 rb067d9b 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 19 08:23:21 201813 // Update Count : 3114 // 15 16 #include "bits/containers.h "17 #include "bits/defs.h "18 #include "bits/locks.h "12 // Last Modified On : Sat Jun 22 18:19:13 2019 13 // Update Count : 40 14 // 15 16 #include "bits/containers.hfa" 17 #include "bits/defs.hfa" 18 #include "bits/locks.hfa" 19 19 20 20 #ifdef __cforall … … 46 46 #ifdef __cforall 47 47 extern "Cforall" { 48 static inline struct thread_desc * & get_next( struct thread_desc & this );49 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this );50 51 48 extern thread_local struct KernelThreadData { 52 struct coroutine_desc * volatile this_coroutine;53 49 struct thread_desc * volatile this_thread; 54 50 struct processor * volatile this_processor; … … 59 55 volatile bool in_progress; 60 56 } preemption_state; 61 } kernelTLS ;57 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 62 58 } 63 64 static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_coroutine ); }65 static inline struct thread_desc * volatile active_thread () { return TL_GET( this_thread ); }66 static inline struct processor * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE67 59 #endif 68 60 69 struct coStack_t { 70 size_t size; // size of stack 71 void * storage; // pointer to stack 72 void * limit; // stack grows towards stack limit 73 void * base; // base of stack 74 void * context; // address of cfa_context_t 75 void * top; // address of top of storage 76 bool userStack; // whether or not the user allocated the stack 61 struct __stack_context_t { 62 void * SP; 63 void * FP; 64 }; 65 66 // low adresses : +----------------------+ <- start of allocation 67 // | optional guard page | 68 // +----------------------+ <- __stack_t.limit 69 // | | 70 // | /\ /\ /\ | 71 // | || || || | 72 // | | 73 // | program stack | 74 // | | 75 // __stack_info_t.storage -> +----------------------+ <- __stack_t.base 76 // | __stack_t | 77 // high adresses : +----------------------+ <- end of allocation 78 79 struct __stack_t { 80 // stack grows towards stack limit 81 void * limit; 82 83 // base of stack 84 void * base; 85 }; 86 87 struct __stack_info_t { 88 // pointer to stack 89 struct __stack_t * storage; 77 90 }; 78 91 … … 80 93 81 94 struct coroutine_desc { 82 struct coStack_t stack; // stack information of the coroutine 83 const char * name; // textual name for coroutine/task, initialized by uC++ generated code 84 int errno_; // copy of global UNIX variable errno 85 enum coroutine_state state; // current execution status for coroutine 86 struct coroutine_desc * starter; // first coroutine to resume this one 87 struct coroutine_desc * last; // last coroutine to resume this one 88 }; 89 95 // context that is switch during a CtxSwitch 96 struct __stack_context_t context; 97 98 // stack information of the coroutine 99 struct __stack_info_t stack; 100 101 // textual name for coroutine/task 102 const char * name; 103 104 // current execution status for coroutine 105 enum coroutine_state state; 106 107 // first coroutine to resume this one 108 struct coroutine_desc * starter; 109 110 // last coroutine to resume this one 111 struct coroutine_desc * last; 112 113 // If non-null stack must be unwound with this exception 114 struct _Unwind_Exception * cancellation; 115 116 }; 117 118 // struct which calls the monitor is accepting 90 119 struct __waitfor_mask_t { 91 120 // the index of the accepted function, -1 if none … … 93 122 94 123 // list of acceptable functions, null if any 95 __ small_array_t(struct __acceptable_t) __cfa_anonymous_object;124 __cfa_anonymous_object( __small_array_t(struct __acceptable_t) ); 96 125 }; 97 126 … … 121 150 struct __monitor_group_t { 122 151 // currently held monitors 123 __ small_array_t(monitor_desc*) __cfa_anonymous_object;152 __cfa_anonymous_object( __small_array_t(monitor_desc*) ); 124 153 125 154 // last function that acquired monitors … … 129 158 struct thread_desc { 130 159 // Core threading fields 160 // context that is switch during a CtxSwitch 161 struct __stack_context_t context; 162 163 // current execution status for coroutine 164 enum coroutine_state state; 165 166 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it 167 131 168 // coroutine body used to store context 132 169 struct coroutine_desc self_cor; … … 155 192 struct thread_desc * prev; 156 193 } node; 157 };158 159 #ifdef __cforall160 extern "Cforall" {161 static inline thread_desc * & get_next( thread_desc & this ) {194 }; 195 196 #ifdef __cforall 197 extern "Cforall" { 198 static inline thread_desc *& get_next( thread_desc & this ) { 162 199 return this.next; 163 200 } … … 166 203 return this.node.[next, prev]; 167 204 } 168 169 static inline struct __condition_criterion_t * & get_next( struct __condition_criterion_t & this );170 205 171 206 static inline void ?{}(__monitor_group_t & this) { … … 216 251 // assembler routines that performs the context switch 217 252 extern void CtxInvokeStub( void ); 218 void CtxSwitch( void * from, void * to ) asm ("CtxSwitch"); 219 220 #if defined( __i386 ) 221 #define CtxGet( ctx ) __asm__ ( \ 222 "movl %%esp,%0\n" \ 223 "movl %%ebp,%1\n" \ 224 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 225 #elif defined( __x86_64 ) 226 #define CtxGet( ctx ) __asm__ ( \ 227 "movq %%rsp,%0\n" \ 228 "movq %%rbp,%1\n" \ 229 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 230 #elif defined( __ARM_ARCH ) 231 #define CtxGet( ctx ) __asm__ ( \ 232 "mov %0,%%sp\n" \ 233 "mov %1,%%r11\n" \ 234 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 235 #else 236 #error unknown hardware architecture 237 #endif 253 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch"); 254 // void CtxStore ( void * this ) asm ("CtxStore"); 255 // void CtxRet ( void * dst ) asm ("CtxRet"); 238 256 239 257 #endif //_INVOKE_PRIVATE_H_ -
libcfa/src/concurrency/kernel.cfa
r7951100 rb067d9b 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 9 16:11:46 201813 // Update Count : 2 412 // Last Modified On : Thu Jun 20 17:21:23 2019 13 // Update Count : 25 14 14 // 15 16 #define __cforall_thread__ 15 17 16 18 //C Includes … … 27 29 28 30 //CFA Includes 29 #include "time "30 #include "kernel_private.h "31 #include "preemption.h "32 #include "startup.h "31 #include "time.hfa" 32 #include "kernel_private.hfa" 33 #include "preemption.hfa" 34 #include "startup.hfa" 33 35 34 36 //Private includes … … 36 38 #include "invoke.h" 37 39 40 //----------------------------------------------------------------------------- 41 // Some assembly required 42 #if defined( __i386 ) 43 #define CtxGet( ctx ) \ 44 __asm__ volatile ( \ 45 "movl %%esp,%0\n"\ 46 "movl %%ebp,%1\n"\ 47 : "=rm" (ctx.SP),\ 48 "=rm" (ctx.FP) \ 49 ) 50 51 // mxcr : SSE Status and Control bits (control bits are preserved across function calls) 52 // fcw : X87 FPU control word (preserved across function calls) 53 #define __x87_store \ 54 uint32_t __mxcr; \ 55 uint16_t __fcw; \ 56 __asm__ volatile ( \ 57 "stmxcsr %0\n" \ 58 "fnstcw %1\n" \ 59 : "=m" (__mxcr),\ 60 "=m" (__fcw) \ 61 ) 62 63 #define __x87_load \ 64 __asm__ volatile ( \ 65 "fldcw %1\n" \ 66 "ldmxcsr %0\n" \ 67 ::"m" (__mxcr),\ 68 "m" (__fcw) \ 69 ) 70 71 #elif defined( __x86_64 ) 72 #define CtxGet( ctx ) \ 73 __asm__ volatile ( \ 74 "movq %%rsp,%0\n"\ 75 "movq %%rbp,%1\n"\ 76 : "=rm" (ctx.SP),\ 77 "=rm" (ctx.FP) \ 78 ) 79 80 #define __x87_store \ 81 uint32_t __mxcr; \ 82 uint16_t __fcw; \ 83 __asm__ volatile ( \ 84 "stmxcsr %0\n" \ 85 "fnstcw %1\n" \ 86 : "=m" (__mxcr),\ 87 "=m" (__fcw) \ 88 ) 89 90 #define __x87_load \ 91 __asm__ volatile ( \ 92 "fldcw %1\n" \ 93 "ldmxcsr %0\n" \ 94 :: "m" (__mxcr),\ 95 "m" (__fcw) \ 96 ) 97 98 99 #elif defined( __ARM_ARCH ) 100 #define CtxGet( ctx ) __asm__ ( \ 101 "mov %0,%%sp\n" \ 102 "mov %1,%%r11\n" \ 103 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 104 #else 105 #error unknown hardware architecture 106 #endif 107 108 //----------------------------------------------------------------------------- 38 109 //Start and stop routine for the kernel, declared first to make sure they run first 39 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));110 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 111 static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 41 112 42 113 //----------------------------------------------------------------------------- 43 114 // Kernel storage 44 KERNEL_STORAGE(cluster, mainCluster);45 KERNEL_STORAGE(processor, mainProcessor);46 KERNEL_STORAGE(thread_desc, mainThread);47 KERNEL_STORAGE( machine_context_t,mainThreadCtx);115 KERNEL_STORAGE(cluster, mainCluster); 116 KERNEL_STORAGE(processor, mainProcessor); 117 KERNEL_STORAGE(thread_desc, mainThread); 118 KERNEL_STORAGE(__stack_t, mainThreadCtx); 48 119 49 120 cluster * mainCluster; … … 55 126 } 56 127 128 size_t __page_size = 0; 129 57 130 //----------------------------------------------------------------------------- 58 131 // Global state 59 thread_local struct KernelThreadData kernelTLS = { 60 NULL, 132 thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = { 61 133 NULL, 62 134 NULL, … … 67 139 // Struct to steal stack 68 140 struct current_stack_info_t { 69 machine_context_t ctx; 70 unsigned int size; // size of stack 141 __stack_t * storage; // pointer to stack object 71 142 void *base; // base of stack 72 void *storage; // pointer to stack73 143 void *limit; // stack grows towards stack limit 74 144 void *context; // address of cfa_context_t 75 void *top; // address of top of storage76 145 }; 77 146 78 147 void ?{}( current_stack_info_t & this ) { 79 CtxGet( this.ctx );80 this.base = this.ctx.FP;81 this. storage = this.ctx.SP;148 __stack_context_t ctx; 149 CtxGet( ctx ); 150 this.base = ctx.FP; 82 151 83 152 rlimit r; 84 153 getrlimit( RLIMIT_STACK, &r); 85 this.size = r.rlim_cur;86 87 this.limit = (void *)(((intptr_t)this.base) - this.size);154 size_t size = r.rlim_cur; 155 156 this.limit = (void *)(((intptr_t)this.base) - size); 88 157 this.context = &storage_mainThreadCtx; 89 this.top = this.base;90 158 } 91 159 92 160 //----------------------------------------------------------------------------- 93 161 // Main thread construction 94 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) {95 size = info->size;96 storage = info->storage;97 limit = info->limit;98 base = info->base;99 context = info->context;100 top = info->top;101 userStack = true;102 }103 162 104 163 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 105 stack{ info }; 164 stack.storage = info->storage; 165 with(*stack.storage) { 166 limit = info->limit; 167 base = info->base; 168 } 169 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage; 170 *istorage |= 0x1; 106 171 name = "Main Thread"; 107 errno_ = 0;108 172 state = Start; 109 173 starter = NULL; 174 last = NULL; 175 cancellation = NULL; 110 176 } 111 177 112 178 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 179 state = Start; 113 180 self_cor{ info }; 114 181 curr_cor = &self_cor; … … 133 200 134 201 // Construct the processor context of non-main processors 135 void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {202 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) { 136 203 (this.__cor){ info }; 137 204 this.proc = proc; 138 205 } 139 206 207 static void start(processor * this); 140 208 void ?{}(processor & this, const char * name, cluster & cltr) with( this ) { 141 209 this.name = name; … … 147 215 runner.proc = &this; 148 216 149 sem_init(&idleLock, 0, 0);217 idleLock{}; 150 218 151 219 start( &this ); … … 155 223 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 156 224 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 157 terminate(&this); 158 verify( __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 159 verify( kernelTLS.this_processor != &this); 225 226 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 227 wake( &this ); 228 160 229 P( terminated ); 161 230 verify( kernelTLS.this_processor != &this); 162 pthread_join( kernel_thread, NULL ); 163 } 164 165 sem_destroy(&idleLock); 231 } 232 233 pthread_join( kernel_thread, NULL ); 166 234 } 167 235 … … 186 254 // Kernel Scheduling logic 187 255 //============================================================================================= 256 static void runThread(processor * this, thread_desc * dst); 257 static void finishRunning(processor * this); 258 static void halt(processor * this); 259 188 260 //Main of the processor contexts 189 261 void main(processorCtx_t & runner) { … … 236 308 } 237 309 310 static int * __volatile_errno() __attribute__((noinline)); 311 static int * __volatile_errno() { asm(""); return &errno; } 312 238 313 // KERNEL ONLY 239 314 // runThread runs a thread by context switching 240 315 // from the processor coroutine to the target thread 241 void runThread(processor * this, thread_desc * dst) { 242 assert(dst->curr_cor); 316 static void runThread(processor * this, thread_desc * thrd_dst) { 243 317 coroutine_desc * proc_cor = get_coroutine(this->runner); 244 coroutine_desc * thrd_cor = dst->curr_cor;245 318 246 319 // Reset the terminating actions here … … 248 321 249 322 // Update global state 250 kernelTLS.this_thread = dst; 251 252 // Context Switch to the thread 253 ThreadCtxSwitch(proc_cor, thrd_cor); 254 // when ThreadCtxSwitch returns we are back in the processor coroutine 323 kernelTLS.this_thread = thrd_dst; 324 325 // set state of processor coroutine to inactive and the thread to active 326 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 327 thrd_dst->state = Active; 328 329 // set context switch to the thread that the processor is executing 330 verify( thrd_dst->context.SP ); 331 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 332 // when CtxSwitch returns we are back in the processor coroutine 333 334 // set state of processor coroutine to active and the thread to inactive 335 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 336 proc_cor->state = Active; 255 337 } 256 338 257 339 // KERNEL_ONLY 258 void returnToKernel() {340 static void returnToKernel() { 259 341 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 260 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine; 261 ThreadCtxSwitch(thrd_cor, proc_cor); 342 thread_desc * thrd_src = kernelTLS.this_thread; 343 344 // set state of current coroutine to inactive 345 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 346 proc_cor->state = Active; 347 int local_errno = *__volatile_errno(); 348 #if defined( __i386 ) || defined( __x86_64 ) 349 __x87_store; 350 #endif 351 352 // set new coroutine that the processor is executing 353 // and context switch to it 354 verify( proc_cor->context.SP ); 355 CtxSwitch( &thrd_src->context, &proc_cor->context ); 356 357 // set state of new coroutine to active 358 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 359 thrd_src->state = Active; 360 361 #if defined( __i386 ) || defined( __x86_64 ) 362 __x87_load; 363 #endif 364 *__volatile_errno() = local_errno; 262 365 } 263 366 … … 265 368 // Once a thread has finished running, some of 266 369 // its final actions must be executed from the kernel 267 void finishRunning(processor * this) with( this->finish ) {370 static void finishRunning(processor * this) with( this->finish ) { 268 371 verify( ! kernelTLS.preemption_state.enabled ); 269 372 choose( action_code ) { … … 295 398 } 296 399 297 // Handles spinning logic298 // TODO : find some strategy to put cores to sleep after some time299 void spin(processor * this, unsigned int * spin_count) {300 // (*spin_count)++;301 halt(this);302 }303 304 400 // KERNEL_ONLY 305 401 // Context invoker for processors 306 402 // This is the entry point for processors (kernel threads) 307 403 // It effectively constructs a coroutine by stealing the pthread stack 308 void * CtxInvokeProcessor(void * arg) {404 static void * CtxInvokeProcessor(void * arg) { 309 405 processor * proc = (processor *) arg; 310 406 kernelTLS.this_processor = proc; 311 kernelTLS.this_coroutine = NULL;312 407 kernelTLS.this_thread = NULL; 313 408 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 316 411 // to waste the perfectly valid stack create by pthread. 317 412 current_stack_info_t info; 318 machine_context_t ctx;319 info. context= &ctx;413 __stack_t ctx; 414 info.storage = &ctx; 320 415 (proc->runner){ proc, &info }; 321 416 322 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack. base);417 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 323 418 324 419 //Set global state 325 kernelTLS.this_coroutine = get_coroutine(proc->runner);326 420 kernelTLS.this_thread = NULL; 327 421 … … 343 437 } 344 438 345 void start(processor * this) {439 static void start(processor * this) { 346 440 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this); 347 441 … … 352 446 353 447 // KERNEL_ONLY 354 void kernel_first_resume( processor * this) {355 coroutine_desc * src = kernelTLS.this_coroutine;448 void kernel_first_resume( processor * this ) { 449 thread_desc * src = mainThread; 356 450 coroutine_desc * dst = get_coroutine(this->runner); 357 451 358 452 verify( ! kernelTLS.preemption_state.enabled ); 359 453 360 create_stack(&dst->stack, dst->stack.size);454 __stack_prepare( &dst->stack, 65000 ); 361 455 CtxStart(&this->runner, CtxInvokeCoroutine); 362 456 363 457 verify( ! kernelTLS.preemption_state.enabled ); 364 458 365 dst->last = src;366 dst->starter = dst->starter ? dst->starter : src;459 dst->last = &src->self_cor; 460 dst->starter = dst->starter ? dst->starter : &src->self_cor; 367 461 368 462 // set state of current coroutine to inactive 369 463 src->state = src->state == Halted ? Halted : Inactive; 370 464 371 // set new coroutine that task is executing372 kernelTLS.this_coroutine = dst;373 374 // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.375 // Therefore, when first creating a coroutine, interrupts are enable before calling the main.376 // This is consistent with thread creation. However, when creating the main processor coroutine,377 // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will378 // stay disabled.379 disable_interrupts();380 381 465 // context switch to specified coroutine 382 assert( src->stack.context);383 CtxSwitch( src->stack.context, dst->stack.context );466 verify( dst->context.SP ); 467 CtxSwitch( &src->context, &dst->context ); 384 468 // when CtxSwitch returns we are back in the src coroutine 385 469 … … 388 472 389 473 verify( ! kernelTLS.preemption_state.enabled ); 474 } 475 476 // KERNEL_ONLY 477 void kernel_last_resume( processor * this ) { 478 coroutine_desc * src = &mainThread->self_cor; 479 coroutine_desc * dst = get_coroutine(this->runner); 480 481 verify( ! kernelTLS.preemption_state.enabled ); 482 verify( dst->starter == src ); 483 verify( dst->context.SP ); 484 485 // context switch to the processor 486 CtxSwitch( &src->context, &dst->context ); 390 487 } 391 488 … … 396 493 void ScheduleThread( thread_desc * thrd ) { 397 494 verify( thrd ); 398 verify( thrd->s elf_cor.state != Halted );495 verify( thrd->state != Halted ); 399 496 400 497 verify( ! kernelTLS.preemption_state.enabled ); … … 408 505 unlock( ready_queue_lock ); 409 506 410 if( was_empty) {507 if(was_empty) { 411 508 lock (proc_list_lock __cfaabi_dbg_ctx2); 412 509 if(idles) { 413 wake (idles.head);510 wake_fast(idles.head); 414 511 } 415 512 unlock (proc_list_lock); 416 513 } 514 else if( struct processor * idle = idles.head ) { 515 wake_fast(idle); 516 } 517 417 518 } 418 519 … … 545 646 //----------------------------------------------------------------------------- 546 647 // Kernel boot procedures 547 void kernel_startup(void) {648 static void kernel_startup(void) { 548 649 verify( ! kernelTLS.preemption_state.enabled ); 549 650 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 651 652 __page_size = sysconf( _SC_PAGESIZE ); 550 653 551 654 __cfa_dbg_global_clusters.list{ __get }; … … 563 666 mainThread = (thread_desc *)&storage_mainThread; 564 667 current_stack_info_t info; 668 info.storage = (__stack_t*)&storage_mainThreadCtx; 565 669 (*mainThread){ &info }; 566 670 … … 597 701 kernelTLS.this_processor = mainProcessor; 598 702 kernelTLS.this_thread = mainThread; 599 kernelTLS.this_coroutine = &mainThread->self_cor;600 703 601 704 // Enable preemption … … 621 724 } 622 725 623 void kernel_shutdown(void) {726 static void kernel_shutdown(void) { 624 727 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 625 728 … … 632 735 // which is currently here 633 736 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 634 returnToKernel();737 kernel_last_resume( kernelTLS.this_processor ); 635 738 mainThread->self_cor.state = Halted; 636 739 … … 658 761 // Kernel Quiescing 659 762 //============================================================================================= 660 661 void halt(processor * this) with( *this ) { 662 verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 763 static void halt(processor * this) with( *this ) { 764 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 663 765 664 766 with( *cltr ) { … … 671 773 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 672 774 673 // #ifdef __CFA_WITH_VERIFY__ 674 // int sval = 0; 675 // sem_getvalue(&this->idleLock, &sval); 676 // verifyf(sval < 200, "Binary semaphore reached value %d : \n", sval); 677 // #endif 678 679 verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 680 int __attribute__((unused)) ret = sem_wait(&idleLock); 681 // verifyf(ret >= 0 || errno == EINTR, "Sem_wait returned %d (errno %d : %s\n", ret, errno, strerror(errno)); 682 683 // wait( idleLock ); 775 wait( idleLock ); 684 776 685 777 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); … … 693 785 } 694 786 695 void wake(processor * this) {696 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);697 int __attribute__((unused)) ret = sem_post(&this->idleLock);698 // verifyf(ret >= 0 || errno == EINTR, "Sem_post returned %d (errno %d : %s\n", ret, errno, strerror(errno));699 700 // #ifdef __CFA_WITH_VERIFY__701 // int sval = 0;702 // sem_getvalue(&this->idleLock, &sval);703 // verifyf(sval < 200, "Binary semaphore reached value %d\n", sval);704 // #endif705 706 // post( this->idleLock );707 }708 709 787 //============================================================================================= 710 788 // Unexpected Terminating logic 711 789 //============================================================================================= 712 713 714 790 static __spinlock_t kernel_abort_lock; 715 791 static bool kernel_abort_called = false; … … 745 821 __cfaabi_dbg_bits_write( abort_text, len ); 746 822 747 if ( get_coroutine(thrd) != kernelTLS.this_coroutine) {748 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine);823 if ( &thrd->self_cor != thrd->curr_cor ) { 824 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor ); 749 825 __cfaabi_dbg_bits_write( abort_text, len ); 750 826 } … … 833 909 void doregister( cluster * cltr, thread_desc & thrd ) { 834 910 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 911 cltr->nthreads += 1; 835 912 push_front(cltr->threads, thrd); 836 913 unlock (cltr->thread_list_lock); … … 840 917 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 841 918 remove(cltr->threads, thrd ); 919 cltr->nthreads -= 1; 842 920 unlock(cltr->thread_list_lock); 843 921 } … … 845 923 void doregister( cluster * cltr, processor * proc ) { 846 924 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 925 cltr->nprocessors += 1; 847 926 push_front(cltr->procs, *proc); 848 927 unlock (cltr->proc_list_lock); … … 852 931 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 853 932 remove(cltr->procs, *proc ); 933 cltr->nprocessors -= 1; 854 934 unlock(cltr->proc_list_lock); 855 935 } … … 858 938 // Debug 859 939 __cfaabi_dbg_debug_do( 860 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) { 861 this.prev_name = prev_name; 862 this.prev_thrd = kernelTLS.this_thread; 940 extern "C" { 941 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) { 942 this.prev_name = prev_name; 943 this.prev_thrd = kernelTLS.this_thread; 944 } 863 945 } 864 946 ) 947 948 //----------------------------------------------------------------------------- 949 // Debug 950 bool threading_enabled(void) { 951 return true; 952 } 865 953 // Local Variables: // 866 954 // mode: c // -
libcfa/src/concurrency/kernel.hfa
r7951100 rb067d9b 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 10 14:46:49 201813 // Update Count : 1 012 // Last Modified On : Sat Jun 22 11:39:17 2019 13 // Update Count : 16 14 14 // 15 15 … … 19 19 20 20 #include "invoke.h" 21 #include "time_t.h "21 #include "time_t.hfa" 22 22 23 23 extern "C" { … … 91 91 this.lock = NULL; 92 92 } 93 static inline void ^?{}(FinishAction & this) {}93 static inline void ^?{}(FinishAction &) {} 94 94 95 95 // Processor … … 113 113 pthread_t kernel_thread; 114 114 115 // RunThread data 116 // Action to do after a thread is ran 117 struct FinishAction finish; 118 119 // Preemption data 120 // Node which is added in the discrete event simulaiton 121 struct alarm_node_t * preemption_alarm; 122 123 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible 124 bool pending_preemption; 125 126 // Idle lock 127 __bin_sem_t idleLock; 128 115 129 // Termination 116 130 // Set to true to notify the processor should terminate … … 119 133 // Termination synchronisation 120 134 semaphore terminated; 121 122 // RunThread data123 // Action to do after a thread is ran124 struct FinishAction finish;125 126 // Preemption data127 // Node which is added in the discrete event simulaiton128 struct alarm_node_t * preemption_alarm;129 130 // If true, a preemption was triggered in an unsafe region, the processor must preempt as soon as possible131 bool pending_preemption;132 133 // Idle lock134 sem_t idleLock;135 // __bin_sem_t idleLock;136 135 137 136 // Link lists fields … … 177 176 __dllist_t(struct processor) procs; 178 177 __dllist_t(struct processor) idles; 179 180 // List of processors 178 unsigned int nprocessors; 179 180 // List of threads 181 181 __spinlock_t thread_list_lock; 182 182 __dllist_t(struct thread_desc) threads; 183 unsigned int nthreads; 183 184 184 185 // Link lists fields … … 201 202 } 202 203 204 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 205 static inline struct cluster * active_cluster () { return TL_GET( this_processor )->cltr; } 206 203 207 // Local Variables: // 204 208 // mode: c // -
libcfa/src/concurrency/kernel_private.hfa
r7951100 rb067d9b 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // kernel_private.h --7 // kernel_private.hfa -- 8 8 // 9 9 // Author : Thierry Delisle … … 16 16 #pragma once 17 17 18 #include "kernel "19 #include "thread "18 #include "kernel.hfa" 19 #include "thread.hfa" 20 20 21 #include "alarm.h "21 #include "alarm.hfa" 22 22 23 23 … … 26 26 27 27 extern "C" { 28 void disable_interrupts() ;28 void disable_interrupts() OPTIONAL_THREAD; 29 29 void enable_interrupts_noPoll(); 30 30 void enable_interrupts( __cfaabi_dbg_ctx_param ); … … 34 34 static inline void WakeThread( thread_desc * thrd ) { 35 35 if( !thrd ) return; 36 37 verify(thrd->state == Inactive); 36 38 37 39 disable_interrupts(); … … 54 56 // Processor 55 57 void main(processorCtx_t *); 56 void start(processor * this); 57 void runThread(processor * this, thread_desc * dst); 58 void finishRunning(processor * this); 59 void halt(processor * this); 60 void wake(processor * this); 61 void terminate(processor * this); 62 void spin(processor * this, unsigned int * spin_count); 58 59 static inline void wake_fast(processor * this) { 60 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this); 61 post( this->idleLock ); 62 } 63 64 static inline void wake(processor * this) { 65 disable_interrupts(); 66 wake_fast(this); 67 enable_interrupts( __cfaabi_dbg_ctx ); 68 } 63 69 64 70 struct event_kernel_t { … … 69 75 extern event_kernel_t * event_kernel; 70 76 71 //extern thread_local coroutine_desc * volatile this_coroutine;72 //extern thread_local thread_desc * volatile this_thread;73 //extern thread_local processor * volatile this_processor;74 75 // extern volatile thread_local bool preemption_in_progress;76 // extern volatile thread_local bool preemption_enabled;77 // extern volatile thread_local unsigned short disable_preempt_count;78 79 77 struct __cfa_kernel_preemption_state_t { 80 78 bool enabled; … … 83 81 }; 84 82 85 extern volatile thread_local __cfa_kernel_preemption_state_t preemption_state ;83 extern volatile thread_local __cfa_kernel_preemption_state_t preemption_state __attribute__ ((tls_model ( "initial-exec" ))); 86 84 87 85 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/monitor.cfa
r7951100 rb067d9b 14 14 // 15 15 16 #include "monitor" 17 18 #include <stdlib> 16 #define __cforall_thread__ 17 18 #include "monitor.hfa" 19 20 #include <stdlib.hfa> 19 21 #include <inttypes.h> 20 22 21 #include "kernel_private.h "22 23 #include "bits/algorithm s.h"23 #include "kernel_private.hfa" 24 25 #include "bits/algorithm.hfa" 24 26 25 27 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/monitor.hfa
r7951100 rb067d9b 20 20 #include <assert.h> 21 21 #include "invoke.h" 22 #include "stdlib "22 #include "stdlib.hfa" 23 23 24 24 trait is_monitor(dtype T) { … … 138 138 139 139 struct __acceptable_t { 140 __monitor_group_t;140 inline struct __monitor_group_t; 141 141 bool is_dtor; 142 142 }; -
libcfa/src/concurrency/mutex.cfa
r7951100 rb067d9b 16 16 // 17 17 18 # include "mutex"18 #define __cforall_thread__ 19 19 20 #include "kernel_private.h" 20 #include "mutex.hfa" 21 22 #include "kernel_private.hfa" 21 23 22 24 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/mutex.hfa
r7951100 rb067d9b 20 20 #include <stdbool.h> 21 21 22 #include "bits/algorithm s.h"23 #include "bits/locks.h "22 #include "bits/algorithm.hfa" 23 #include "bits/locks.hfa" 24 24 25 25 #include "invoke.h" 26 #include "time_t.h "26 #include "time_t.hfa" 27 27 28 28 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/preemption.cfa
r7951100 rb067d9b 14 14 // 15 15 16 #include "preemption.h" 16 #define __cforall_thread__ 17 18 #include "preemption.hfa" 17 19 #include <assert.h> 18 20 … … 24 26 } 25 27 26 #include "bits/signal.h "28 #include "bits/signal.hfa" 27 29 28 30 #if !defined(__CFA_DEFAULT_PREEMPTION__) … … 39 41 40 42 // FwdDeclarations : Signal handlers 41 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );42 void sigHandler_segv ( __CFA_SIGPARMS__ );43 void sigHandler_ill ( __CFA_SIGPARMS__ );44 void sigHandler_fpe ( __CFA_SIGPARMS__ );45 void sigHandler_abort ( __CFA_SIGPARMS__ );43 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 44 static void sigHandler_segv ( __CFA_SIGPARMS__ ); 45 static void sigHandler_ill ( __CFA_SIGPARMS__ ); 46 static void sigHandler_fpe ( __CFA_SIGPARMS__ ); 47 static void sigHandler_abort ( __CFA_SIGPARMS__ ); 46 48 47 49 // FwdDeclarations : alarm thread main 48 void * alarm_loop( __attribute__((unused)) void * args );50 static void * alarm_loop( __attribute__((unused)) void * args ); 49 51 50 52 // Machine specific register name … … 63 65 static pthread_t alarm_thread; // pthread handle to alarm thread 64 66 65 void ?{}(event_kernel_t & this) with( this ) {67 static void ?{}(event_kernel_t & this) with( this ) { 66 68 alarms{}; 67 69 lock{}; … … 85 87 86 88 // Tick one frame of the Discrete Event Simulation for alarms 87 void tick_preemption() {89 static void tick_preemption() { 88 90 alarm_node_t * node = NULL; // Used in the while loop but cannot be declared in the while condition 89 91 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 263 265 } 264 266 265 // kill wrapper : signal a processor266 void terminate(processor * this) {267 disable_interrupts();268 __atomic_store_n(&this->do_terminate, true, __ATOMIC_SEQ_CST);269 wake( this );270 sigval_t value = { PREEMPT_TERMINATE };271 enable_interrupts( __cfaabi_dbg_ctx );272 pthread_sigqueue( this->kernel_thread, SIGUSR1, value );273 }274 275 267 // reserved for future use 276 268 static void timeout( thread_desc * this ) { … … 360 352 // Context switch signal handler 361 353 // Receives SIGUSR1 signal and causes the current thread to yield 362 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {354 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 363 355 __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); ) 364 356 … … 403 395 // Main of the alarm thread 404 396 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 405 void * alarm_loop( __attribute__((unused)) void * args ) {397 static void * alarm_loop( __attribute__((unused)) void * args ) { 406 398 // Block sigalrms to control when they arrive 407 399 sigset_t mask; -
libcfa/src/concurrency/preemption.hfa
r7951100 rb067d9b 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // preemption.h --7 // preemption.hfa -- 8 8 // 9 9 // Author : Thierry Delisle … … 16 16 #pragma once 17 17 18 #include "alarm.h "19 #include "kernel_private.h "18 #include "alarm.hfa" 19 #include "kernel_private.hfa" 20 20 21 21 void kernel_start_preemption(); 22 22 void kernel_stop_preemption(); 23 23 void update_preemption( processor * this, Duration duration ); 24 void tick_preemption();25 24 26 25 struct preemption_scope { -
libcfa/src/concurrency/thread.cfa
r7951100 rb067d9b 14 14 // 15 15 16 # include "thread"16 #define __cforall_thread__ 17 17 18 #include "kernel_private.h" 18 #include "thread.hfa" 19 20 #include "kernel_private.hfa" 19 21 20 22 #define __CFA_INVOKE_PRIVATE__ … … 31 33 // Thread ctors and dtors 32 34 void ?{}(thread_desc & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) { 35 context{ NULL, NULL }; 33 36 self_cor{ name, storage, storageSize }; 34 verify(&self_cor);37 state = Start; 35 38 curr_cor = &self_cor; 36 39 self_mon.owner = &this; … … 73 76 forall( dtype T | is_thread(T) ) 74 77 void __thrd_start( T& this ) { 75 coroutine_desc* thrd_c = get_coroutine(this); 76 thread_desc * thrd_h = get_thread (this); 77 thrd_c->last = TL_GET( this_coroutine ); 78 79 // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); 78 thread_desc * this_thrd = get_thread(this); 79 thread_desc * curr_thrd = TL_GET( this_thread ); 80 80 81 81 disable_interrupts(); 82 create_stack(&thrd_c->stack, thrd_c->stack.size);83 kernelTLS.this_coroutine = thrd_c;84 82 CtxStart(&this, CtxInvokeThread); 85 assert( thrd_c->last->stack.context ); 86 CtxSwitch( thrd_c->last->stack.context, thrd_c->stack.context ); 83 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 84 verify( this_thrd->context.SP ); 85 CtxSwitch( &curr_thrd->context, &this_thrd->context ); 87 86 88 ScheduleThread(th rd_h);87 ScheduleThread(this_thrd); 89 88 enable_interrupts( __cfaabi_dbg_ctx ); 90 89 } … … 92 91 extern "C" { 93 92 // KERNEL ONLY 94 void __finish_creation(void) { 95 coroutine_desc* thrd_c = kernelTLS.this_coroutine; 96 ThreadCtxSwitch( thrd_c, thrd_c->last ); 93 void __finish_creation(thread_desc * this) { 94 // set new coroutine that the processor is executing 95 // and context switch to it 96 verify( kernelTLS.this_thread != this ); 97 verify( kernelTLS.this_thread->context.SP ); 98 CtxSwitch( &this->context, &kernelTLS.this_thread->context ); 97 99 } 98 100 } … … 112 114 } 113 115 114 // KERNEL ONLY115 void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {116 // set state of current coroutine to inactive117 src->state = src->state == Halted ? Halted : Inactive;118 dst->state = Active;119 120 // set new coroutine that the processor is executing121 // and context switch to it122 kernelTLS.this_coroutine = dst;123 assert( src->stack.context );124 CtxSwitch( src->stack.context, dst->stack.context );125 kernelTLS.this_coroutine = src;126 127 // set state of new coroutine to active128 dst->state = dst->state == Halted ? Halted : Inactive;129 src->state = Active;130 }131 132 116 // Local Variables: // 133 117 // mode: c // -
libcfa/src/concurrency/thread.hfa
r7951100 rb067d9b 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 29 14:07:11 201813 // Update Count : 412 // Last Modified On : Fri Jun 21 17:51:33 2019 13 // Update Count : 5 14 14 // 15 15 … … 19 19 #include "invoke.h" 20 20 21 #include "coroutine "22 #include "kernel "23 #include "monitor "21 #include "coroutine.hfa" 22 #include "kernel.hfa" 23 #include "monitor.hfa" 24 24 25 25 //----------------------------------------------------------------------------- … … 61 61 void ^?{}(thread_desc & this); 62 62 63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 0 }; }63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, NULL, 65000 }; } 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, 0 }; }67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, 0, stackSize }; }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 }; } 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, 0 }; }70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, NULL, 0 }; }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 }; } 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 … … 91 91 void yield( unsigned times ); 92 92 93 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 94 93 95 // Local Variables: // 94 96 // mode: c //
Note:
See TracChangeset
for help on using the changeset viewer.