Changeset eef8dfb for libcfa/src/bits
- Timestamp:
- Jan 7, 2021, 2:55:57 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 58fe85a
- Parents:
- bdfc032 (diff), 44e37ef (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/bits
- Files:
-
- 5 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/bits/containers.hfa
rbdfc032 reef8dfb 17 17 #include "bits/align.hfa" 18 18 #include "bits/defs.hfa" 19 19 #include <stdio.h> 20 20 //----------------------------------------------------------------------------- 21 21 // Array … … 36 36 #define __small_array_t(T) __small_array(T) 37 37 #else 38 #define __small_array_t(T) struct__small_array38 #define __small_array_t(T) __small_array 39 39 #endif 40 40 … … 146 146 static inline forall( dtype T | is_node(T) ) { 147 147 void ?{}( __queue(T) & this ) with( this ) { 148 head{ 0p }; 149 tail{ &head }; 148 (this.head){ 1p }; 149 (this.tail){ &this.head }; 150 verify(*this.tail == 1p); 150 151 } 151 152 152 153 void append( __queue(T) & this, T * val ) with( this ) { 153 verify(tail != 0p); 154 *tail = val; 155 tail = &get_next( *val ); 154 verify(this.tail != 0p); 155 verify(*this.tail == 1p); 156 *this.tail = val; 157 this.tail = &get_next( *val ); 158 *this.tail = 1p; 159 } 160 161 T * peek( __queue(T) & this ) { 162 verify(*this.tail == 1p); 163 T * front = this.head; 164 if( front != 1p ) { 165 verify(*this.tail == 1p); 166 return front; 167 } 168 verify(*this.tail == 1p); 169 return 0p; 156 170 } 157 171 158 172 T * pop_head( __queue(T) & this ) { 159 T * head = this.head; 160 if( head ) { 161 this.head = get_next( *head ); 162 if( !get_next( *head ) ) { 173 verify(*this.tail == 1p); 174 T * _head = this.head; 175 if( _head != 1p ) { 176 this.head = get_next( *_head ); 177 if( get_next( *_head ) == 1p ) { 163 178 this.tail = &this.head; 164 179 } 165 get_next( *head ) = 0p; 166 } 167 return head; 180 get_next( *_head ) = 0p; 181 verify(*this.tail == 1p); 182 verify( get_next(*_head) == 0p ); 183 return _head; 184 } 185 verify(*this.tail == 1p); 186 return 0p; 168 187 } 169 188 … … 174 193 (*it) = get_next( *val ); 175 194 176 if( t ail == &get_next( *val ) ) {177 t ail = it;195 if( this.tail == &get_next( *val ) ) { 196 this.tail = it; 178 197 } 179 198 180 199 get_next( *val ) = 0p; 181 200 182 verify( ( head == 0p) == (&head ==tail) );183 verify( *t ail == 0p );201 verify( (this.head == 1p) == (&this.head == this.tail) ); 202 verify( *this.tail == 1p ); 184 203 return val; 185 204 } 186 205 187 206 int ?!=?( const __queue(T) & this, __attribute__((unused)) zero_t zero ) { 188 return this.head != 0;207 return this.head != 1p; 189 208 } 190 209 } … … 220 239 forall(dtype T ) 221 240 static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) { 222 this.head{ 0p };241 (this.head){ 0p }; 223 242 this.__get = __get; 224 243 } … … 229 248 void push_front( __dllist(T) & this, T & node ) with( this ) { 230 249 verify(__get); 231 if ( head ) {232 __get( node ).next = head;233 __get( node ).prev = __get( * head ).prev;250 if ( this.head ) { 251 __get( node ).next = this.head; 252 __get( node ).prev = __get( *this.head ).prev; 234 253 // inserted node must be consistent before it is seen 235 254 // prevent code movement across barrier 236 255 asm( "" : : : "memory" ); 237 __get( * head ).prev = &node;256 __get( *this.head ).prev = &node; 238 257 T & _prev = *__get( node ).prev; 239 258 __get( _prev ).next = &node; … … 245 264 // prevent code movement across barrier 246 265 asm( "" : : : "memory" ); 247 head = &node;266 this.head = &node; 248 267 } 249 268 250 269 void remove( __dllist(T) & this, T & node ) with( this ) { 251 270 verify(__get); 252 if ( &node == head ) {253 if ( __get( * head ).next ==head ) {254 head = 0p;271 if ( &node == this.head ) { 272 if ( __get( *this.head ).next == this.head ) { 273 this.head = 0p; 255 274 } else { 256 head = __get( *head ).next;275 this.head = __get( *this.head ).next; 257 276 } 258 277 } … … 266 285 return this.head != 0; 267 286 } 287 288 void move_to_front( __dllist(T) & src, __dllist(T) & dst, T & node ) { 289 remove (src, node); 290 push_front(dst, node); 291 } 268 292 } 269 293 #undef next -
libcfa/src/bits/debug.cfa
rbdfc032 reef8dfb 10 10 // Created On : Thu Mar 30 12:30:01 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Nov 21 17:16:30 201913 // Update Count : 1 012 // Last Modified On : Wed Jun 17 11:07:13 2020 13 // Update Count : 12 14 14 // 15 15 16 extern "C" {17 16 #include <stdio.h> 18 17 #include <stdlib.h> … … 21 20 #include <stdarg.h> 22 21 #include <unistd.h> 23 }24 22 25 23 enum { buffer_size = 4096 }; … … 27 25 28 26 extern "C" { 29 30 void __cfaabi_bits_write( int fd, const char *in_buffer, int len ) { 27 void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) { 31 28 // ensure all data is written 32 29 for ( int count = 0, retcode; count < len; count += retcode ) { -
libcfa/src/bits/debug.hfa
rbdfc032 reef8dfb 9 9 // Author : Thierry Delisle 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Thu Nov 21 17:06:58 201913 // Update Count : 811 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 27 10:15:00 2020 13 // Update Count : 10 14 14 // 15 15 16 16 #pragma once 17 18 #include <assert.h> 17 19 18 20 #ifdef __CFA_DEBUG__ … … 21 23 #define __cfaabi_dbg_ctx __PRETTY_FUNCTION__ 22 24 #define __cfaabi_dbg_ctx2 , __PRETTY_FUNCTION__ 23 #define __cfaabi_dbg_ctx_param const char * caller 24 #define __cfaabi_dbg_ctx_param2 , const char * caller 25 #define __cfaabi_dbg_ctx_param const char caller[] 26 #define __cfaabi_dbg_ctx_param2 , const char caller[] 27 #define __cfaabi_dbg_ctx_fwd caller 28 #define __cfaabi_dbg_ctx_fwd2 , caller 25 29 #else 26 30 #define __cfaabi_dbg_debug_do(...) … … 30 34 #define __cfaabi_dbg_ctx_param 31 35 #define __cfaabi_dbg_ctx_param2 36 #define __cfaabi_dbg_ctx_fwd 37 #define __cfaabi_dbg_ctx_fwd2 32 38 #endif 33 39 … … 36 42 #endif 37 43 #include <stdarg.h> 38 #include <stdio.h>39 44 40 extern void __cfaabi_bits_write( int fd, const char *buffer, int len );45 extern void __cfaabi_bits_write( int fd, const char buffer[], int len ); 41 46 extern void __cfaabi_bits_acquire(); 42 47 extern void __cfaabi_bits_release(); … … 45 50 extern void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list arg ); 46 51 extern void __cfaabi_bits_print_buffer( int fd, char buffer[], int buffer_size, const char fmt[], ... ) __attribute__(( format(printf, 4, 5) )); 52 53 #if defined(__CFA_DEBUG_PRINT__) \ 54 || defined(__CFA_DEBUG_PRINT_IO__) || defined(__CFA_DEBUG_PRINT_IO_CORE__) \ 55 || defined(__CFA_DEBUG_PRINT_MONITOR__) || defined(__CFA_DEBUG_PRINT_PREEMPTION__) \ 56 || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__) \ 57 || defined(__CFA_DEBUG_PRINT_READY_QUEUE__) 58 #include <stdio.h> 59 #include <unistd.h> 60 #endif 47 61 #ifdef __cforall 48 62 } 49 63 #endif 50 64 65 // Deprecated: Use the versions with the new module names. 51 66 #ifdef __CFA_DEBUG_PRINT__ 52 67 #define __cfaabi_dbg_write( buffer, len ) __cfaabi_bits_write( STDERR_FILENO, buffer, len ) 53 68 #define __cfaabi_dbg_acquire() __cfaabi_bits_acquire() 54 69 #define __cfaabi_dbg_release() __cfaabi_bits_release() 55 #define __cfaabi_dbg_print_safe(...) __cfaabi_bits_print_safe ( __VA_ARGS__)56 #define __cfaabi_dbg_print_nolock(...) __cfaabi_bits_print_nolock ( __VA_ARGS__)57 #define __cfaabi_dbg_print_buffer(...) __cfaabi_bits_print_buffer ( __VA_ARGS__)58 #define __cfaabi_dbg_print_buffer_decl(...) char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len );59 #define __cfaabi_dbg_print_buffer_local(...) __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( __dbg_text, __dbg_len );70 #define __cfaabi_dbg_print_safe(...) __cfaabi_bits_print_safe ( STDERR_FILENO, __VA_ARGS__ ) 71 #define __cfaabi_dbg_print_nolock(...) __cfaabi_bits_print_nolock ( STDERR_FILENO, __VA_ARGS__ ) 72 #define __cfaabi_dbg_print_buffer(...) __cfaabi_bits_print_buffer ( STDERR_FILENO, __VA_ARGS__ ) 73 #define __cfaabi_dbg_print_buffer_decl(...) char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO, __dbg_text, __dbg_len ); 74 #define __cfaabi_dbg_print_buffer_local(...) __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( STDERR_FILENO, __dbg_text, __dbg_len ); 60 75 #else 61 76 #define __cfaabi_dbg_write(...) ((void)0) … … 69 84 #endif 70 85 86 // Debug print functions and statements: 87 // Most are wrappers around the bits printing function but are not always used. 88 // If they are used depends if the group (first argument) is active or not. The group must be one 89 // defined belowe. The other arguments depend on the wrapped function. 90 #define __cfadbg_write(group, buffer, len) \ 91 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_write(STDERR_FILENO, buffer, len)) 92 #define __cfadbg_acquire(group) \ 93 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_acquire()) 94 #define __cfadbg_release(group) \ 95 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_release()) 96 #define __cfadbg_print_safe(group, ...) \ 97 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_safe(STDERR_FILENO, __VA_ARGS__)) 98 #define __cfadbg_print_nolock(group, ...) \ 99 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_nolock(STDERR_FILENO, __VA_ARGS__)) 100 #define __cfadbg_print_buffer(group, ...) \ 101 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__)) 102 #define __cfadbg_print_buffer_decl(group, ...) \ 103 __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len )) 104 #define __cfadbg_print_buffer_local(group, ...) \ 105 __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len)) 106 107 // The debug print groups: 108 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_IO__) 109 # define __CFADBG_PRINT_GROUP_io(...) __VA_ARGS__ 110 #else 111 # define __CFADBG_PRINT_GROUP_io(...) ((void)0) 112 #endif 113 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_IO__) || defined(__CFA_DEBUG_PRINT_IO_CORE__) 114 # define __CFADBG_PRINT_GROUP_io_core(...) __VA_ARGS__ 115 #else 116 # define __CFADBG_PRINT_GROUP_io_core(...) ((void)0) 117 #endif 118 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_MONITOR__) 119 # define __CFADBG_PRINT_GROUP_monitor(...) __VA_ARGS__ 120 #else 121 # define __CFADBG_PRINT_GROUP_monitor(...) ((void)0) 122 #endif 123 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_PREEMPTION__) 124 # define __CFADBG_PRINT_GROUP_preemption(...) __VA_ARGS__ 125 #else 126 # define __CFADBG_PRINT_GROUP_preemption(...) ((void)0) 127 #endif 128 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__) 129 # define __CFADBG_PRINT_GROUP_runtime_core(...) __VA_ARGS__ 130 #else 131 # define __CFADBG_PRINT_GROUP_runtime_core(...) ((void)0) 132 #endif 133 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__) 134 # define __CFADBG_PRINT_GROUP_ready_queue(...) __VA_ARGS__ 135 #else 136 # define __CFADBG_PRINT_GROUP_ready_queue(...) ((void)0) 137 #endif 138 #if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__) 139 # define __CFADBG_PRINT_GROUP_exception(...) __VA_ARGS__ 140 #else 141 # define __CFADBG_PRINT_GROUP_exception(...) ((void)0) 142 #endif 143 71 144 // Local Variables: // 72 145 // mode: c // -
libcfa/src/bits/defs.hfa
rbdfc032 reef8dfb 10 10 // Created On : Thu Nov 9 13:24:10 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jan 28 22:38:27202013 // Update Count : 912 // Last Modified On : Sat Oct 24 10:53:15 2020 13 // Update Count : 21 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <stdbool.h>19 #include <stddef.h>20 18 #include <stdint.h> 19 #include <assert.h> 21 20 22 21 #define likely(x) __builtin_expect(!!(x), 1) … … 30 29 #define __cfa_anonymous_object(x) inline struct x 31 30 #else 32 #define __cfa_anonymous_object(x) x __cfa_anonymous_object31 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object 33 32 #endif 34 33 … … 49 48 #endif 50 49 51 static inline long long rdtscl(void) { 52 unsigned int lo, hi; 53 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 54 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 50 static inline long long int rdtscl(void) { 51 #if defined( __i386 ) || defined( __x86_64 ) 52 unsigned int lo, hi; 53 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 54 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 55 #elif defined( __aarch64__ ) || defined( __arm__ ) 56 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116 57 long long int virtual_timer_value; 58 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); 59 return virtual_timer_value; 60 #else 61 #error unsupported hardware architecture 62 #endif 55 63 } -
libcfa/src/bits/locks.hfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Oct 31 15:14:38 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 11 15:42:24 201813 // Update Count : 1 012 // Last Modified On : Wed Aug 12 14:18:07 2020 13 // Update Count : 13 14 14 // 15 15 … … 27 27 28 28 // pause to prevent excess processor bus usage 29 #if defined( __sparc ) 30 #define Pause() __asm__ __volatile__ ( "rd %ccr,%g0" ) 31 #elif defined( __i386 ) || defined( __x86_64 ) 29 #if defined( __i386 ) || defined( __x86_64 ) 32 30 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 33 31 #elif defined( __ARM_ARCH ) 34 #define Pause() __asm__ __volatile__ ( " nop" : : : )32 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 35 33 #else 36 34 #error unsupported architecture … … 54 52 55 53 #ifdef __CFA_DEBUG__ 56 void __cfaabi_dbg_record (__spinlock_t & this, const char * prev_name);54 void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]); 57 55 #else 58 #define __cfaabi_dbg_record (x, y)56 #define __cfaabi_dbg_record_lock(x, y) 59 57 #endif 60 58 } 61 62 extern void yield( unsigned int );63 59 64 60 static inline void ?{}( __spinlock_t & this ) { … … 68 64 // Lock the spinlock, return false if already acquired 69 65 static inline bool try_lock ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) { 66 disable_interrupts(); 70 67 bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0); 71 68 if( result ) { 72 disable_interrupts(); 73 __cfaabi_dbg_record( this, caller ); 69 __cfaabi_dbg_record_lock( this, caller ); 70 } else { 71 enable_interrupts_noPoll(); 74 72 } 75 73 return result; … … 83 81 #endif 84 82 83 disable_interrupts(); 85 84 for ( unsigned int i = 1;; i += 1 ) { 86 85 if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break; … … 98 97 #endif 99 98 } 100 disable_interrupts(); 101 __cfaabi_dbg_record( this, caller ); 99 __cfaabi_dbg_record_lock( this, caller ); 102 100 } 103 101 104 102 static inline void unlock( __spinlock_t & this ) { 103 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 105 104 enable_interrupts_noPoll(); 106 __atomic_clear( &this.lock, __ATOMIC_RELEASE );107 105 } 108 106 … … 112 110 #endif 113 111 112 extern "C" { 113 char * strerror(int); 114 } 115 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); } 116 114 117 struct __bin_sem_t { 115 bool signaled;116 118 pthread_mutex_t lock; 117 119 pthread_cond_t cond; 120 int val; 118 121 }; 119 122 120 123 static inline void ?{}(__bin_sem_t & this) with( this ) { 121 signaled = false; 122 pthread_mutex_init(&lock, NULL); 123 pthread_cond_init (&cond, NULL); 124 // Create the mutex with error checking 125 pthread_mutexattr_t mattr; 126 pthread_mutexattr_init( &mattr ); 127 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP); 128 pthread_mutex_init(&lock, &mattr); 129 130 pthread_cond_init (&cond, (const pthread_condattr_t *)0p); // workaround trac#208: cast should not be required 131 val = 0; 124 132 } 125 133 126 134 static inline void ^?{}(__bin_sem_t & this) with( this ) { 127 pthread_mutex_destroy(&lock);128 pthread_cond_destroy (&cond);135 CHECKED( pthread_mutex_destroy(&lock) ); 136 CHECKED( pthread_cond_destroy (&cond) ); 129 137 } 130 138 131 139 static inline void wait(__bin_sem_t & this) with( this ) { 132 140 verify(__cfaabi_dbg_in_kernel()); 133 pthread_mutex_lock(&lock);134 if(!signaled) { // this must be a loop, not if!141 CHECKED( pthread_mutex_lock(&lock) ); 142 while(val < 1) { 135 143 pthread_cond_wait(&cond, &lock); 136 144 } 137 signaled = false; 138 pthread_mutex_unlock(&lock); 139 } 140 141 static inline void post(__bin_sem_t & this) with( this ) { 142 verify(__cfaabi_dbg_in_kernel()); 143 144 pthread_mutex_lock(&lock); 145 bool needs_signal = !signaled; 146 signaled = true; 147 pthread_mutex_unlock(&lock); 148 149 if (needs_signal) 150 pthread_cond_signal(&cond); 145 val -= 1; 146 CHECKED( pthread_mutex_unlock(&lock) ); 147 } 148 149 static inline bool post(__bin_sem_t & this) with( this ) { 150 bool needs_signal = false; 151 152 CHECKED( pthread_mutex_lock(&lock) ); 153 if(val < 1) { 154 val += 1; 155 pthread_cond_signal(&cond); 156 needs_signal = true; 157 } 158 CHECKED( pthread_mutex_unlock(&lock) ); 159 160 return needs_signal; 161 } 162 163 #undef CHECKED 164 165 struct $thread; 166 extern void park( void ); 167 extern void unpark( struct $thread * this ); 168 static inline struct $thread * active_thread (); 169 170 // Semaphore which only supports a single thread 171 struct single_sem { 172 struct $thread * volatile ptr; 173 }; 174 175 static inline { 176 void ?{}(single_sem & this) { 177 this.ptr = 0p; 178 } 179 180 void ^?{}(single_sem &) {} 181 182 bool wait(single_sem & this) { 183 for() { 184 struct $thread * expected = this.ptr; 185 if(expected == 1p) { 186 if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 187 return false; 188 } 189 } 190 else { 191 /* paranoid */ verify( expected == 0p ); 192 if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 193 park(); 194 return true; 195 } 196 } 197 198 } 199 } 200 201 bool post(single_sem & this) { 202 for() { 203 struct $thread * expected = this.ptr; 204 if(expected == 1p) return false; 205 if(expected == 0p) { 206 if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 207 return false; 208 } 209 } 210 else { 211 if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 212 unpark( expected ); 213 return true; 214 } 215 } 216 } 217 } 218 } 219 220 // Synchronozation primitive which only supports a single thread and one post 221 // Similar to a binary semaphore with a 'one shot' semantic 222 // is expected to be discarded after each party call their side 223 struct oneshot { 224 // Internal state : 225 // 0p : is initial state (wait will block) 226 // 1p : fulfilled (wait won't block) 227 // any thread : a thread is currently waiting 228 struct $thread * volatile ptr; 229 }; 230 231 static inline { 232 void ?{}(oneshot & this) { 233 this.ptr = 0p; 234 } 235 236 void ^?{}(oneshot &) {} 237 238 // Wait for the post, return immidiately if it already happened. 239 // return true if the thread was parked 240 bool wait(oneshot & this) { 241 for() { 242 struct $thread * expected = this.ptr; 243 if(expected == 1p) return false; 244 /* paranoid */ verify( expected == 0p ); 245 if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 246 park(); 247 /* paranoid */ verify( this.ptr == 1p ); 248 return true; 249 } 250 } 251 } 252 253 // Mark as fulfilled, wake thread if needed 254 // return true if a thread was unparked 255 bool post(oneshot & this) { 256 struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 257 if( got == 0p ) return false; 258 unpark( got ); 259 return true; 260 } 261 } 262 263 // base types for future to build upon 264 // It is based on the 'oneshot' type to allow multiple futures 265 // to block on the same instance, permitting users to block a single 266 // thread on "any of" [a given set of] futures. 267 // does not support multiple threads waiting on the same future 268 struct future_t { 269 // Internal state : 270 // 0p : is initial state (wait will block) 271 // 1p : fulfilled (wait won't block) 272 // 2p : in progress () 273 // 3p : abandoned, server should delete 274 // any oneshot : a context has been setup to wait, a thread could wait on it 275 struct oneshot * volatile ptr; 276 }; 277 278 static inline { 279 void ?{}(future_t & this) { 280 this.ptr = 0p; 281 } 282 283 void ^?{}(future_t &) {} 284 285 void reset(future_t & this) { 286 // needs to be in 0p or 1p 287 __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST); 288 } 289 290 // check if the future is available 291 bool available( future_t & this ) { 292 return this.ptr == 1p; 293 } 294 295 // Prepare the future to be waited on 296 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly 297 bool setup( future_t & this, oneshot & wait_ctx ) { 298 /* paranoid */ verify( wait_ctx.ptr == 0p ); 299 // The future needs to set the wait context 300 for() { 301 struct oneshot * expected = this.ptr; 302 // Is the future already fulfilled? 303 if(expected == 1p) return false; // Yes, just return false (didn't block) 304 305 // The future is not fulfilled, try to setup the wait context 306 /* paranoid */ verify( expected == 0p ); 307 if(__atomic_compare_exchange_n(&this.ptr, &expected, &wait_ctx, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 308 return true; 309 } 310 } 311 } 312 313 // Stop waiting on a future 314 // When multiple futures are waited for together in "any of" pattern 315 // futures that weren't fulfilled before the thread woke up 316 // should retract the wait ctx 317 // intented to be use by wait, wait_any, waitfor, etc. rather than used directly 318 void retract( future_t & this, oneshot & wait_ctx ) { 319 // Remove the wait context 320 struct oneshot * got = __atomic_exchange_n( &this.ptr, 0p, __ATOMIC_SEQ_CST); 321 322 // got == 0p: future was never actually setup, just return 323 if( got == 0p ) return; 324 325 // got == wait_ctx: since fulfil does an atomic_swap, 326 // if we got back the original then no one else saw context 327 // It is safe to delete (which could happen after the return) 328 if( got == &wait_ctx ) return; 329 330 // got == 1p: the future is ready and the context was fully consumed 331 // the server won't use the pointer again 332 // It is safe to delete (which could happen after the return) 333 if( got == 1p ) return; 334 335 // got == 2p: the future is ready but the context hasn't fully been consumed 336 // spin until it is safe to move on 337 if( got == 2p ) { 338 while( this.ptr != 1p ) Pause(); 339 return; 340 } 341 342 // got == any thing else, something wen't wrong here, abort 343 abort("Future in unexpected state"); 344 } 345 346 // Mark the future as abandoned, meaning it will be deleted by the server 347 bool abandon( future_t & this ) { 348 /* paranoid */ verify( this.ptr != 3p ); 349 350 // Mark the future as abandonned 351 struct oneshot * got = __atomic_exchange_n( &this.ptr, 3p, __ATOMIC_SEQ_CST); 352 353 // If the future isn't already fulfilled, let the server delete it 354 if( got == 0p ) return false; 355 356 // got == 2p: the future is ready but the context hasn't fully been consumed 357 // spin until it is safe to move on 358 if( got == 2p ) { 359 while( this.ptr != 1p ) Pause(); 360 got = 1p; 361 } 362 363 // The future is completed delete it now 364 /* paranoid */ verify( this.ptr != 1p ); 365 free( &this ); 366 return true; 367 } 368 369 // from the server side, mark the future as fulfilled 370 // delete it if needed 371 bool fulfil( future_t & this ) { 372 for() { 373 struct oneshot * expected = this.ptr; 374 // was this abandoned? 375 #if defined(__GNUC__) && __GNUC__ >= 7 376 #pragma GCC diagnostic push 377 #pragma GCC diagnostic ignored "-Wfree-nonheap-object" 378 #endif 379 if( expected == 3p ) { free( &this ); return false; } 380 #if defined(__GNUC__) && __GNUC__ >= 7 381 #pragma GCC diagnostic pop 382 #endif 383 384 /* paranoid */ verify( expected != 1p ); // Future is already fulfilled, should not happen 385 /* paranoid */ verify( expected != 2p ); // Future is bein fulfilled by someone else, this is even less supported then the previous case. 386 387 // If there is a wait context, we need to consume it and mark it as consumed after 388 // If there is no context then we can skip the in progress phase 389 struct oneshot * want = expected == 0p ? 1p : 2p; 390 if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 391 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; } 392 bool ret = post( *expected ); 393 __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 394 return ret; 395 } 396 } 397 398 } 399 400 // Wait for the future to be fulfilled 401 bool wait( future_t & this ) { 402 oneshot temp; 403 if( !setup(this, temp) ) return false; 404 405 // Wait context is setup, just wait on it 406 bool ret = wait( temp ); 407 408 // Wait for the future to tru 409 while( this.ptr == 2p ) Pause(); 410 // Make sure the state makes sense 411 // Should be fulfilled, could be in progress but it's out of date if so 412 // since if that is the case, the oneshot was fulfilled (unparking this thread) 413 // and the oneshot should not be needed any more 414 __attribute__((unused)) struct oneshot * was = this.ptr; 415 /* paranoid */ verifyf( was == 1p, "Expected this.ptr to be 1p, was %p\n", was ); 416 417 // Mark the future as fulfilled, to be consistent 418 // with potential calls to avail 419 // this.ptr = 1p; 420 return ret; 421 } 151 422 } 152 423 #endif -
libcfa/src/bits/signal.hfa
rbdfc032 reef8dfb 19 19 #include "bits/defs.hfa" 20 20 21 extern "C" {22 21 #include <errno.h> 23 22 #define __USE_GNU … … 26 25 #include <stdlib.h> 27 26 #include <string.h> 28 }29 27 30 28 // Short hands for signal context information … … 54 52 sig, handler, flags, errno, strerror( errno ) 55 53 ); 56 _ exit( EXIT_FAILURE );54 _Exit( EXIT_FAILURE ); 57 55 } // if 58 56 }
Note:
See TracChangeset
for help on using the changeset viewer.