Changeset eef8dfb for libcfa/src
- 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
- Files:
-
- 38 added
- 3 deleted
- 56 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
rbdfc032 reef8dfb 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Jul 15 22:43:27 201914 ## Update Count : 2 4113 ## Last Modified On : Wed Dec 9 22:46:14 2020 14 ## Update Count : 250 15 15 ############################################################################### 16 16 … … 19 19 ACLOCAL_AMFLAGS = -I automake 20 20 21 include $( srcdir)/../../src/cfa.make21 include $(top_srcdir)/../tools/build/cfa.make 22 22 23 23 libdir = ${CFA_LIBDIR} … … 31 31 # AM_CFAFLAGS for only cfa source 32 32 # use -no-include-stdhdr to prevent rebuild cycles 33 # The built sources must not depend on the installed headers34 AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@35 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC - pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@33 # The built sources must not depend on the installed inst_headers_src 34 AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr -I$(srcdir)/concurrency $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@ 35 AM_CFLAGS = -g -Wall -Wno-unused-function -fPIC -fexceptions -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@ 36 36 AM_CCASFLAGS = -g -Wall -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@ 37 37 CFACC = @CFACC@ … … 39 39 #---------------------------------------------------------------------------------------------------------------- 40 40 if BUILDLIB 41 headers_nosrc = math.hfa gmp.hfa time_t.hfa bits/align.hfa bits/containers.hfa bits/defs.hfa bits/debug.hfa bits/locks.hfa 42 headers = fstream.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa time.hfa stdlib.hfa common.hfa \ 43 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa \ 44 vec/vec.hfa vec/vec2.hfa vec/vec3.hfa vec/vec4.hfa 45 46 libsrc = startup.cfa interpose.cfa bits/debug.cfa assert.cfa exception.c virtual.c heap.cfa ${headers:.hfa=.cfa} 41 inst_headers_nosrc = \ 42 bitmanip.hfa \ 43 clock.hfa \ 44 exception.hfa \ 45 exception.h \ 46 gmp.hfa \ 47 math.hfa \ 48 time_t.hfa \ 49 bits/align.hfa \ 50 bits/containers.hfa \ 51 bits/debug.hfa \ 52 bits/defs.hfa \ 53 bits/locks.hfa \ 54 bits/collection.hfa \ 55 bits/stack.hfa \ 56 bits/queue.hfa \ 57 bits/sequence.hfa \ 58 concurrency/iofwd.hfa \ 59 containers/list.hfa \ 60 containers/stackLockFree.hfa \ 61 vec/vec.hfa \ 62 vec/vec2.hfa \ 63 vec/vec3.hfa \ 64 vec/vec4.hfa 65 66 inst_headers_src = \ 67 common.hfa \ 68 fstream.hfa \ 69 heap.hfa \ 70 iostream.hfa \ 71 iterator.hfa \ 72 limits.hfa \ 73 memory.hfa \ 74 parseargs.hfa \ 75 rational.hfa \ 76 stdlib.hfa \ 77 time.hfa \ 78 containers/maybe.hfa \ 79 containers/pair.hfa \ 80 containers/result.hfa \ 81 containers/vector.hfa 82 83 libsrc = ${inst_headers_src} ${inst_headers_src:.hfa=.cfa} \ 84 assert.cfa \ 85 bits/algorithm.hfa \ 86 bits/debug.cfa \ 87 exception.c \ 88 interpose.cfa \ 89 lsda.h \ 90 startup.cfa \ 91 startup.hfa \ 92 virtual.c \ 93 virtual.h 47 94 48 95 # not all platforms support concurrency, add option do disable it 49 thread_headers_nosrc = concurrency/invoke.h 50 thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa 51 thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/preemption.cfa ${thread_headers:.hfa=.cfa} 96 inst_thread_headers_nosrc = \ 97 bits/random.hfa \ 98 concurrency/clib/cfathread.h \ 99 concurrency/invoke.h \ 100 concurrency/future.hfa \ 101 concurrency/kernel/fwd.hfa 102 103 inst_thread_headers_src = \ 104 concurrency/coroutine.hfa \ 105 concurrency/exception.hfa \ 106 concurrency/kernel.hfa \ 107 concurrency/locks.hfa \ 108 concurrency/monitor.hfa \ 109 concurrency/mutex.hfa \ 110 concurrency/thread.hfa 111 112 thread_libsrc = ${inst_thread_headers_src} ${inst_thread_headers_src:.hfa=.cfa} \ 113 bits/signal.hfa \ 114 concurrency/alarm.cfa \ 115 concurrency/alarm.hfa \ 116 concurrency/clib/cfathread.cfa \ 117 concurrency/CtxSwitch-@ARCHITECTURE@.S \ 118 concurrency/invoke.c \ 119 concurrency/io.cfa \ 120 concurrency/io/setup.cfa \ 121 concurrency/io/types.hfa \ 122 concurrency/io/call.cfa \ 123 concurrency/iofwd.hfa \ 124 concurrency/kernel_private.hfa \ 125 concurrency/kernel/startup.cfa \ 126 concurrency/preemption.cfa \ 127 concurrency/preemption.hfa \ 128 concurrency/ready_queue.cfa \ 129 concurrency/ready_subqueue.hfa \ 130 concurrency/snzi.hfa \ 131 concurrency/stats.cfa \ 132 concurrency/stats.hfa \ 133 concurrency/stats.hfa 134 52 135 else 53 headers=54 thread_headers=55 headers_nosrc =56 thread_headers_nosrc =136 inst_headers_src = 137 inst_thread_headers_src = 138 inst_headers_nosrc = 139 inst_thread_headers_nosrc = 57 140 libsrc = 58 141 endif … … 97 180 98 181 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 99 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA 182 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@} 100 183 101 184 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 102 185 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 103 $(CFACOMPILE) -quiet -XCFA -l ${<} -c -o ${@} 104 105 #---------------------------------------------------------------------------------------------------------------- 106 libcfa_la_SOURCES = prelude.cfa ${libsrc} 186 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@} 187 188 #---------------------------------------------------------------------------------------------------------------- 189 libcfa_la_SOURCES = ${libsrc} 190 nodist_libcfa_la_SOURCES = prelude.cfa 107 191 libcfa_la_LDFLAGS = -version-info @CFA_VERSION@ 108 192 … … 113 197 114 198 cfa_includedir = $(CFA_INCDIR) 115 nobase_cfa_include_HEADERS = ${stdhdr} ${headers} ${headers_nosrc} ${thread_headers} ${thread_headers_nosrc} 199 nobase_cfa_include_HEADERS = ${stdhdr} ${inst_headers_src} ${inst_headers_nosrc} ${inst_thread_headers_src} ${inst_thread_headers_nosrc} 200 EXTRA_DIST = stdhdr 116 201 117 202 #---------------------------------------------------------------------------------------------------------------- 118 203 maintainer-clean-local: 119 204 -rm -rf ${CFA_INCDIR} ${CFA_LIBDIR} 205 206 distclean-local: 207 find ${builddir} -path '*.Plo' -delete 120 208 121 209 -
libcfa/src/assert.cfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Nov 21 17:09:26 201913 // Update Count : 512 // Last Modified On : Tue Feb 4 13:00:18 2020 13 // Update Count : 6 14 14 // 15 15 … … 26 26 27 27 // called by macro assert in assert.h 28 void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function) {28 void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) { 29 29 __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file ); 30 30 abort(); … … 32 32 33 33 // called by macro assertf 34 void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {34 void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) { 35 35 __cfaabi_bits_acquire(); 36 36 __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file ); -
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 } -
libcfa/src/common.hfa
rbdfc032 reef8dfb 10 10 // Created On : Wed Jul 11 17:54:36 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 12 08:02:18 201813 // Update Count : 512 // Last Modified On : Sat Aug 15 08:51:29 2020 13 // Update Count : 14 14 14 // 15 15 … … 67 67 68 68 static inline { 69 char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization 70 intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization 71 uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization 69 72 forall( otype T | { int ?<?( T, T ); } ) 70 73 T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; } 71 74 75 char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization 76 intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization 77 uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization 72 78 forall( otype T | { int ?>?( T, T ); } ) 73 79 T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; } -
libcfa/src/concurrency/CtxSwitch-i386.S
rbdfc032 reef8dfb 10 10 // Created On : Tue Dec 6 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:29:25 2017 13 // Update Count : 1 14 // 15 // This library is free software; you can redistribute it and/or modify it 16 // under the terms of the GNU Lesser General Public License as published by the 17 // Free Software Foundation; either version 2.1 of the License, or (at your 18 // option) any later version. 19 // 20 // This library is distributed in the hope that it will be useful, but WITHOUT 21 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 22 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 23 // for more details. 24 // 25 // You should have received a copy of the GNU Lesser General Public License 26 // along with this library. 12 // Last Modified On : Sun Sep 6 18:23:37 2020 13 // Update Count : 5 27 14 // 28 15 29 // This context switch routine depends on the fact that the stack of a new 30 // thread has been set up to look like the thread has saved its context in 31 // the normal manner. 32 // 33 // void CtxSwitch( machine_context *from, machine_context *to ); 16 // The context switch routine requires the initial the stack of a thread to 17 // look like the thread has saved its context in the normal manner. 34 18 35 // Offsets in the context structure. This needs to be synchronized with the 36 // high level code a little better. 19 // Offsets must synchronized with the __stack_context_t in invoke.h. 37 20 38 21 #define PTR_BYTE 4 39 22 #define SP_OFFSET ( 0 * PTR_BYTE ) 40 23 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 #define PC_OFFSET ( 2 * PTR_BYTE )42 24 25 // Context switch between coroutines/tasks. 26 // void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) ; 27 // Arguments "from" in register 4(%esp), "to" in register 20(%esp) 28 29 .file "CtxSwitch-i386.S" 43 30 .text 44 31 .align 2 45 .glob l CtxSwitch46 .type CtxSwitch, @function47 CtxSwitch:32 .global __cfactx_switch 33 .type __cfactx_switch, @function 34 __cfactx_switch: 48 35 49 36 // Copy the "from" context argument from the stack to register eax 50 // Return address is at 0(%esp), with parameters following 37 // Return address is at 0(%esp), with parameters following. 51 38 52 39 movl 4(%esp),%eax … … 63 50 movl %ebp,FP_OFFSET(%eax) 64 51 65 // Copy the "to" context argument from the stack to register eax 66 // Having pushed three words (= 12 bytes) on the stack, the67 // argument is now at 8 + 12 = 20(%esp)52 // Copy the "to" context argument from the stack to register eax. Having 53 // pushed 3 words (= 12 bytes) on the stack, the argument is now at 54 // 8 + 12 = 20(%esp). 68 55 69 56 movl 20(%esp),%eax … … 83 70 84 71 ret 85 .size CtxSwitch, .-CtxSwitch72 .size __cfactx_switch, .-__cfactx_switch 86 73 87 74 // Local Variables: // -
libcfa/src/concurrency/CtxSwitch-x86_64.S
rbdfc032 reef8dfb 7 7 // CtxSwitch-x86_64.S -- 8 8 // 9 // Author : Thierry Delisle10 // Created On : Mon Nov 28 12:27:26 20169 // Author : Peter A. Buhr 10 // Created On : Mon Aug 10 08:10:26 2020 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:28:11 2017 13 // Update Count : 1 14 // 15 // This library is free software; you can redistribute it and/or modify it 16 // under the terms of the GNU Lesser General Public License as published by the 17 // Free Software Foundation; either version 2.1 of the License, or (at your 18 // option) any later version. 19 // 20 // This library is distributed in the hope that it will be useful, but WITHOUT 21 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 22 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 23 // for more details. 24 // 25 // You should have received a copy of the GNU Lesser General Public License 26 // along with this library. 12 // Last Modified On : Sat Oct 24 14:36:25 2020 13 // Update Count : 10 27 14 // 28 15 29 // This context switch routine depends on the fact that the stack of a new 30 // thread has been set up to look like the thread has saved its context in 31 // the normal manner. 32 // 33 // void CtxSwitch( machine_context *from, machine_context *to ); 16 // The context switch routine requires the initial the stack of a thread to 17 // look like the thread has saved its context in the normal manner. 34 18 35 // Offsets in the context structure. This needs to be synchronized with the 36 // high level code a little better. 19 // Offsets must synchronized with the __stack_context_t in invoke.h. 37 20 38 21 #define PTR_BYTE 8 … … 40 23 #define FP_OFFSET ( 1 * PTR_BYTE ) 41 24 42 //----------------------------------------------------------------------------- 43 // Regular context switch routine which enables switching from one context to anouther 25 // Context switch between coroutines/tasks. 26 // void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) ; 27 // Arguments "from" in register rdi, "to" in register rsi. 28 29 .file "CtxSwitch-x86_64.S" 44 30 .text 45 31 .align 2 46 .glob l CtxSwitch47 .type CtxSwitch, @function48 CtxSwitch:32 .global __cfactx_switch 33 .type __cfactx_switch, @function 34 __cfactx_switch: 49 35 50 36 // Save volatile registers on the stack. … … 77 63 78 64 ret 79 .size CtxSwitch, .-CtxSwitch65 .size __cfactx_switch, .-__cfactx_switch 80 66 81 //----------------------------------------------------------------------------- 82 // Stub used to create new stacks which are ready to be context switched to 67 // Stub to create new stacks which can be context switched to 68 // void __cfactx_invoke_stub( void ); 69 83 70 .text 84 71 .align 2 85 .glob l CtxInvokeStub86 .type CtxInvokeStub, @function87 CtxInvokeStub:88 movq %rbx, %rdi 72 .global __cfactx_invoke_stub 73 .type __cfactx_invoke_stub, @function 74 __cfactx_invoke_stub: 75 movq %rbx, %rdi // move main and this to first two arguments 89 76 movq %r12, %rsi 90 jmp *%r13 91 .size CtxInvokeStub, .-CtxInvokeStub77 jmp *%r13 // jmp to invoke 78 .size __cfactx_invoke_stub, .-__cfactx_invoke_stub 92 79 93 80 // Local Variables: // 94 // mode: c//81 // mode: asm // 95 82 // tab-width: 4 // 96 83 // End: // -
libcfa/src/concurrency/alarm.cfa
rbdfc032 reef8dfb 10 10 // Created On : Fri Jun 2 11:31:25 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 5 08:41:36202013 // Update Count : 6912 // Last Modified On : Wed Jun 17 16:11:35 2020 13 // Update Count : 75 14 14 // 15 15 16 16 #define __cforall_thread__ 17 17 18 extern "C" {19 18 #include <errno.h> 20 19 #include <stdio.h> 20 #include <unistd.h> 21 21 #include <string.h> 22 #include <unistd.h>23 22 #include <sys/time.h> 24 }25 23 26 24 #include "alarm.hfa" 27 #include "kernel _private.hfa"25 #include "kernel/fwd.hfa" 28 26 #include "preemption.hfa" 29 27 … … 47 45 //============================================================================================= 48 46 49 void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period) with( this ) {47 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period) with( this ) { 50 48 this.thrd = thrd; 51 49 this.alarm = alarm; 52 50 this.period = period; 53 next = 0;54 51 set = false; 55 kernel_alarm = false;52 type = User; 56 53 } 57 54 58 void ?{}( alarm_node_t & this, processor 55 void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ) with( this ) { 59 56 this.proc = proc; 60 57 this.alarm = alarm; 61 58 this.period = period; 62 next = 0;63 59 set = false; 64 kernel_alarm = true; 60 type = Kernel; 61 } 62 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ) with( this ) { 63 this.alarm = alarm; 64 this.period = period; 65 this.callback = callback; 66 set = false; 67 type = Callback; 65 68 } 66 69 … … 71 74 } 72 75 73 #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__)) 74 bool validate( alarm_list_t * this ) { 75 alarm_node_t ** it = &this->head; 76 while( (*it) ) { 77 it = &(*it)->next; 76 void insert( alarm_list_t * this, alarm_node_t * n ) { 77 alarm_node_t * it = & (*this)`first; 78 while( it && (n->alarm > it->alarm) ) { 79 it = & (*it)`next; 80 } 81 if ( it ) { 82 insert_before( *it, *n ); 83 } else { 84 insert_last(*this, *n); 78 85 } 79 86 80 return it == this->tail; 81 } 82 #endif 83 84 static inline void insert_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t p ) { 85 verify( !n->next ); 86 if( p == this->tail ) { 87 this->tail = &n->next; 88 } 89 else { 90 n->next = *p; 91 } 92 *p = n; 93 94 verify( validate( this ) ); 95 } 96 97 void insert( alarm_list_t * this, alarm_node_t * n ) { 98 alarm_node_t ** it = &this->head; 99 while( (*it) && (n->alarm > (*it)->alarm) ) { 100 it = &(*it)->next; 101 } 102 103 insert_at( this, n, it ); 104 105 verify( validate( this ) ); 87 verify( validate( *this ) ); 106 88 } 107 89 108 90 alarm_node_t * pop( alarm_list_t * this ) { 109 alarm_node_t * head = this->head; 91 verify( validate( *this ) ); 92 alarm_node_t * head = & (*this)`first; 110 93 if( head ) { 111 this->head = head->next; 112 if( !head->next ) { 113 this->tail = &this->head; 114 } 115 head->next = 0p; 94 remove(*head); 116 95 } 117 verify( validate( this ) );96 verify( validate( *this ) ); 118 97 return head; 119 98 } 120 99 121 static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) {122 verify( it );123 verify( (*it) == n );124 125 (*it) = n->next;126 if( !n-> next ) {127 this->tail = it;128 }129 n->next = 0p;130 131 verify( validate( this ) );132 }133 134 static inline void remove( alarm_list_t * this, alarm_node_t * n ) {135 alarm_node_t ** it = &this->head;136 while( (*it) && (*it) != n ) {137 it = &(*it)->next;138 }139 140 verify( validate( this ) );141 142 if( *it ) { remove_at( this, n, it ); }143 144 verify( validate( this ) );145 }146 147 100 void register_self( alarm_node_t * this ) { 148 alarm_list_t * alarms = &event_kernel->alarms;101 alarm_list_t & alarms = event_kernel->alarms; 149 102 150 103 disable_interrupts(); … … 152 105 { 153 106 verify( validate( alarms ) ); 154 bool first = ! alarms->head;107 bool first = ! & alarms`first; 155 108 156 insert( alarms, this );109 insert( &alarms, this ); 157 110 if( first ) { 158 __kernel_set_timer( alarms ->head->alarm - __kernel_get_time() );111 __kernel_set_timer( alarms`first.alarm - __kernel_get_time() ); 159 112 } 160 113 } … … 168 121 lock( event_kernel->lock __cfaabi_dbg_ctx2 ); 169 122 { 170 verify( validate( &event_kernel->alarms ) );171 remove( &event_kernel->alarms,this );123 verify( validate( event_kernel->alarms ) ); 124 remove( *this ); 172 125 } 173 126 unlock( event_kernel->lock ); … … 176 129 } 177 130 131 //============================================================================================= 132 // Utilities 133 //============================================================================================= 134 135 void sleep( Duration duration ) { 136 alarm_node_t node = { active_thread(), __kernel_get_time() + duration, 0`s }; 137 138 register_self( &node ); 139 park(); 140 141 /* paranoid */ verify( !node.set ); 142 /* paranoid */ verify( & node`next == 0p ); 143 /* paranoid */ verify( & node`prev == 0p ); 144 } 145 178 146 // Local Variables: // 179 147 // mode: c // -
libcfa/src/concurrency/alarm.hfa
rbdfc032 reef8dfb 23 23 #include "time.hfa" 24 24 25 struct thread_desc; 25 #include "containers/list.hfa" 26 27 struct $thread; 26 28 struct processor; 27 29 … … 37 39 //============================================================================================= 38 40 41 enum alarm_type{ Kernel = 0, User = 1, Callback = 2 }; 42 43 struct alarm_node_t; 44 45 typedef void (*Alarm_Callback)(alarm_node_t & ); 46 39 47 struct alarm_node_t { 40 48 Time alarm; // time when alarm goes off 41 49 Duration period; // if > 0 => period of alarm 42 alarm_node_t * next; // intrusive link list field 50 51 DLISTED_MGD_IMPL_IN(alarm_node_t) 43 52 44 53 union { 45 thread_desc * thrd; // thrd who created event 46 processor * proc; // proc who created event 54 $thread * thrd; // thrd who created event 55 processor * proc; // proc who created event 56 Alarm_Callback callback; // callback to handle event 47 57 }; 48 58 49 59 bool set :1; // whether or not the alarm has be registered 50 bool kernel_alarm :1; // true if this is not a user defined alarm60 enum alarm_type type; // true if this is not a user defined alarm 51 61 }; 62 DLISTED_MGD_IMPL_OUT(alarm_node_t) 52 63 53 typedef alarm_node_t ** __alarm_it_t; 54 55 void ?{}( alarm_node_t & this, thread_desc * thrd, Time alarm, Duration period ); 64 void ?{}( alarm_node_t & this, $thread * thrd, Time alarm, Duration period ); 56 65 void ?{}( alarm_node_t & this, processor * proc, Time alarm, Duration period ); 66 void ?{}( alarm_node_t & this, Alarm_Callback callback, Time alarm, Duration period ); 57 67 void ^?{}( alarm_node_t & this ); 58 68 59 struct alarm_list_t { 60 alarm_node_t * head; 61 __alarm_it_t tail; 62 }; 63 64 static inline void ?{}( alarm_list_t & this ) with( this ) { 65 head = 0; 66 tail = &head; 67 } 69 typedef dlist(alarm_node_t, alarm_node_t) alarm_list_t; 68 70 69 71 void insert( alarm_list_t * this, alarm_node_t * n ); -
libcfa/src/concurrency/coroutine.cfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Dec 5 14:37:29 201913 // Update Count : 1512 // Last Modified On : Tue Dec 15 12:06:04 2020 13 // Update Count : 23 14 14 // 15 15 … … 18 18 #include "coroutine.hfa" 19 19 20 extern "C" {21 20 #include <stddef.h> 22 21 #include <malloc.h> … … 24 23 #include <string.h> 25 24 #include <unistd.h> 26 // use this define to make unwind.h play nice, definetely a hack 27 #define HIDE_EXPORTS 25 #include <sys/mman.h> // mprotect 28 26 #include <unwind.h> 29 #undef HIDE_EXPORTS30 #include <sys/mman.h>31 }32 27 33 28 #include "kernel_private.hfa" 29 #include "exception.hfa" 30 #include "math.hfa" 31 32 #define CFA_COROUTINE_USE_MMAP 0 34 33 35 34 #define __CFA_INVOKE_PRIVATE__ … … 37 36 38 37 extern "C" { 39 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc*) __attribute__ ((__noreturn__));38 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__)); 40 39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__)); 41 40 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) { … … 47 46 48 47 //----------------------------------------------------------------------------- 48 FORALL_DATA_INSTANCE(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) 49 50 forall(dtype T) 51 void mark_exception(CoroutineCancelled(T) *) {} 52 53 forall(dtype T) 54 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { 55 dst->virtual_table = src->virtual_table; 56 dst->the_coroutine = src->the_coroutine; 57 dst->the_exception = src->the_exception; 58 } 59 60 forall(dtype T) 61 const char * msg(CoroutineCancelled(T) *) { 62 return "CoroutineCancelled(...)"; 63 } 64 65 // This code should not be inlined. It is the error path on resume. 66 forall(dtype T | is_coroutine(T)) 67 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) { 68 verify( desc->cancellation ); 69 desc->state = Cancelled; 70 exception_t * except = __cfaehm_cancellation_exception( desc->cancellation ); 71 72 // TODO: Remove explitate vtable set once trac#186 is fixed. 73 CoroutineCancelled(T) except; 74 except.virtual_table = &get_exception_vtable(&except); 75 except.the_coroutine = &cor; 76 except.the_exception = except; 77 throwResume except; 78 79 except->virtual_table->free( except ); 80 free( desc->cancellation ); 81 desc->cancellation = 0p; 82 } 83 84 //----------------------------------------------------------------------------- 49 85 // Global state variables 50 86 51 87 // minimum feasible stack size in bytes 52 #define MinStackSize 1000 88 static const size_t MinStackSize = 1000; 53 89 extern size_t __page_size; // architecture pagesize HACK, should go in proper runtime singleton 90 extern int __map_prot; 54 91 55 92 void __stack_prepare( __stack_info_t * this, size_t create_size ); 93 void __stack_clean ( __stack_info_t * this ); 56 94 57 95 //----------------------------------------------------------------------------- … … 74 112 bool userStack = ((intptr_t)this.storage & 0x1) != 0; 75 113 if ( ! userStack && this.storage ) { 76 __attribute__((may_alias)) intptr_t * istorage = (intptr_t *)&this.storage; 77 *istorage &= (intptr_t)-1; 78 79 void * storage = this.storage->limit; 80 __cfaabi_dbg_debug_do( 81 storage = (char*)(storage) - __page_size; 82 if ( mprotect( storage, __page_size, PROT_READ | PROT_WRITE ) == -1 ) { 83 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 84 } 85 ); 86 __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage); 87 free( storage ); 88 } 89 } 90 91 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) { 114 __stack_clean( &this ); 115 } 116 } 117 118 void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize ) with( this ) { 92 119 (this.context){0p, 0p}; 93 120 (this.stack){storage, storageSize}; … … 99 126 } 100 127 101 void ^?{}( coroutine_desc& this) {128 void ^?{}($coroutine& this) { 102 129 if(this.state != Halted && this.state != Start && this.state != Primed) { 103 coroutine_desc * src = TL_GET( this_thread )->curr_cor;104 coroutine_desc* dst = &this;130 $coroutine * src = active_coroutine(); 131 $coroutine * dst = &this; 105 132 106 133 struct _Unwind_Exception storage; … … 115 142 } 116 143 117 CoroutineCtxSwitch( src, dst );144 $ctx_switch( src, dst ); 118 145 } 119 146 } … … 123 150 forall(dtype T | is_coroutine(T)) 124 151 void prime(T& cor) { 125 coroutine_desc* this = get_coroutine(cor);152 $coroutine* this = get_coroutine(cor); 126 153 assert(this->state == Start); 127 154 … … 134 161 assert(__page_size != 0l); 135 162 size_t size = libCeiling( storageSize, 16 ) + stack_data_size; 163 size = ceiling(size, __page_size); 136 164 137 165 // If we are running debug, we also need to allocate a guardpage to catch stack overflows. 138 166 void * storage; 139 __cfaabi_dbg_debug_do( 140 storage = memalign( __page_size, size + __page_size ); 141 ); 142 __cfaabi_dbg_no_debug_do( 143 storage = (void*)malloc(size); 144 ); 145 167 #if CFA_COROUTINE_USE_MMAP 168 storage = mmap(0p, size + __page_size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 169 if(storage == ((void*)-1)) { 170 abort( "coroutine stack creation : internal error, mmap failure, error(%d) %s.", errno, strerror( errno ) ); 171 } 172 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) { 173 abort( "coroutine stack creation : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) ); 174 } // if 175 storage = (void *)(((intptr_t)storage) + __page_size); 176 #else 177 __cfaabi_dbg_debug_do( 178 storage = memalign( __page_size, size + __page_size ); 179 ); 180 __cfaabi_dbg_no_debug_do( 181 storage = (void*)malloc(size); 182 ); 183 184 __cfaabi_dbg_debug_do( 185 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) { 186 abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 187 } 188 storage = (void *)(((intptr_t)storage) + __page_size); 189 ); 190 #endif 146 191 __cfaabi_dbg_print_safe("Kernel : Created stack %p of size %zu\n", storage, size); 147 __cfaabi_dbg_debug_do(148 if ( mprotect( storage, __page_size, PROT_NONE ) == -1 ) {149 abort( "__stack_alloc : internal error, mprotect failure, error(%d) %s.", (int)errno, strerror( (int)errno ) );150 }151 storage = (void *)(((intptr_t)storage) + __page_size);152 );153 192 154 193 verify( ((intptr_t)storage & (libAlign() - 1)) == 0ul ); 155 194 return [storage, size]; 195 } 196 197 void __stack_clean ( __stack_info_t * this ) { 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t); 199 void * storage = this->storage->limit; 200 201 #if CFA_COROUTINE_USE_MMAP 202 storage = (void *)(((intptr_t)storage) - __page_size); 203 if(munmap(storage, size + __page_size) == -1) { 204 abort( "coroutine stack destruction : internal error, munmap failure, error(%d) %s.", errno, strerror( errno ) ); 205 } 206 #else 207 __cfaabi_dbg_debug_do( 208 storage = (char*)(storage) - __page_size; 209 if ( mprotect( storage, __page_size, __map_prot ) == -1 ) { 210 abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) ); 211 } 212 ); 213 214 free( storage ); 215 #endif 216 __cfaabi_dbg_print_safe("Kernel : Deleting stack %p\n", storage); 156 217 } 157 218 … … 175 236 size = libFloor(create_size - stack_data_size - diff, libAlign()); 176 237 } // if 177 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of % d bytes for a stack.", size, MinStackSize );178 179 this->storage = (__stack_t *)((intptr_t)storage + size );238 assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %zd bytes for a stack.", size, MinStackSize ); 239 240 this->storage = (__stack_t *)((intptr_t)storage + size - sizeof(__stack_t)); 180 241 this->storage->limit = storage; 181 this->storage->base = (void*)((intptr_t)storage + size); 242 this->storage->base = (void*)((intptr_t)storage + size - sizeof(__stack_t)); 243 this->storage->exception_context.top_resume = 0p; 244 this->storage->exception_context.current_exception = 0p; 182 245 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage; 183 246 *istorage |= userStack ? 0x1 : 0x0; … … 187 250 // is not inline (We can't inline Cforall in C) 188 251 extern "C" { 189 void __ leave_coroutine( struct coroutine_desc* src ) {190 coroutine_desc* starter = src->cancellation != 0 ? src->last : src->starter;252 void __cfactx_cor_leave( struct $coroutine * src ) { 253 $coroutine * starter = src->cancellation != 0 ? src->last : src->starter; 191 254 192 255 src->state = Halted; … … 201 264 src->name, src, starter->name, starter ); 202 265 203 CoroutineCtxSwitch( src, starter );204 } 205 206 struct coroutine_desc * __finish_coroutine(void) {207 struct coroutine_desc * cor = kernelTLS.this_thread->curr_cor;266 $ctx_switch( src, starter ); 267 } 268 269 struct $coroutine * __cfactx_cor_finish(void) { 270 struct $coroutine * cor = active_coroutine(); 208 271 209 272 if(cor->state == Primed) { 210 suspend();273 __cfactx_suspend(); 211 274 } 212 275 -
libcfa/src/concurrency/coroutine.hfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 3 22:47:58 201913 // Update Count : 1 012 // Last Modified On : Tue Feb 4 12:29:26 2020 13 // Update Count : 11 14 14 // 15 15 … … 18 18 #include <assert.h> 19 19 #include "invoke.h" 20 #include "../exception.hfa" 21 22 //----------------------------------------------------------------------------- 23 // Exception thrown from resume when a coroutine stack is cancelled. 24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) ( 25 coroutine_t * the_coroutine; 26 exception_t * the_exception; 27 ); 28 29 forall(dtype T) 30 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src); 31 32 forall(dtype T) 33 const char * msg(CoroutineCancelled(T) *); 20 34 21 35 //----------------------------------------------------------------------------- … … 23 37 // Anything that implements this trait can be resumed. 24 38 // Anything that is resumed is a coroutine. 25 trait is_coroutine(dtype T ) {26 27 coroutine_desc* get_coroutine(T & this);39 trait is_coroutine(dtype T | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) { 40 void main(T & this); 41 $coroutine * get_coroutine(T & this); 28 42 }; 29 43 30 #define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)44 #define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this) 31 45 32 46 //----------------------------------------------------------------------------- … … 35 49 // void ^?{}( coStack_t & this ); 36 50 37 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );38 void ^?{}( coroutine_desc& this );51 void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize ); 52 void ^?{}( $coroutine & this ); 39 53 40 static inline void ?{}( coroutine_desc& this) { this{ "Anonymous Coroutine", 0p, 0 }; }41 static inline void ?{}( coroutine_desc& this, size_t stackSize) { this{ "Anonymous Coroutine", 0p, stackSize }; }42 static inline void ?{}( coroutine_desc& this, void * storage, size_t storageSize ) { this{ "Anonymous Coroutine", storage, storageSize }; }43 static inline void ?{}( coroutine_desc & this, const char * name) { this{ name, 0p, 0 }; }44 static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, 0p, stackSize }; }54 static inline void ?{}( $coroutine & this) { this{ "Anonymous Coroutine", 0p, 0 }; } 55 static inline void ?{}( $coroutine & this, size_t stackSize) { this{ "Anonymous Coroutine", 0p, stackSize }; } 56 static inline void ?{}( $coroutine & this, void * storage, size_t storageSize ) { this{ "Anonymous Coroutine", storage, storageSize }; } 57 static inline void ?{}( $coroutine & this, const char name[]) { this{ name, 0p, 0 }; } 58 static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; } 45 59 46 60 //----------------------------------------------------------------------------- 47 61 // Public coroutine API 48 static inline void suspend(void);49 50 forall(dtype T | is_coroutine(T))51 static inline T & resume(T & cor);52 53 62 forall(dtype T | is_coroutine(T)) 54 63 void prime(T & cor); 55 64 56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread)->curr_cor; }65 static inline struct $coroutine * active_coroutine() { return active_thread()->curr_cor; } 57 66 58 67 //----------------------------------------------------------------------------- … … 61 70 // Start coroutine routines 62 71 extern "C" { 63 void CtxInvokeCoroutine(void (*main)(void *), void * this);72 void __cfactx_invoke_coroutine(void (*main)(void *), void * this); 64 73 65 74 forall(dtype T) 66 void CtxStart(void (*main)(T &), struct coroutine_desc* cor, T & this, void (*invoke)(void (*main)(void *), void *));75 void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *)); 67 76 68 extern void _ CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc*) __attribute__ ((__noreturn__));77 extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__)); 69 78 70 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");79 extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch"); 71 80 } 72 81 73 82 // Private wrappers for context switch and stack creation 74 83 // Wrapper for co 75 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {84 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) { 76 85 // set state of current coroutine to inactive 77 src->state = src->state == Halted ? Halted : Inactive;86 src->state = src->state == Halted ? Halted : Blocked; 78 87 79 88 // set new coroutine that task is executing 80 TL_GET( this_thread)->curr_cor = dst;89 active_thread()->curr_cor = dst; 81 90 82 91 // context switch to specified coroutine 83 92 verify( dst->context.SP ); 84 CtxSwitch( &src->context, &dst->context );85 // when CtxSwitch returns we are back in the src coroutine93 __cfactx_switch( &src->context, &dst->context ); 94 // when __cfactx_switch returns we are back in the src coroutine 86 95 87 96 // set state of new coroutine to active … … 89 98 90 99 if( unlikely(src->cancellation != 0p) ) { 91 _ CtxCoroutine_Unwind(src->cancellation, src);100 __cfactx_coroutine_unwind(src->cancellation, src); 92 101 } 93 102 } 94 103 95 extern void __stack_prepare ( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 104 extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 105 extern void __stack_clean ( __stack_info_t * this ); 106 96 107 97 108 // Suspend implementation inlined for performance 98 static inline void suspend(void) { 99 // optimization : read TLS once and reuse it 100 // Safety note: this is preemption safe since if 101 // preemption occurs after this line, the pointer 102 // will also migrate which means this value will 103 // stay in syn with the TLS 104 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 109 extern "C" { 110 static inline void __cfactx_suspend(void) { 111 // optimization : read TLS once and reuse it 112 // Safety note: this is preemption safe since if 113 // preemption occurs after this line, the pointer 114 // will also migrate which means this value will 115 // stay in syn with the TLS 116 $coroutine * src = active_coroutine(); 105 117 106 assertf( src->last != 0,107 "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"108 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",109 src->name, src );110 assertf( src->last->state != Halted,111 "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"112 "Possible cause is terminated coroutine's main routine has already returned.",113 src->name, src, src->last->name, src->last );118 assertf( src->last != 0, 119 "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n" 120 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 121 src->name, src ); 122 assertf( src->last->state != Halted, 123 "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n" 124 "Possible cause is terminated coroutine's main routine has already returned.", 125 src->name, src, src->last->name, src->last ); 114 126 115 CoroutineCtxSwitch( src, src->last ); 127 $ctx_switch( src, src->last ); 128 } 116 129 } 130 131 forall(dtype T | is_coroutine(T)) 132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ); 117 133 118 134 // Resume implementation inlined for performance … … 124 140 // will also migrate which means this value will 125 141 // stay in syn with the TLS 126 coroutine_desc * src = TL_GET( this_thread )->curr_cor;127 coroutine_desc* dst = get_coroutine(cor);142 $coroutine * src = active_coroutine(); 143 $coroutine * dst = get_coroutine(cor); 128 144 129 145 if( unlikely(dst->context.SP == 0p) ) { 130 TL_GET( this_thread )->curr_cor = dst;131 146 __stack_prepare(&dst->stack, 65000); 132 CtxStart(main, dst, cor, CtxInvokeCoroutine); 133 TL_GET( this_thread )->curr_cor = src; 147 __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine); 134 148 } 135 149 … … 147 161 148 162 // always done for performance testing 149 CoroutineCtxSwitch( src, dst ); 163 $ctx_switch( src, dst ); 164 if ( unlikely(dst->cancellation) ) { 165 __cfaehm_cancelled_coroutine( cor, dst ); 166 } 150 167 151 168 return cor; 152 169 } 153 170 154 static inline void resume( coroutine_desc * dst) {171 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) { 155 172 // optimization : read TLS once and reuse it 156 173 // Safety note: this is preemption safe since if … … 158 175 // will also migrate which means this value will 159 176 // stay in syn with the TLS 160 coroutine_desc * src = TL_GET( this_thread )->curr_cor;177 $coroutine * src = active_coroutine(); 161 178 162 179 // not resuming self ? … … 172 189 173 190 // always done for performance testing 174 CoroutineCtxSwitch( src, dst );191 $ctx_switch( src, dst ); 175 192 } 176 193 -
libcfa/src/concurrency/invoke.c
rbdfc032 reef8dfb 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Feb 9 16:37:42 201813 // Update Count : 512 // Last Modified On : Sat Oct 24 14:35:28 2020 13 // Update Count : 32 14 14 // 15 15 … … 29 29 // Called from the kernel when starting a coroutine or task so must switch back to user mode. 30 30 31 extern void __leave_coroutine ( struct coroutine_desc * ); 32 extern struct coroutine_desc * __finish_coroutine(void); 33 extern void __leave_thread_monitor(); 31 extern struct $coroutine * __cfactx_cor_finish(void); 32 extern void __cfactx_cor_leave ( struct $coroutine * ); 33 extern void __cfactx_thrd_leave(); 34 34 35 extern void disable_interrupts() OPTIONAL_THREAD; 35 36 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 36 37 37 void CtxInvokeCoroutine(38 void __cfactx_invoke_coroutine( 38 39 void (*main)(void *), 39 40 void *this 40 41 ) { 41 42 // Finish setting up the coroutine by setting its state 42 struct coroutine_desc * cor = __finish_coroutine();43 struct $coroutine * cor = __cfactx_cor_finish(); 43 44 44 45 // Call the main of the coroutine … … 46 47 47 48 //Final suspend, should never return 48 __ leave_coroutine( cor );49 __cfactx_cor_leave( cor ); 49 50 __cabi_abort( "Resumed dead coroutine" ); 50 51 } 51 52 52 static _Unwind_Reason_Code _ CtxCoroutine_UnwindStop(53 static _Unwind_Reason_Code __cfactx_coroutine_unwindstop( 53 54 __attribute((__unused__)) int version, 54 55 _Unwind_Action actions, … … 61 62 // We finished unwinding the coroutine, 62 63 // leave it 63 __ leave_coroutine( param );64 __cfactx_cor_leave( param ); 64 65 __cabi_abort( "Resumed dead coroutine" ); 65 66 } … … 69 70 } 70 71 71 void _ CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc* cor) __attribute__ ((__noreturn__));72 void _ CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc* cor) {73 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _ CtxCoroutine_UnwindStop, cor );72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) __attribute__ ((__noreturn__)); 73 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine * cor) { 74 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor ); 74 75 printf("UNWIND ERROR %d after force unwind\n", ret); 75 76 abort(); 76 77 } 77 78 78 void CtxInvokeThread(79 void __cfactx_invoke_thread( 79 80 void (*main)(void *), 80 81 void *this … … 93 94 // The order of these 4 operations is very important 94 95 //Final suspend, should never return 95 __ leave_thread_monitor();96 __cfactx_thrd_leave(); 96 97 __cabi_abort( "Resumed dead thread" ); 97 98 } 98 99 99 void CtxStart(100 void __cfactx_start( 100 101 void (*main)(void *), 101 struct coroutine_desc* cor,102 struct $coroutine * cor, 102 103 void *this, 103 104 void (*invoke)(void *) … … 108 109 109 110 struct FakeStack { 110 void *fixedRegisters[3]; 111 void *rturn; 112 void *dummyReturn; 113 void *argument[3]; 114 void *padding; 111 void *fixedRegisters[3]; // fixed registers ebx, edi, esi (popped on 1st uSwitch, values unimportant) 112 void *rturn; // where to go on return from uSwitch 113 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke 114 void *argument[3]; // for 16-byte ABI, 16-byte alignment starts here 115 void *padding; // padding to force 16-byte alignment, as "base" is 16-byte aligned 115 116 }; 116 117 … … 121 122 122 123 fs->dummyReturn = NULL; 123 fs->argument[0] = main; 124 fs->argument[1] = this; 124 fs->argument[0] = main; // argument to invoke 125 fs->argument[1] = this; // argument to invoke 125 126 fs->rturn = invoke; 126 127 … … 128 129 129 130 struct FakeStack { 130 void *fixedRegisters[5]; 131 void *rturn; 132 void *dummyReturn; 131 void *fixedRegisters[5]; // fixed registers rbx, r12, r13, r14, r15 132 void *rturn; // where to go on return from uSwitch 133 void *dummyReturn; // NULL return address to provide proper alignment 133 134 }; 134 135 135 136 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 136 cor->context.FP = NULL; // terminate stack with NULL fp137 cor->context.FP = NULL; // terminate stack with NULL fp 137 138 138 139 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 139 140 140 141 fs->dummyReturn = NULL; 141 fs->rturn = CtxInvokeStub;142 fs->fixedRegisters[0] = main; 143 fs->fixedRegisters[1] = this; 142 fs->rturn = __cfactx_invoke_stub; 143 fs->fixedRegisters[0] = main; // argument to invoke 144 fs->fixedRegisters[1] = this; // argument to invoke 144 145 fs->fixedRegisters[2] = invoke; 145 146 146 #elif defined( __ARM_ARCH ) 147 #error ARM needs to be upgrade to use to parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it) 147 #elif defined( __ARM_ARCH_32 ) 148 #error ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it) 149 // More details about the error: 150 // To avoid the thunk problem, I changed the invoke routine to pass the main explicitly 151 // instead of relying on an assertion. This effectively hoists any required thunk one level 152 // which was enough to get to global scope in most cases. 153 // This means that __cfactx_invoke_... now takes two parameters and the FakeStack needs 154 // to be adjusted as a consequence of that. 155 // I don't know how to do that for ARM, hence the #error 156 148 157 struct FakeStack { 149 float fpRegs[16]; // floating point registers150 void * intRegs[9];// integer/pointer registers151 void * arg[2];// placeholder for this pointer158 float fpRegs[16]; // floating point registers 159 void * intRegs[9]; // integer/pointer registers 160 void * arg[2]; // placeholder for this pointer 152 161 }; 153 162 … … 157 166 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 158 167 159 fs->intRegs[8] = CtxInvokeStub;168 fs->intRegs[8] = __cfactx_invoke_stub; 160 169 fs->arg[0] = this; 161 170 fs->arg[1] = invoke; 162 171 172 #elif defined( __ARM_ARCH ) 173 struct FakeStack { 174 void * intRegs[12]; // x19-x30 integer registers 175 double fpRegs[8]; // v8-v15 floating point 176 }; 177 178 cor->context.SP = (char *)stack->base - sizeof( struct FakeStack ); 179 cor->context.FP = NULL; 180 181 struct FakeStack *fs = (struct FakeStack *)cor->context.SP; 182 183 fs->intRegs[0] = main; // argument to invoke x19 => x0 184 fs->intRegs[1] = this; // argument to invoke x20 => x1 185 fs->intRegs[2] = invoke; 186 fs->intRegs[11] = __cfactx_invoke_stub; // link register x30 => ret moves to pc 163 187 #else 164 188 #error uknown hardware architecture -
libcfa/src/concurrency/invoke.h
rbdfc032 reef8dfb 17 17 #include "bits/defs.hfa" 18 18 #include "bits/locks.hfa" 19 #include "kernel/fwd.hfa" 19 20 20 21 #ifdef __cforall … … 26 27 #define _INVOKE_H_ 27 28 28 #ifdef __ARM_ARCH 29 // function prototypes are only really used by these macros on ARM 30 void disable_global_interrupts(); 31 void enable_global_interrupts(); 32 33 #define TL_GET( member ) ( { __typeof__( kernelTLS.member ) target; \ 34 disable_global_interrupts(); \ 35 target = kernelTLS.member; \ 36 enable_global_interrupts(); \ 37 target; } ) 38 #define TL_SET( member, value ) disable_global_interrupts(); \ 39 kernelTLS.member = value; \ 40 enable_global_interrupts(); 41 #else 42 #define TL_GET( member ) kernelTLS.member 43 #define TL_SET( member, value ) kernelTLS.member = value; 44 #endif 45 46 #ifdef __cforall 47 extern "Cforall" { 48 extern __attribute__((aligned(128))) thread_local struct KernelThreadData { 49 struct thread_desc * volatile this_thread; 50 struct processor * volatile this_processor; 51 52 struct { 53 volatile unsigned short disable_count; 54 volatile bool enabled; 55 volatile bool in_progress; 56 } preemption_state; 57 58 uint32_t rand_seed; 59 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 60 } 61 #endif 29 struct __cfaehm_try_resume_node; 30 struct __cfaehm_base_exception_t; 31 struct exception_context_t { 32 struct __cfaehm_try_resume_node * top_resume; 33 struct __cfaehm_base_exception_t * current_exception; 34 }; 62 35 63 36 struct __stack_context_t { … … 85 58 // base of stack 86 59 void * base; 60 61 // Information for exception handling. 62 struct exception_context_t exception_context; 87 63 }; 88 64 … … 92 68 }; 93 69 94 enum coroutine_state { Halted, Start, Inactive, Active, Primed};95 96 struct coroutine_desc{97 // context that is switch during a CtxSwitch70 enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled, Halting }; 71 72 struct $coroutine { 73 // context that is switch during a __cfactx_switch 98 74 struct __stack_context_t context; 99 75 … … 105 81 106 82 // current execution status for coroutine 107 enum coroutine_state state;83 enum __Coroutine_State state; 108 84 109 85 // first coroutine to resume this one 110 struct coroutine_desc* starter;86 struct $coroutine * starter; 111 87 112 88 // last coroutine to resume this one 113 struct coroutine_desc* last;89 struct $coroutine * last; 114 90 115 91 // If non-null stack must be unwound with this exception … … 117 93 118 94 }; 95 // Wrapper for gdb 96 struct cfathread_coroutine_t { struct $coroutine debug; }; 97 98 static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { 99 return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); 100 } 119 101 120 102 // struct which calls the monitor is accepting … … 127 109 }; 128 110 129 struct monitor_desc{111 struct $monitor { 130 112 // spinlock to protect internal data 131 113 struct __spinlock_t lock; 132 114 133 115 // current owner of the monitor 134 struct thread_desc* owner;116 struct $thread * owner; 135 117 136 118 // queue of threads that are blocked waiting for the monitor 137 __queue_t(struct thread_desc) entry_queue;119 __queue_t(struct $thread) entry_queue; 138 120 139 121 // stack of conditions to run next once we exit the monitor … … 149 131 struct __condition_node_t * dtor_node; 150 132 }; 133 // Wrapper for gdb 134 struct cfathread_monitor_t { struct $monitor debug; }; 151 135 152 136 struct __monitor_group_t { 153 137 // currently held monitors 154 __cfa_anonymous_object( __small_array_t( monitor_desc*) );138 __cfa_anonymous_object( __small_array_t($monitor*) ); 155 139 156 140 // last function that acquired monitors … … 158 142 }; 159 143 160 struct thread_desc { 144 // Link lists fields 145 // instrusive link field for threads 146 struct __thread_desc_link { 147 struct $thread * next; 148 struct $thread * prev; 149 volatile unsigned long long ts; 150 int preferred; 151 }; 152 153 struct $thread { 161 154 // Core threading fields 162 // context that is switch during a CtxSwitch155 // context that is switch during a __cfactx_switch 163 156 struct __stack_context_t context; 164 157 165 158 // current execution status for coroutine 166 enum coroutine_state state; 159 // Possible values are: 160 // - TICKET_BLOCKED (-1) thread is blocked 161 // - TICKET_RUNNING ( 0) thread is running 162 // - TICKET_UNBLOCK ( 1) thread should ignore next block 163 volatile int ticket; 164 enum __Coroutine_State state:8; 165 enum __Preemption_Reason preempted:8; 167 166 168 167 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it 169 170 // coroutine body used to store context171 struct coroutine_desc self_cor;172 173 // current active context174 struct coroutine_desc * curr_cor;175 176 // monitor body used for mutual exclusion177 struct monitor_desc self_mon;178 179 // pointer to monitor with sufficient lifetime for current monitors180 struct monitor_desc * self_mon_p;181 168 182 169 // pointer to the cluster on which the thread is running 183 170 struct cluster * curr_cluster; 184 171 172 // Link lists fields 173 // instrusive link field for threads 174 struct __thread_desc_link link; 175 176 // coroutine body used to store context 177 struct $coroutine self_cor; 178 179 // current active context 180 struct $coroutine * curr_cor; 181 182 // monitor body used for mutual exclusion 183 struct $monitor self_mon; 184 185 // pointer to monitor with sufficient lifetime for current monitors 186 struct $monitor * self_mon_p; 187 185 188 // monitors currently held by this thread 186 189 struct __monitor_group_t monitors; 187 190 188 // Link lists fields 189 // instrusive link field for threads 190 struct thread_desc * next; 191 191 // used to put threads on user data structures 192 192 struct { 193 struct thread_desc * next; 194 struct thread_desc * prev; 193 struct $thread * next; 194 struct $thread * back; 195 } seqable; 196 197 struct { 198 struct $thread * next; 199 struct $thread * prev; 195 200 } node; 196 }; 201 202 #if defined( __CFA_WITH_VERIFY__ ) 203 void * canary; 204 #endif 205 }; 206 // Wrapper for gdb 207 struct cfathread_thread_t { struct $thread debug; }; 208 209 #ifdef __CFA_DEBUG__ 210 void __cfaabi_dbg_record_thrd($thread & this, bool park, const char prev_name[]); 211 #else 212 #define __cfaabi_dbg_record_thrd(x, y, z) 213 #endif 197 214 198 215 #ifdef __cforall 199 216 extern "Cforall" { 200 static inline thread_desc *& get_next( thread_desc & this ) { 201 return this.next; 202 } 203 204 static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) { 217 218 static inline $thread *& get_next( $thread & this ) __attribute__((const)) { 219 return this.link.next; 220 } 221 222 static inline [$thread *&, $thread *& ] __get( $thread & this ) __attribute__((const)) { 205 223 return this.node.[next, prev]; 224 } 225 226 static inline $thread *& Back( $thread * this ) __attribute__((const)) { 227 return this->seqable.back; 228 } 229 230 static inline $thread *& Next( $thread * this ) __attribute__((const)) { 231 return this->seqable.next; 232 } 233 234 static inline bool listed( $thread * this ) { 235 return this->seqable.next != 0p; 206 236 } 207 237 … … 212 242 } 213 243 214 static inline void ?{}(__monitor_group_t & this, struct monitor_desc** data, __lock_size_t size, fptr_t func) {244 static inline void ?{}(__monitor_group_t & this, struct $monitor ** data, __lock_size_t size, fptr_t func) { 215 245 (this.data){data}; 216 246 (this.size){size}; … … 218 248 } 219 249 220 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) {250 static inline bool ?==?( const __monitor_group_t & lhs, const __monitor_group_t & rhs ) __attribute__((const)) { 221 251 if( (lhs.data != 0) != (rhs.data != 0) ) return false; 222 252 if( lhs.size != rhs.size ) return false; … … 252 282 253 283 // assembler routines that performs the context switch 254 extern void CtxInvokeStub( void );255 extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");284 extern void __cfactx_invoke_stub( void ); 285 extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch"); 256 286 // void CtxStore ( void * this ) asm ("CtxStore"); 257 287 // void CtxRet ( void * dst ) asm ("CtxRet"); -
libcfa/src/concurrency/kernel.cfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 30 22:55:50 202013 // Update Count : 5612 // Last Modified On : Mon Aug 31 07:08:20 2020 13 // Update Count : 71 14 14 // 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ 17 18 18 19 //C Includes 19 #include <stddef.h>20 20 #include <errno.h> 21 #include <string.h>22 extern "C" {23 21 #include <stdio.h> 24 #include <fenv.h>25 #include <sys/resource.h>26 22 #include <signal.h> 27 23 #include <unistd.h> 28 #include <limits.h> // PTHREAD_STACK_MIN29 #include <sys/mman.h> // mprotect30 }31 24 32 25 //CFA Includes 33 #include "time.hfa"34 26 #include "kernel_private.hfa" 35 27 #include "preemption.hfa" 36 #include "startup.hfa"37 28 38 29 //Private includes … … 40 31 #include "invoke.h" 41 32 33 42 34 //----------------------------------------------------------------------------- 43 35 // Some assembly required 44 36 #if defined( __i386 ) 45 #define CtxGet( ctx ) \46 __asm__ volatile ( \47 "movl %%esp,%0\n"\48 "movl %%ebp,%1\n"\49 : "=rm" (ctx.SP),\50 "=rm" (ctx.FP) \51 )52 53 37 // mxcr : SSE Status and Control bits (control bits are preserved across function calls) 54 38 // fcw : X87 FPU control word (preserved across function calls) … … 72 56 73 57 #elif defined( __x86_64 ) 74 #define CtxGet( ctx ) \75 __asm__ volatile ( \76 "movq %%rsp,%0\n"\77 "movq %%rbp,%1\n"\78 : "=rm" (ctx.SP),\79 "=rm" (ctx.FP) \80 )81 82 58 #define __x87_store \ 83 59 uint32_t __mxcr; \ … … 98 74 ) 99 75 100 101 #elif defined( __ARM_ARCH ) 102 #define CtxGet( ctx ) __asm__ ( \ 103 "mov %0,%%sp\n" \ 104 "mov %1,%%r11\n" \ 105 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 76 #elif defined( __arm__ ) 77 #define __x87_store 78 #define __x87_load 79 80 #elif defined( __aarch64__ ) 81 #define __x87_store \ 82 uint32_t __fpcntl[2]; \ 83 __asm__ volatile ( \ 84 "mrs x9, FPCR\n" \ 85 "mrs x10, FPSR\n" \ 86 "stp x9, x10, %0\n" \ 87 : "=m" (__fpcntl) : : "x9", "x10" \ 88 ) 89 90 #define __x87_load \ 91 __asm__ volatile ( \ 92 "ldp x9, x10, %0\n" \ 93 "msr FPSR, x10\n" \ 94 "msr FPCR, x9\n" \ 95 : "=m" (__fpcntl) : : "x9", "x10" \ 96 ) 97 106 98 #else 107 #error un knownhardware architecture99 #error unsupported hardware architecture 108 100 #endif 109 101 102 extern $thread * mainThread; 103 extern processor * mainProcessor; 104 110 105 //----------------------------------------------------------------------------- 111 //Start and stop routine for the kernel, declared first to make sure they run first 112 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 113 static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 114 115 //----------------------------------------------------------------------------- 116 // Kernel storage 117 KERNEL_STORAGE(cluster, mainCluster); 118 KERNEL_STORAGE(processor, mainProcessor); 119 KERNEL_STORAGE(thread_desc, mainThread); 120 KERNEL_STORAGE(__stack_t, mainThreadCtx); 121 122 cluster * mainCluster; 123 processor * mainProcessor; 124 thread_desc * mainThread; 125 126 extern "C" { 127 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 128 } 129 130 size_t __page_size = 0; 131 132 //----------------------------------------------------------------------------- 133 // Global state 134 thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = { 135 NULL, // cannot use 0p 136 NULL, 137 { 1, false, false }, 138 6u //this should be seeded better but due to a bug calling rdtsc doesn't work 139 }; 140 141 //----------------------------------------------------------------------------- 142 // Struct to steal stack 143 struct current_stack_info_t { 144 __stack_t * storage; // pointer to stack object 145 void * base; // base of stack 146 void * limit; // stack grows towards stack limit 147 void * context; // address of cfa_context_t 148 }; 149 150 void ?{}( current_stack_info_t & this ) { 151 __stack_context_t ctx; 152 CtxGet( ctx ); 153 this.base = ctx.FP; 154 155 rlimit r; 156 getrlimit( RLIMIT_STACK, &r); 157 size_t size = r.rlim_cur; 158 159 this.limit = (void *)(((intptr_t)this.base) - size); 160 this.context = &storage_mainThreadCtx; 161 } 162 163 //----------------------------------------------------------------------------- 164 // Main thread construction 165 166 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 167 stack.storage = info->storage; 168 with(*stack.storage) { 169 limit = info->limit; 170 base = info->base; 171 } 172 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage; 173 *istorage |= 0x1; 174 name = "Main Thread"; 175 state = Start; 176 starter = 0p; 177 last = 0p; 178 cancellation = 0p; 179 } 180 181 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 182 state = Start; 183 self_cor{ info }; 184 curr_cor = &self_cor; 185 curr_cluster = mainCluster; 186 self_mon.owner = &this; 187 self_mon.recursion = 1; 188 self_mon_p = &self_mon; 189 next = 0p; 190 191 node.next = 0p; 192 node.prev = 0p; 193 doregister(curr_cluster, this); 194 195 monitors{ &self_mon_p, 1, (fptr_t)0 }; 196 } 197 198 //----------------------------------------------------------------------------- 199 // Processor coroutine 200 void ?{}(processorCtx_t & this) { 201 202 } 203 204 // Construct the processor context of non-main processors 205 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) { 206 (this.__cor){ info }; 207 this.proc = proc; 208 } 209 210 static void start(processor * this); 211 void ?{}(processor & this, const char * name, cluster & cltr) with( this ) { 212 this.name = name; 213 this.cltr = &cltr; 214 terminated{ 0 }; 215 do_terminate = false; 216 preemption_alarm = 0p; 217 pending_preemption = false; 218 runner.proc = &this; 219 220 idleLock{}; 221 222 start( &this ); 223 } 224 225 void ^?{}(processor & this) with( this ){ 226 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 227 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 228 229 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 230 wake( &this ); 231 232 P( terminated ); 233 verify( kernelTLS.this_processor != &this); 234 } 235 236 pthread_join( kernel_thread, 0p ); 237 free( this.stack ); 238 } 239 240 void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) { 241 this.name = name; 242 this.preemption_rate = preemption_rate; 243 ready_queue{}; 244 ready_queue_lock{}; 245 246 procs{ __get }; 247 idles{ __get }; 248 threads{ __get }; 249 250 doregister(this); 251 } 252 253 void ^?{}(cluster & this) { 254 unregister(this); 255 } 106 // Kernel Scheduling logic 107 static $thread * __next_thread(cluster * this); 108 static $thread * __next_thread_slow(cluster * this); 109 static void __run_thread(processor * this, $thread * dst); 110 static void __wake_one(cluster * cltr); 111 112 static void push (__cluster_idles & idles, processor & proc); 113 static void remove(__cluster_idles & idles, processor & proc); 114 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 115 256 116 257 117 //============================================================================================= 258 118 // Kernel Scheduling logic 259 119 //============================================================================================= 260 static void runThread(processor * this, thread_desc * dst);261 static void finishRunning(processor * this);262 static void halt(processor * this);263 264 120 //Main of the processor contexts 265 121 void main(processorCtx_t & runner) { 266 122 // Because of a bug, we couldn't initialized the seed on construction 267 123 // Do it here 268 kernelTLS.rand_seed ^= rdtscl(); 124 __cfaabi_tls.rand_seed ^= rdtscl(); 125 __cfaabi_tls.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner); 126 __tls_rand_advance_bck(); 269 127 270 128 processor * this = runner.proc; 271 129 verify(this); 272 130 273 __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this); 274 275 doregister(this->cltr, this); 131 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 132 #if !defined(__CFA_NO_STATISTICS__) 133 if( this->print_halts ) { 134 __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this); 135 } 136 #endif 276 137 277 138 { … … 279 140 preemption_scope scope = { this }; 280 141 281 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this); 282 283 thread_desc * readyThread = 0p; 284 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) { 285 readyThread = nextThread( this->cltr ); 286 287 if(readyThread) { 288 verify( ! kernelTLS.preemption_state.enabled ); 289 290 runThread(this, readyThread); 291 292 verify( ! kernelTLS.preemption_state.enabled ); 293 294 //Some actions need to be taken from the kernel 295 finishRunning(this); 296 297 spin_count = 0; 298 } else { 299 // spin(this, &spin_count); 300 halt(this); 142 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this); 143 144 $thread * readyThread = 0p; 145 MAIN_LOOP: 146 for() { 147 // Try to get the next thread 148 readyThread = __next_thread( this->cltr ); 149 150 if( !readyThread ) { 151 readyThread = __next_thread_slow( this->cltr ); 301 152 } 302 } 303 304 __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this); 305 } 306 307 unregister(this->cltr, this); 153 154 HALT: 155 if( !readyThread ) { 156 // Don't block if we are done 157 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 158 159 #if !defined(__CFA_NO_STATISTICS__) 160 __tls_stats()->ready.sleep.halts++; 161 #endif 162 163 // Push self to idle stack 164 push(this->cltr->idles, * this); 165 166 // Confirm the ready-queue is empty 167 readyThread = __next_thread_slow( this->cltr ); 168 if( readyThread ) { 169 // A thread was found, cancel the halt 170 remove(this->cltr->idles, * this); 171 172 #if !defined(__CFA_NO_STATISTICS__) 173 __tls_stats()->ready.sleep.cancels++; 174 #endif 175 176 // continue the mai loop 177 break HALT; 178 } 179 180 #if !defined(__CFA_NO_STATISTICS__) 181 if(this->print_halts) { 182 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); 183 } 184 #endif 185 186 wait( this->idle ); 187 188 #if !defined(__CFA_NO_STATISTICS__) 189 if(this->print_halts) { 190 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); 191 } 192 #endif 193 194 // We were woken up, remove self from idle 195 remove(this->cltr->idles, * this); 196 197 // DON'T just proceed, start looking again 198 continue MAIN_LOOP; 199 } 200 201 /* paranoid */ verify( readyThread ); 202 203 // We found a thread run it 204 __run_thread(this, readyThread); 205 206 // Are we done? 207 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 208 } 209 210 __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this); 211 } 308 212 309 213 V( this->terminated ); 310 214 311 __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this); 215 if(this == mainProcessor) { 216 // HACK : the coroutine context switch expects this_thread to be set 217 // and it make sense for it to be set in all other cases except here 218 // fake it 219 __cfaabi_tls.this_thread = mainThread; 220 } 221 222 __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this); 312 223 } 313 224 … … 318 229 // runThread runs a thread by context switching 319 230 // from the processor coroutine to the target thread 320 static void runThread(processor * this, thread_desc * thrd_dst) { 321 coroutine_desc * proc_cor = get_coroutine(this->runner); 322 323 // Reset the terminating actions here 324 this->finish.action_code = No_Action; 325 326 // Update global state 327 kernelTLS.this_thread = thrd_dst; 328 329 // set state of processor coroutine to inactive and the thread to active 330 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 331 thrd_dst->state = Active; 332 333 // set context switch to the thread that the processor is executing 334 verify( thrd_dst->context.SP ); 335 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 336 // when CtxSwitch returns we are back in the processor coroutine 337 338 // set state of processor coroutine to active and the thread to inactive 339 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 231 static void __run_thread(processor * this, $thread * thrd_dst) { 232 /* paranoid */ verify( ! __preemption_enabled() ); 233 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); 234 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 235 __builtin_prefetch( thrd_dst->context.SP ); 236 237 $coroutine * proc_cor = get_coroutine(this->runner); 238 239 // set state of processor coroutine to inactive 240 verify(proc_cor->state == Active); 241 proc_cor->state = Blocked; 242 243 // Actually run the thread 244 RUNNING: while(true) { 245 thrd_dst->preempted = __NO_PREEMPTION; 246 thrd_dst->state = Active; 247 248 // Update global state 249 kernelTLS().this_thread = thrd_dst; 250 251 /* paranoid */ verify( ! __preemption_enabled() ); 252 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst ); 253 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr ); 254 /* paranoid */ verify( thrd_dst->context.SP ); 255 /* paranoid */ verify( thrd_dst->state != Halted ); 256 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 257 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor 258 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 259 260 261 262 // set context switch to the thread that the processor is executing 263 __cfactx_switch( &proc_cor->context, &thrd_dst->context ); 264 // when __cfactx_switch returns we are back in the processor coroutine 265 266 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 267 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); 268 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); 269 /* paranoid */ verify( thrd_dst->context.SP ); 270 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr ); 271 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst ); 272 /* paranoid */ verify( ! __preemption_enabled() ); 273 274 // Reset global state 275 kernelTLS().this_thread = 0p; 276 277 // We just finished running a thread, there are a few things that could have happened. 278 // 1 - Regular case : the thread has blocked and now one has scheduled it yet. 279 // 2 - Racy case : the thread has blocked but someone has already tried to schedule it. 280 // 4 - Preempted 281 // In case 1, we may have won a race so we can't write to the state again. 282 // In case 2, we lost the race so we now own the thread. 283 284 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 285 // The thread was preempted, reschedule it and reset the flag 286 __schedule_thread( thrd_dst ); 287 break RUNNING; 288 } 289 290 if(unlikely(thrd_dst->state == Halting)) { 291 // The thread has halted, it should never be scheduled/run again 292 // finish the thread 293 __thread_finish( thrd_dst ); 294 break RUNNING; 295 } 296 297 /* paranoid */ verify( thrd_dst->state == Active ); 298 thrd_dst->state = Blocked; 299 300 // set state of processor coroutine to active and the thread to inactive 301 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST); 302 switch(old_ticket) { 303 case TICKET_RUNNING: 304 // This is case 1, the regular case, nothing more is needed 305 break RUNNING; 306 case TICKET_UNBLOCK: 307 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 308 // In this case, just run it again. 309 continue RUNNING; 310 default: 311 // This makes no sense, something is wrong abort 312 abort(); 313 } 314 } 315 316 // Just before returning to the processor, set the processor coroutine to active 340 317 proc_cor->state = Active; 318 319 /* paranoid */ verify( ! __preemption_enabled() ); 341 320 } 342 321 343 322 // KERNEL_ONLY 344 static void returnToKernel() { 345 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 346 thread_desc * thrd_src = kernelTLS.this_thread; 347 348 // set state of current coroutine to inactive 349 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 350 proc_cor->state = Active; 351 int local_errno = *__volatile_errno(); 352 #if defined( __i386 ) || defined( __x86_64 ) 353 __x87_store; 323 void returnToKernel() { 324 /* paranoid */ verify( ! __preemption_enabled() ); 325 $coroutine * proc_cor = get_coroutine(kernelTLS().this_processor->runner); 326 $thread * thrd_src = kernelTLS().this_thread; 327 328 #if !defined(__CFA_NO_STATISTICS__) 329 struct processor * last_proc = kernelTLS().this_processor; 354 330 #endif 355 331 356 // set new coroutine that the processor is executing 357 // and context switch to it 358 verify( proc_cor->context.SP ); 359 CtxSwitch( &thrd_src->context, &proc_cor->context ); 360 361 // set state of new coroutine to active 362 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 363 thrd_src->state = Active; 364 365 #if defined( __i386 ) || defined( __x86_64 ) 366 __x87_load; 332 // Run the thread on this processor 333 { 334 int local_errno = *__volatile_errno(); 335 #if defined( __i386 ) || defined( __x86_64 ) 336 __x87_store; 337 #endif 338 /* paranoid */ verify( proc_cor->context.SP ); 339 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_src->canary ); 340 __cfactx_switch( &thrd_src->context, &proc_cor->context ); 341 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_src->canary ); 342 #if defined( __i386 ) || defined( __x86_64 ) 343 __x87_load; 344 #endif 345 *__volatile_errno() = local_errno; 346 } 347 348 #if !defined(__CFA_NO_STATISTICS__) 349 if(last_proc != kernelTLS().this_processor) { 350 __tls_stats()->ready.threads.migration++; 351 } 367 352 #endif 368 *__volatile_errno() = local_errno; 369 } 370 371 // KERNEL_ONLY 372 // Once a thread has finished running, some of 373 // its final actions must be executed from the kernel 374 static void finishRunning(processor * this) with( this->finish ) { 375 verify( ! kernelTLS.preemption_state.enabled ); 376 choose( action_code ) { 377 case No_Action: 378 break; 379 case Release: 380 unlock( *lock ); 381 case Schedule: 382 ScheduleThread( thrd ); 383 case Release_Schedule: 384 unlock( *lock ); 385 ScheduleThread( thrd ); 386 case Release_Multi: 387 for(int i = 0; i < lock_count; i++) { 388 unlock( *locks[i] ); 389 } 390 case Release_Multi_Schedule: 391 for(int i = 0; i < lock_count; i++) { 392 unlock( *locks[i] ); 393 } 394 for(int i = 0; i < thrd_count; i++) { 395 ScheduleThread( thrds[i] ); 396 } 397 case Callback: 398 callback(); 399 default: 400 abort("KERNEL ERROR: Unexpected action to run after thread"); 401 } 402 } 403 404 // KERNEL_ONLY 405 // Context invoker for processors 406 // This is the entry point for processors (kernel threads) 407 // It effectively constructs a coroutine by stealing the pthread stack 408 static void * CtxInvokeProcessor(void * arg) { 409 processor * proc = (processor *) arg; 410 kernelTLS.this_processor = proc; 411 kernelTLS.this_thread = 0p; 412 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; 413 // SKULLDUGGERY: We want to create a context for the processor coroutine 414 // which is needed for the 2-step context switch. However, there is no reason 415 // to waste the perfectly valid stack create by pthread. 416 current_stack_info_t info; 417 __stack_t ctx; 418 info.storage = &ctx; 419 (proc->runner){ proc, &info }; 420 421 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 422 423 //Set global state 424 kernelTLS.this_thread = 0p; 425 426 //We now have a proper context from which to schedule threads 427 __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx); 428 429 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 430 // resume it to start it like it normally would, it will just context switch 431 // back to here. Instead directly call the main since we already are on the 432 // appropriate stack. 433 get_coroutine(proc->runner)->state = Active; 434 main( proc->runner ); 435 get_coroutine(proc->runner)->state = Halted; 436 437 // Main routine of the core returned, the core is now fully terminated 438 __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner); 439 440 return 0p; 441 } 442 443 static void Abort( int ret, const char * func ) { 444 if ( ret ) { // pthread routines return errno values 445 abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) ); 446 } // if 447 } // Abort 448 449 void * create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) { 450 pthread_attr_t attr; 451 452 Abort( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute 453 454 size_t stacksize; 455 // default stack size, normally defined by shell limit 456 Abort( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" ); 457 assert( stacksize >= PTHREAD_STACK_MIN ); 458 459 void * stack; 460 __cfaabi_dbg_debug_do( 461 stack = memalign( __page_size, stacksize + __page_size ); 462 // pthread has no mechanism to create the guard page in user supplied stack. 463 if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) { 464 abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) ); 465 } // if 466 ); 467 __cfaabi_dbg_no_debug_do( 468 stack = malloc( stacksize ); 469 ); 470 471 Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" ); 472 473 Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" ); 474 return stack; 475 } 476 477 static void start(processor * this) { 478 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this); 479 480 this->stack = create_pthread( &this->kernel_thread, CtxInvokeProcessor, (void *)this ); 481 482 __cfaabi_dbg_print_safe("Kernel : core %p started\n", this); 483 } 484 485 // KERNEL_ONLY 486 void kernel_first_resume( processor * this ) { 487 thread_desc * src = mainThread; 488 coroutine_desc * dst = get_coroutine(this->runner); 489 490 verify( ! kernelTLS.preemption_state.enabled ); 491 492 kernelTLS.this_thread->curr_cor = dst; 493 __stack_prepare( &dst->stack, 65000 ); 494 CtxStart(main, dst, this->runner, CtxInvokeCoroutine); 495 496 verify( ! kernelTLS.preemption_state.enabled ); 497 498 dst->last = &src->self_cor; 499 dst->starter = dst->starter ? dst->starter : &src->self_cor; 500 501 // set state of current coroutine to inactive 502 src->state = src->state == Halted ? Halted : Inactive; 503 504 // context switch to specified coroutine 505 verify( dst->context.SP ); 506 CtxSwitch( &src->context, &dst->context ); 507 // when CtxSwitch returns we are back in the src coroutine 508 509 mainThread->curr_cor = &mainThread->self_cor; 510 511 // set state of new coroutine to active 512 src->state = Active; 513 514 verify( ! kernelTLS.preemption_state.enabled ); 515 } 516 517 // KERNEL_ONLY 518 void kernel_last_resume( processor * this ) { 519 coroutine_desc * src = &mainThread->self_cor; 520 coroutine_desc * dst = get_coroutine(this->runner); 521 522 verify( ! kernelTLS.preemption_state.enabled ); 523 verify( dst->starter == src ); 524 verify( dst->context.SP ); 525 526 // context switch to the processor 527 CtxSwitch( &src->context, &dst->context ); 353 354 /* paranoid */ verify( ! __preemption_enabled() ); 355 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src ); 356 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src ); 528 357 } 529 358 530 359 //----------------------------------------------------------------------------- 531 360 // Scheduler routines 532 533 361 // KERNEL ONLY 534 void ScheduleThread( thread_desc * thrd ) { 535 verify( thrd ); 536 verify( thrd->state != Halted ); 537 538 verify( ! kernelTLS.preemption_state.enabled ); 539 540 verifyf( thrd->next == 0p, "Expected null got %p", thrd->next ); 541 542 with( *thrd->curr_cluster ) { 543 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 544 bool was_empty = !(ready_queue != 0); 545 append( ready_queue, thrd ); 546 unlock( ready_queue_lock ); 547 548 if(was_empty) { 549 lock (proc_list_lock __cfaabi_dbg_ctx2); 550 if(idles) { 551 wake_fast(idles.head); 362 void __schedule_thread( $thread * thrd ) { 363 /* paranoid */ verify( ! __preemption_enabled() ); 364 /* paranoid */ verify( kernelTLS().this_proc_id ); 365 /* paranoid */ verify( thrd ); 366 /* paranoid */ verify( thrd->state != Halted ); 367 /* paranoid */ verify( thrd->curr_cluster ); 368 /* paranoid */ #if defined( __CFA_WITH_VERIFY__ ) 369 /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION, 370 "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted ); 371 /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active, 372 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted ); 373 /* paranoid */ #endif 374 /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next ); 375 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 376 377 378 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 379 380 ready_schedule_lock(); 381 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 382 struct cluster * cl = thrd->curr_cluster; 383 384 // push the thread to the cluster ready-queue 385 push( cl, thrd ); 386 387 // variable thrd is no longer safe to use 388 389 // wake the cluster using the save variable. 390 __wake_one( cl ); 391 ready_schedule_unlock(); 392 393 /* paranoid */ verify( ! __preemption_enabled() ); 394 } 395 396 // KERNEL ONLY 397 static inline $thread * __next_thread(cluster * this) with( *this ) { 398 /* paranoid */ verify( ! __preemption_enabled() ); 399 /* paranoid */ verify( kernelTLS().this_proc_id ); 400 401 ready_schedule_lock(); 402 $thread * thrd = pop( this ); 403 ready_schedule_unlock(); 404 405 /* paranoid */ verify( kernelTLS().this_proc_id ); 406 /* paranoid */ verify( ! __preemption_enabled() ); 407 return thrd; 408 } 409 410 // KERNEL ONLY 411 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 412 /* paranoid */ verify( ! __preemption_enabled() ); 413 /* paranoid */ verify( kernelTLS().this_proc_id ); 414 415 ready_schedule_lock(); 416 $thread * thrd = pop_slow( this ); 417 ready_schedule_unlock(); 418 419 /* paranoid */ verify( kernelTLS().this_proc_id ); 420 /* paranoid */ verify( ! __preemption_enabled() ); 421 return thrd; 422 } 423 424 void unpark( $thread * thrd ) { 425 if( !thrd ) return; 426 427 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 428 switch(old_ticket) { 429 case TICKET_RUNNING: 430 // Wake won the race, the thread will reschedule/rerun itself 431 break; 432 case TICKET_BLOCKED: 433 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 434 /* paranoid */ verify( thrd->state == Blocked ); 435 436 { 437 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 438 bool full = publicTLS_get(this_proc_id)->full_proc; 439 if(full) disable_interrupts(); 440 441 /* paranoid */ verify( ! __preemption_enabled() ); 442 443 // Wake lost the race, 444 __schedule_thread( thrd ); 445 446 /* paranoid */ verify( ! __preemption_enabled() ); 447 448 if(full) enable_interrupts( __cfaabi_dbg_ctx ); 449 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 552 450 } 553 unlock (proc_list_lock); 554 } 555 else if( struct processor * idle = idles.head ) { 556 wake_fast(idle); 557 } 558 559 } 560 561 verify( ! kernelTLS.preemption_state.enabled ); 451 452 break; 453 default: 454 // This makes no sense, something is wrong abort 455 abort("Thread %p (%s) has mismatch park/unpark\n", thrd, thrd->self_cor.name); 456 } 457 } 458 459 void park( void ) { 460 /* paranoid */ verify( __preemption_enabled() ); 461 disable_interrupts(); 462 /* paranoid */ verify( ! __preemption_enabled() ); 463 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); 464 465 returnToKernel(); 466 467 /* paranoid */ verify( ! __preemption_enabled() ); 468 enable_interrupts( __cfaabi_dbg_ctx ); 469 /* paranoid */ verify( __preemption_enabled() ); 470 471 } 472 473 extern "C" { 474 // Leave the thread monitor 475 // last routine called by a thread. 476 // Should never return 477 void __cfactx_thrd_leave() { 478 $thread * thrd = active_thread(); 479 $monitor * this = &thrd->self_mon; 480 481 // Lock the monitor now 482 lock( this->lock __cfaabi_dbg_ctx2 ); 483 484 disable_interrupts(); 485 486 /* paranoid */ verify( ! __preemption_enabled() ); 487 /* paranoid */ verify( thrd->state == Active ); 488 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 489 /* paranoid */ verify( kernelTLS().this_thread == thrd ); 490 /* paranoid */ verify( thrd->context.SP ); 491 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : $thread %p has been corrupted.\n StackPointer too large.\n", thrd ); 492 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : $thread %p has been corrupted.\n StackPointer too small.\n", thrd ); 493 494 thrd->state = Halting; 495 if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); } 496 if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); } 497 if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); } 498 499 // Leave the thread 500 returnToKernel(); 501 502 // Control flow should never reach here! 503 abort(); 504 } 562 505 } 563 506 564 507 // KERNEL ONLY 565 thread_desc * nextThread(cluster * this) with( *this ) { 566 verify( ! kernelTLS.preemption_state.enabled ); 567 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 568 thread_desc * head = pop_head( ready_queue ); 569 unlock( ready_queue_lock ); 570 verify( ! kernelTLS.preemption_state.enabled ); 571 return head; 572 } 573 574 void BlockInternal() { 508 bool force_yield( __Preemption_Reason reason ) { 509 /* paranoid */ verify( __preemption_enabled() ); 575 510 disable_interrupts(); 576 verify( ! kernelTLS.preemption_state.enabled ); 577 returnToKernel(); 578 verify( ! kernelTLS.preemption_state.enabled ); 511 /* paranoid */ verify( ! __preemption_enabled() ); 512 513 $thread * thrd = kernelTLS().this_thread; 514 /* paranoid */ verify(thrd->state == Active); 515 516 // SKULLDUGGERY: It is possible that we are preempting this thread just before 517 // it was going to park itself. If that is the case and it is already using the 518 // intrusive fields then we can't use them to preempt the thread 519 // If that is the case, abandon the preemption. 520 bool preempted = false; 521 if(thrd->link.next == 0p) { 522 preempted = true; 523 thrd->preempted = reason; 524 returnToKernel(); 525 } 526 527 /* paranoid */ verify( ! __preemption_enabled() ); 528 enable_interrupts_noPoll(); 529 /* paranoid */ verify( __preemption_enabled() ); 530 531 return preempted; 532 } 533 534 //============================================================================================= 535 // Kernel Idle Sleep 536 //============================================================================================= 537 // Wake a thread from the front if there are any 538 static void __wake_one(cluster * this) { 539 /* paranoid */ verify( ! __preemption_enabled() ); 540 /* paranoid */ verify( ready_schedule_islocked() ); 541 542 // Check if there is a sleeping processor 543 processor * p; 544 unsigned idle; 545 unsigned total; 546 [idle, total, p] = query(this->idles); 547 548 // If no one is sleeping, we are done 549 if( idle == 0 ) return; 550 551 // We found a processor, wake it up 552 post( p->idle ); 553 554 #if !defined(__CFA_NO_STATISTICS__) 555 __tls_stats()->ready.sleep.wakes++; 556 #endif 557 558 /* paranoid */ verify( ready_schedule_islocked() ); 559 /* paranoid */ verify( ! __preemption_enabled() ); 560 561 return; 562 } 563 564 // Unconditionnaly wake a thread 565 void __wake_proc(processor * this) { 566 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 567 568 disable_interrupts(); 569 /* paranoid */ verify( ! __preemption_enabled() ); 570 post( this->idle ); 579 571 enable_interrupts( __cfaabi_dbg_ctx ); 580 572 } 581 573 582 void BlockInternal( __spinlock_t * lock ) { 583 disable_interrupts(); 584 with( *kernelTLS.this_processor ) { 585 finish.action_code = Release; 586 finish.lock = lock; 587 } 588 589 verify( ! kernelTLS.preemption_state.enabled ); 590 returnToKernel(); 591 verify( ! kernelTLS.preemption_state.enabled ); 592 593 enable_interrupts( __cfaabi_dbg_ctx ); 594 } 595 596 void BlockInternal( thread_desc * thrd ) { 597 disable_interrupts(); 598 with( * kernelTLS.this_processor ) { 599 finish.action_code = Schedule; 600 finish.thrd = thrd; 601 } 602 603 verify( ! kernelTLS.preemption_state.enabled ); 604 returnToKernel(); 605 verify( ! kernelTLS.preemption_state.enabled ); 606 607 enable_interrupts( __cfaabi_dbg_ctx ); 608 } 609 610 void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) { 611 assert(thrd); 612 disable_interrupts(); 613 with( * kernelTLS.this_processor ) { 614 finish.action_code = Release_Schedule; 615 finish.lock = lock; 616 finish.thrd = thrd; 617 } 618 619 verify( ! kernelTLS.preemption_state.enabled ); 620 returnToKernel(); 621 verify( ! kernelTLS.preemption_state.enabled ); 622 623 enable_interrupts( __cfaabi_dbg_ctx ); 624 } 625 626 void BlockInternal(__spinlock_t * locks [], unsigned short count) { 627 disable_interrupts(); 628 with( * kernelTLS.this_processor ) { 629 finish.action_code = Release_Multi; 630 finish.locks = locks; 631 finish.lock_count = count; 632 } 633 634 verify( ! kernelTLS.preemption_state.enabled ); 635 returnToKernel(); 636 verify( ! kernelTLS.preemption_state.enabled ); 637 638 enable_interrupts( __cfaabi_dbg_ctx ); 639 } 640 641 void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) { 642 disable_interrupts(); 643 with( *kernelTLS.this_processor ) { 644 finish.action_code = Release_Multi_Schedule; 645 finish.locks = locks; 646 finish.lock_count = lock_count; 647 finish.thrds = thrds; 648 finish.thrd_count = thrd_count; 649 } 650 651 verify( ! kernelTLS.preemption_state.enabled ); 652 returnToKernel(); 653 verify( ! kernelTLS.preemption_state.enabled ); 654 655 enable_interrupts( __cfaabi_dbg_ctx ); 656 } 657 658 void BlockInternal(__finish_callback_fptr_t callback) { 659 disable_interrupts(); 660 with( *kernelTLS.this_processor ) { 661 finish.action_code = Callback; 662 finish.callback = callback; 663 } 664 665 verify( ! kernelTLS.preemption_state.enabled ); 666 returnToKernel(); 667 verify( ! kernelTLS.preemption_state.enabled ); 668 669 enable_interrupts( __cfaabi_dbg_ctx ); 670 } 671 672 // KERNEL ONLY 673 void LeaveThread(__spinlock_t * lock, thread_desc * thrd) { 674 verify( ! kernelTLS.preemption_state.enabled ); 675 with( * kernelTLS.this_processor ) { 676 finish.action_code = thrd ? Release_Schedule : Release; 677 finish.lock = lock; 678 finish.thrd = thrd; 679 } 680 681 returnToKernel(); 682 } 683 684 //============================================================================================= 685 // Kernel Setup logic 686 //============================================================================================= 687 //----------------------------------------------------------------------------- 688 // Kernel boot procedures 689 static void kernel_startup(void) { 690 verify( ! kernelTLS.preemption_state.enabled ); 691 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 692 693 __page_size = sysconf( _SC_PAGESIZE ); 694 695 __cfa_dbg_global_clusters.list{ __get }; 696 __cfa_dbg_global_clusters.lock{}; 697 698 // Initialize the main cluster 699 mainCluster = (cluster *)&storage_mainCluster; 700 (*mainCluster){"Main Cluster"}; 701 702 __cfaabi_dbg_print_safe("Kernel : Main cluster ready\n"); 703 704 // Start by initializing the main thread 705 // SKULLDUGGERY: the mainThread steals the process main thread 706 // which will then be scheduled by the mainProcessor normally 707 mainThread = (thread_desc *)&storage_mainThread; 708 current_stack_info_t info; 709 info.storage = (__stack_t*)&storage_mainThreadCtx; 710 (*mainThread){ &info }; 711 712 __cfaabi_dbg_print_safe("Kernel : Main thread ready\n"); 713 714 715 716 // Construct the processor context of the main processor 717 void ?{}(processorCtx_t & this, processor * proc) { 718 (this.__cor){ "Processor" }; 719 this.__cor.starter = 0p; 720 this.proc = proc; 721 } 722 723 void ?{}(processor & this) with( this ) { 724 name = "Main Processor"; 725 cltr = mainCluster; 726 terminated{ 0 }; 727 do_terminate = false; 728 preemption_alarm = 0p; 729 pending_preemption = false; 730 kernel_thread = pthread_self(); 731 732 runner{ &this }; 733 __cfaabi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner); 734 } 735 736 // Initialize the main processor and the main processor ctx 737 // (the coroutine that contains the processing control flow) 738 mainProcessor = (processor *)&storage_mainProcessor; 739 (*mainProcessor){}; 740 741 //initialize the global state variables 742 kernelTLS.this_processor = mainProcessor; 743 kernelTLS.this_thread = mainThread; 744 745 // Enable preemption 746 kernel_start_preemption(); 747 748 // Add the main thread to the ready queue 749 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 750 ScheduleThread(mainThread); 751 752 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX 753 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 754 // mainThread is on the ready queue when this call is made. 755 kernel_first_resume( kernelTLS.this_processor ); 756 757 758 759 // THE SYSTEM IS NOW COMPLETELY RUNNING 760 __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n"); 761 762 verify( ! kernelTLS.preemption_state.enabled ); 763 enable_interrupts( __cfaabi_dbg_ctx ); 764 verify( TL_GET( preemption_state.enabled ) ); 765 } 766 767 static void kernel_shutdown(void) { 768 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 769 770 verify( TL_GET( preemption_state.enabled ) ); 771 disable_interrupts(); 772 verify( ! kernelTLS.preemption_state.enabled ); 773 774 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates. 775 // When its coroutine terminates, it return control to the mainThread 776 // which is currently here 777 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 778 kernel_last_resume( kernelTLS.this_processor ); 779 mainThread->self_cor.state = Halted; 780 781 // THE SYSTEM IS NOW COMPLETELY STOPPED 782 783 // Disable preemption 784 kernel_stop_preemption(); 785 786 // Destroy the main processor and its context in reverse order of construction 787 // These were manually constructed so we need manually destroy them 788 ^(mainProcessor->runner){}; 789 ^(mainProcessor){}; 790 791 // Final step, destroy the main thread since it is no longer needed 792 // Since we provided a stack to this taxk it will not destroy anything 793 ^(mainThread){}; 794 795 ^(__cfa_dbg_global_clusters.list){}; 796 ^(__cfa_dbg_global_clusters.lock){}; 797 798 __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n"); 799 } 800 801 //============================================================================================= 802 // Kernel Quiescing 803 //============================================================================================= 804 static void halt(processor * this) with( *this ) { 805 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 806 807 with( *cltr ) { 808 lock (proc_list_lock __cfaabi_dbg_ctx2); 809 remove (procs, *this); 810 push_front(idles, *this); 811 unlock (proc_list_lock); 812 } 813 814 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 815 816 wait( idleLock ); 817 818 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); 819 820 with( *cltr ) { 821 lock (proc_list_lock __cfaabi_dbg_ctx2); 822 remove (idles, *this); 823 push_front(procs, *this); 824 unlock (proc_list_lock); 574 static void push (__cluster_idles & this, processor & proc) { 575 /* paranoid */ verify( ! __preemption_enabled() ); 576 lock( this ); 577 this.idle++; 578 /* paranoid */ verify( this.idle <= this.total ); 579 580 insert_first(this.list, proc); 581 unlock( this ); 582 /* paranoid */ verify( ! __preemption_enabled() ); 583 } 584 585 static void remove(__cluster_idles & this, processor & proc) { 586 /* paranoid */ verify( ! __preemption_enabled() ); 587 lock( this ); 588 this.idle--; 589 /* paranoid */ verify( this.idle >= 0 ); 590 591 remove(proc); 592 unlock( this ); 593 /* paranoid */ verify( ! __preemption_enabled() ); 594 } 595 596 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) { 597 for() { 598 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST); 599 if( 1 == (l % 2) ) { Pause(); continue; } 600 unsigned idle = this.idle; 601 unsigned total = this.total; 602 processor * proc = &this.list`first; 603 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it 604 asm volatile("": : :"memory"); 605 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; } 606 return [idle, total, proc]; 825 607 } 826 608 } … … 836 618 // the globalAbort flag is true. 837 619 lock( kernel_abort_lock __cfaabi_dbg_ctx2 ); 620 621 // disable interrupts, it no longer makes sense to try to interrupt this processor 622 disable_interrupts(); 838 623 839 624 // first task to abort ? … … 853 638 } 854 639 855 return kernelTLS.this_thread;640 return __cfaabi_tls.this_thread; 856 641 } 857 642 858 643 void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) { 859 thread_desc * thrd =kernel_data;644 $thread * thrd = ( $thread * ) kernel_data; 860 645 861 646 if(thrd) { … … 878 663 879 664 int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) { 880 return get_coroutine(kernelTLS .this_thread) == get_coroutine(mainThread) ? 4 : 2;665 return get_coroutine(kernelTLS().this_thread) == get_coroutine(mainThread) ? 4 : 2; 881 666 } 882 667 … … 905 690 void ^?{}(semaphore & this) {} 906 691 907 voidP(semaphore & this) with( this ){692 bool P(semaphore & this) with( this ){ 908 693 lock( lock __cfaabi_dbg_ctx2 ); 909 694 count -= 1; 910 695 if ( count < 0 ) { 911 696 // queue current task 912 append( waiting, kernelTLS.this_thread);697 append( waiting, active_thread() ); 913 698 914 699 // atomically release spin lock and block 915 BlockInternal( &lock ); 700 unlock( lock ); 701 park(); 702 return true; 916 703 } 917 704 else { 918 705 unlock( lock ); 919 } 920 } 921 922 void V(semaphore & this) with( this ) { 923 thread_desc * thrd = 0p; 706 return false; 707 } 708 } 709 710 bool V(semaphore & this) with( this ) { 711 $thread * thrd = 0p; 924 712 lock( lock __cfaabi_dbg_ctx2 ); 925 713 count += 1; … … 932 720 933 721 // make new owner 934 WakeThread( thrd ); 935 } 936 937 //----------------------------------------------------------------------------- 938 // Global Queues 939 void doregister( cluster & cltr ) { 940 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 941 push_front( __cfa_dbg_global_clusters.list, cltr ); 942 unlock ( __cfa_dbg_global_clusters.lock ); 943 } 944 945 void unregister( cluster & cltr ) { 946 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2); 947 remove( __cfa_dbg_global_clusters.list, cltr ); 948 unlock( __cfa_dbg_global_clusters.lock ); 949 } 950 951 void doregister( cluster * cltr, thread_desc & thrd ) { 952 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 953 cltr->nthreads += 1; 954 push_front(cltr->threads, thrd); 955 unlock (cltr->thread_list_lock); 956 } 957 958 void unregister( cluster * cltr, thread_desc & thrd ) { 959 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 960 remove(cltr->threads, thrd ); 961 cltr->nthreads -= 1; 962 unlock(cltr->thread_list_lock); 963 } 964 965 void doregister( cluster * cltr, processor * proc ) { 966 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 967 cltr->nprocessors += 1; 968 push_front(cltr->procs, *proc); 969 unlock (cltr->proc_list_lock); 970 } 971 972 void unregister( cluster * cltr, processor * proc ) { 973 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 974 remove(cltr->procs, *proc ); 975 cltr->nprocessors -= 1; 976 unlock(cltr->proc_list_lock); 722 unpark( thrd ); 723 724 return thrd != 0p; 725 } 726 727 bool V(semaphore & this, unsigned diff) with( this ) { 728 $thread * thrd = 0p; 729 lock( lock __cfaabi_dbg_ctx2 ); 730 int release = max(-count, (int)diff); 731 count += diff; 732 for(release) { 733 unpark( pop_head( waiting ) ); 734 } 735 736 unlock( lock ); 737 738 return thrd != 0p; 977 739 } 978 740 … … 981 743 __cfaabi_dbg_debug_do( 982 744 extern "C" { 983 void __cfaabi_dbg_record (__spinlock_t & this, const char * prev_name) {745 void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]) { 984 746 this.prev_name = prev_name; 985 this.prev_thrd = kernelTLS .this_thread;747 this.prev_thrd = kernelTLS().this_thread; 986 748 } 987 749 } … … 990 752 //----------------------------------------------------------------------------- 991 753 // Debug 992 bool threading_enabled(void) {754 bool threading_enabled(void) __attribute__((const)) { 993 755 return true; 994 756 } 757 758 //----------------------------------------------------------------------------- 759 // Statistics 760 #if !defined(__CFA_NO_STATISTICS__) 761 void print_halts( processor & this ) { 762 this.print_halts = true; 763 } 764 765 void print_stats_now( cluster & this, int flags ) { 766 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 767 } 768 769 extern int __print_alarm_stats; 770 void print_alarm_stats() { 771 __print_alarm_stats = -1; 772 } 773 #endif 995 774 // Local Variables: // 996 775 // mode: c // -
libcfa/src/concurrency/kernel.hfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 4 07:54:51 201913 // Update Count : 1812 // Last Modified On : Tue Feb 4 12:29:26 2020 13 // Update Count : 22 14 14 // 15 15 16 16 #pragma once 17 18 #include <stdbool.h>19 17 20 18 #include "invoke.h" … … 22 20 #include "coroutine.hfa" 23 21 22 #include "containers/list.hfa" 23 24 24 extern "C" { 25 #include <pthread.h>26 #include <semaphore.h>25 #include <bits/pthreadtypes.h> 26 #include <linux/types.h> 27 27 } 28 28 … … 32 32 __spinlock_t lock; 33 33 int count; 34 __queue_t( thread_desc) waiting;34 __queue_t($thread) waiting; 35 35 }; 36 36 37 37 void ?{}(semaphore & this, int count = 1); 38 38 void ^?{}(semaphore & this); 39 void P (semaphore & this); 40 void V (semaphore & this); 39 bool P (semaphore & this); 40 bool V (semaphore & this); 41 bool V (semaphore & this, unsigned count); 41 42 42 43 … … 45 46 extern struct cluster * mainCluster; 46 47 47 enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule, Callback }; 48 49 typedef void (*__finish_callback_fptr_t)(void); 50 51 //TODO use union, many of these fields are mutually exclusive (i.e. MULTI vs NOMULTI) 52 struct FinishAction { 53 FinishOpCode action_code; 54 /* 55 // Union of possible actions 56 union { 57 // Option 1 : locks and threads 58 struct { 59 // 1 thread or N thread 60 union { 61 thread_desc * thrd; 62 struct { 63 thread_desc ** thrds; 64 unsigned short thrd_count; 65 }; 66 }; 67 // 1 lock or N lock 68 union { 69 __spinlock_t * lock; 70 struct { 71 __spinlock_t ** locks; 72 unsigned short lock_count; 73 }; 74 }; 75 }; 76 // Option 2 : action pointer 77 __finish_callback_fptr_t callback; 78 }; 79 /*/ 80 thread_desc * thrd; 81 thread_desc ** thrds; 82 unsigned short thrd_count; 83 __spinlock_t * lock; 84 __spinlock_t ** locks; 85 unsigned short lock_count; 86 __finish_callback_fptr_t callback; 87 //*/ 88 }; 89 static inline void ?{}(FinishAction & this) { 90 this.action_code = No_Action; 91 this.thrd = 0p; 92 this.lock = 0p; 93 } 94 static inline void ^?{}(FinishAction &) {} 95 96 // Processor 48 // Processor id, required for scheduling threads 49 struct __processor_id_t { 50 unsigned id:24; 51 bool full_proc:1; 52 53 #if !defined(__CFA_NO_STATISTICS__) 54 struct __stats_t * stats; 55 #endif 56 }; 57 97 58 coroutine processorCtx_t { 98 59 struct processor * proc; … … 100 61 101 62 // Wrapper around kernel threads 102 struct processor {63 struct __attribute__((aligned(128))) processor { 103 64 // Main state 65 inline __processor_id_t; 66 67 // Cluster from which to get threads 68 struct cluster * cltr; 69 70 // Set to true to notify the processor should terminate 71 volatile bool do_terminate; 72 104 73 // Coroutine ctx who does keeps the state of the processor 105 74 struct processorCtx_t runner; 106 75 107 // Cluster from which to get threads108 struct cluster * cltr;109 110 76 // Name of the processor 111 77 const char * name; … … 113 79 // Handle to pthreads 114 80 pthread_t kernel_thread; 115 116 // RunThread data117 // Action to do after a thread is ran118 struct FinishAction finish;119 81 120 82 // Preemption data … … 125 87 bool pending_preemption; 126 88 127 // Idle lock 128 __bin_sem_t idleLock; 129 130 // Termination 131 // Set to true to notify the processor should terminate 132 volatile bool do_terminate; 133 134 // Termination synchronisation 89 // Idle lock (kernel semaphore) 90 __bin_sem_t idle; 91 92 // Termination synchronisation (user semaphore) 135 93 semaphore terminated; 136 94 … … 139 97 140 98 // Link lists fields 141 struct __dbg_node_proc { 142 struct processor * next; 143 struct processor * prev; 144 } node; 99 DLISTED_MGD_IMPL_IN(processor) 100 101 #if !defined(__CFA_NO_STATISTICS__) 102 int print_stats; 103 bool print_halts; 104 #endif 145 105 146 106 #ifdef __CFA_DEBUG__ … … 150 110 }; 151 111 152 void ?{}(processor & this, const char * name, struct cluster & cltr);112 void ?{}(processor & this, const char name[], struct cluster & cltr); 153 113 void ^?{}(processor & this); 154 114 155 115 static inline void ?{}(processor & this) { this{ "Anonymous Processor", *mainCluster}; } 156 116 static inline void ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; } 157 static inline void ?{}(processor & this, const char * name) { this{name, *mainCluster }; } 158 159 static inline [processor *&, processor *& ] __get( processor & this ) { 160 return this.node.[next, prev]; 161 } 117 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster }; } 118 119 DLISTED_MGD_IMPL_OUT(processor) 120 121 //----------------------------------------------------------------------------- 122 // I/O 123 struct __io_data; 124 125 // IO poller user-thread 126 // Not using the "thread" keyword because we want to control 127 // more carefully when to start/stop it 128 struct $io_ctx_thread { 129 struct __io_data * ring; 130 single_sem sem; 131 volatile bool done; 132 $thread self; 133 }; 134 135 136 struct io_context { 137 $io_ctx_thread thrd; 138 }; 139 140 struct io_context_params { 141 int num_entries; 142 int num_ready; 143 int submit_aff; 144 bool eager_submits:1; 145 bool poller_submits:1; 146 bool poll_submit:1; 147 bool poll_complete:1; 148 }; 149 150 void ?{}(io_context_params & this); 151 152 void ?{}(io_context & this, struct cluster & cl); 153 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params); 154 void ^?{}(io_context & this); 155 156 struct io_cancellation { 157 __u64 target; 158 }; 159 160 static inline void ?{}(io_cancellation & this) { this.target = -1u; } 161 static inline void ^?{}(io_cancellation &) {} 162 bool cancel(io_cancellation & this); 163 164 //----------------------------------------------------------------------------- 165 // Cluster Tools 166 167 // Intrusives lanes which are used by the relaxed ready queue 168 struct __attribute__((aligned(128))) __intrusive_lane_t; 169 void ?{}(__intrusive_lane_t & this); 170 void ^?{}(__intrusive_lane_t & this); 171 172 // Counter used for wether or not the lanes are all empty 173 struct __attribute__((aligned(128))) __snzi_node_t; 174 struct __snzi_t { 175 unsigned mask; 176 int root; 177 __snzi_node_t * nodes; 178 }; 179 180 void ?{}( __snzi_t & this, unsigned depth ); 181 void ^?{}( __snzi_t & this ); 182 183 //TODO adjust cache size to ARCHITECTURE 184 // Structure holding the relaxed ready queue 185 struct __ready_queue_t { 186 // Data tracking how many/which lanes are used 187 // Aligned to 128 for cache locality 188 __snzi_t snzi; 189 190 // Data tracking the actual lanes 191 // On a seperate cacheline from the used struct since 192 // used can change on each push/pop but this data 193 // only changes on shrink/grow 194 struct { 195 // Arary of lanes 196 __intrusive_lane_t * volatile data; 197 198 // Number of lanes (empty or not) 199 volatile size_t count; 200 } lanes; 201 }; 202 203 void ?{}(__ready_queue_t & this); 204 void ^?{}(__ready_queue_t & this); 205 206 // Idle Sleep 207 struct __cluster_idles { 208 // Spin lock protecting the queue 209 volatile uint64_t lock; 210 211 // Total number of processors 212 unsigned total; 213 214 // Total number of idle processors 215 unsigned idle; 216 217 // List of idle processors 218 dlist(processor, processor) list; 219 }; 162 220 163 221 //----------------------------------------------------------------------------- 164 222 // Cluster 165 struct cluster { 166 // Ready queue locks 167 __spinlock_t ready_queue_lock; 168 223 struct __attribute__((aligned(128))) cluster { 169 224 // Ready queue for threads 170 __ queue_t(thread_desc)ready_queue;225 __ready_queue_t ready_queue; 171 226 172 227 // Name of the cluster … … 176 231 Duration preemption_rate; 177 232 178 // List of processors 179 __spinlock_t proc_list_lock; 180 __dllist_t(struct processor) procs; 181 __dllist_t(struct processor) idles; 182 unsigned int nprocessors; 233 // List of idle processors 234 __cluster_idles idles; 183 235 184 236 // List of threads 185 237 __spinlock_t thread_list_lock; 186 __dllist_t(struct thread_desc) threads;238 __dllist_t(struct $thread) threads; 187 239 unsigned int nthreads; 188 240 … … 192 244 cluster * prev; 193 245 } node; 246 247 struct { 248 io_context * ctxs; 249 unsigned cnt; 250 } io; 251 252 #if !defined(__CFA_NO_STATISTICS__) 253 struct __stats_t * stats; 254 int print_stats; 255 #endif 194 256 }; 195 257 extern Duration default_preemption(); 196 258 197 void ?{} (cluster & this, const char * name, Duration preemption_rate);259 void ?{} (cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params); 198 260 void ^?{}(cluster & this); 199 261 200 static inline void ?{} (cluster & this) { this{"Anonymous Cluster", default_preemption()}; } 201 static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; } 202 static inline void ?{} (cluster & this, const char * name) { this{name, default_preemption()}; } 203 204 static inline [cluster *&, cluster *& ] __get( cluster & this ) { 205 return this.node.[next, prev]; 206 } 207 208 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 209 static inline struct cluster * active_cluster () { return TL_GET( this_processor )->cltr; } 262 static inline void ?{} (cluster & this) { io_context_params default_params; this{"Anonymous Cluster", default_preemption(), 1, default_params}; } 263 static inline void ?{} (cluster & this, Duration preemption_rate) { io_context_params default_params; this{"Anonymous Cluster", preemption_rate, 1, default_params}; } 264 static inline void ?{} (cluster & this, const char name[]) { io_context_params default_params; this{name, default_preemption(), 1, default_params}; } 265 static inline void ?{} (cluster & this, unsigned num_io) { io_context_params default_params; this{"Anonymous Cluster", default_preemption(), num_io, default_params}; } 266 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io) { io_context_params default_params; this{"Anonymous Cluster", preemption_rate, num_io, default_params}; } 267 static inline void ?{} (cluster & this, const char name[], unsigned num_io) { io_context_params default_params; this{name, default_preemption(), num_io, default_params}; } 268 static inline void ?{} (cluster & this, const io_context_params & io_params) { this{"Anonymous Cluster", default_preemption(), 1, io_params}; } 269 static inline void ?{} (cluster & this, Duration preemption_rate, const io_context_params & io_params) { this{"Anonymous Cluster", preemption_rate, 1, io_params}; } 270 static inline void ?{} (cluster & this, const char name[], const io_context_params & io_params) { this{name, default_preemption(), 1, io_params}; } 271 static inline void ?{} (cluster & this, unsigned num_io, const io_context_params & io_params) { this{"Anonymous Cluster", default_preemption(), num_io, io_params}; } 272 static inline void ?{} (cluster & this, Duration preemption_rate, unsigned num_io, const io_context_params & io_params) { this{"Anonymous Cluster", preemption_rate, num_io, io_params}; } 273 static inline void ?{} (cluster & this, const char name[], unsigned num_io, const io_context_params & io_params) { this{name, default_preemption(), num_io, io_params}; } 274 275 static inline [cluster *&, cluster *& ] __get( cluster & this ) __attribute__((const)) { return this.node.[next, prev]; } 276 277 static inline struct processor * active_processor() { return publicTLS_get( this_processor ); } // UNSAFE 278 static inline struct cluster * active_cluster () { return publicTLS_get( this_processor )->cltr; } 279 280 #if !defined(__CFA_NO_STATISTICS__) 281 void print_stats_now( cluster & this, int flags ); 282 283 static inline void print_stats_at_exit( cluster & this, int flags ) { 284 this.print_stats |= flags; 285 } 286 287 static inline void print_stats_at_exit( processor & this, int flags ) { 288 this.print_stats |= flags; 289 } 290 291 void print_halts( processor & this ); 292 #endif 210 293 211 294 // Local Variables: // -
libcfa/src/concurrency/kernel_private.hfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Feb 13 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Nov 30 19:25:02 201913 // Update Count : 812 // Last Modified On : Wed Aug 12 08:21:33 2020 13 // Update Count : 9 14 14 // 15 15 … … 20 20 21 21 #include "alarm.hfa" 22 22 #include "stats.hfa" 23 23 24 24 //----------------------------------------------------------------------------- 25 25 // Scheduler 26 27 struct __attribute__((aligned(128))) __scheduler_lock_id_t; 26 28 27 29 extern "C" { … … 31 33 } 32 34 33 void ScheduleThread( thread_desc * ); 34 static inline void WakeThread( thread_desc * thrd ) { 35 if( !thrd ) return; 36 37 verify(thrd->state == Inactive); 38 39 disable_interrupts(); 40 ScheduleThread( thrd ); 41 enable_interrupts( __cfaabi_dbg_ctx ); 42 } 43 thread_desc * nextThread(cluster * this); 44 45 //Block current thread and release/wake-up the following resources 46 void BlockInternal(void); 47 void BlockInternal(__spinlock_t * lock); 48 void BlockInternal(thread_desc * thrd); 49 void BlockInternal(__spinlock_t * lock, thread_desc * thrd); 50 void BlockInternal(__spinlock_t * locks [], unsigned short count); 51 void BlockInternal(__spinlock_t * locks [], unsigned short count, thread_desc * thrds [], unsigned short thrd_count); 52 void BlockInternal(__finish_callback_fptr_t callback); 53 void LeaveThread(__spinlock_t * lock, thread_desc * thrd); 35 void __schedule_thread( $thread * ) 36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__)) 37 __attribute__((nonnull (1))) 38 #endif 39 ; 40 41 extern bool __preemption_enabled(); 42 43 //release/wake-up the following resources 44 void __thread_finish( $thread * thrd ); 54 45 55 46 //----------------------------------------------------------------------------- … … 57 48 void main(processorCtx_t *); 58 49 59 void * create_pthread( pthread_t *, void * (*)(void *), void * ); 60 61 static inline void wake_fast(processor * this) { 62 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this); 63 post( this->idleLock ); 64 } 65 66 static inline void wake(processor * this) { 67 disable_interrupts(); 68 wake_fast(this); 69 enable_interrupts( __cfaabi_dbg_ctx ); 70 } 71 72 struct event_kernel_t { 73 alarm_list_t alarms; 74 __spinlock_t lock; 75 }; 76 77 extern event_kernel_t * event_kernel; 78 79 struct __cfa_kernel_preemption_state_t { 80 bool enabled; 81 bool in_progress; 82 unsigned short disable_count; 83 }; 84 85 extern volatile thread_local __cfa_kernel_preemption_state_t preemption_state __attribute__ ((tls_model ( "initial-exec" ))); 50 void * __create_pthread( pthread_t *, void * (*)(void *), void * ); 51 void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ); 52 53 54 55 extern cluster * mainCluster; 86 56 87 57 //----------------------------------------------------------------------------- 88 58 // Threads 89 59 extern "C" { 90 void CtxInvokeThread(void (*main)(void *), void * this); 91 } 92 93 extern void ThreadCtxSwitch(coroutine_desc * src, coroutine_desc * dst); 60 void __cfactx_invoke_thread(void (*main)(void *), void * this); 61 } 94 62 95 63 __cfaabi_dbg_debug_do( 96 extern void __cfaabi_dbg_thread_register ( thread_desc* thrd );97 extern void __cfaabi_dbg_thread_unregister( thread_desc* thrd );64 extern void __cfaabi_dbg_thread_register ( $thread * thrd ); 65 extern void __cfaabi_dbg_thread_unregister( $thread * thrd ); 98 66 ) 99 67 68 #define TICKET_BLOCKED (-1) // thread is blocked 69 #define TICKET_RUNNING ( 0) // thread is running 70 #define TICKET_UNBLOCK ( 1) // thread should ignore next block 71 100 72 //----------------------------------------------------------------------------- 101 73 // Utils 102 #define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)] 103 104 static inline uint32_t tls_rand() { 105 kernelTLS.rand_seed ^= kernelTLS.rand_seed << 6; 106 kernelTLS.rand_seed ^= kernelTLS.rand_seed >> 21; 107 kernelTLS.rand_seed ^= kernelTLS.rand_seed << 7; 108 return kernelTLS.rand_seed; 109 } 110 111 112 void doregister( struct cluster & cltr ); 113 void unregister( struct cluster & cltr ); 114 115 void doregister( struct cluster * cltr, struct thread_desc & thrd ); 116 void unregister( struct cluster * cltr, struct thread_desc & thrd ); 117 118 void doregister( struct cluster * cltr, struct processor * proc ); 119 void unregister( struct cluster * cltr, struct processor * proc ); 74 void doregister( struct cluster * cltr, struct $thread & thrd ); 75 void unregister( struct cluster * cltr, struct $thread & thrd ); 76 77 //----------------------------------------------------------------------------- 78 // I/O 79 void ^?{}(io_context & this, bool ); 80 81 //======================================================================= 82 // Cluster lock API 83 //======================================================================= 84 // Cells use by the reader writer lock 85 // while not generic it only relies on a opaque pointer 86 struct __attribute__((aligned(128))) __scheduler_lock_id_t { 87 // Spin lock used as the underlying lock 88 volatile bool lock; 89 90 // Handle pointing to the proc owning this cell 91 // Used for allocating cells and debugging 92 __processor_id_t * volatile handle; 93 94 #ifdef __CFA_WITH_VERIFY__ 95 // Debug, check if this is owned for reading 96 bool owned; 97 #endif 98 }; 99 100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t)); 101 102 // Lock-Free registering/unregistering of threads 103 // Register a processor to a given cluster and get its unique id in return 104 unsigned doregister( struct __processor_id_t * proc ); 105 106 // Unregister a processor from a given cluster using its id, getting back the original pointer 107 void unregister( struct __processor_id_t * proc ); 108 109 //----------------------------------------------------------------------- 110 // Cluster idle lock/unlock 111 static inline void lock(__cluster_idles & this) { 112 for() { 113 uint64_t l = this.lock; 114 if( 115 (0 == (l % 2)) 116 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 117 ) return; 118 Pause(); 119 } 120 } 121 122 static inline void unlock(__cluster_idles & this) { 123 /* paranoid */ verify( 1 == (this.lock % 2) ); 124 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 125 } 126 127 //======================================================================= 128 // Reader-writer lock implementation 129 // Concurrent with doregister/unregister, 130 // i.e., threads can be added at any point during or between the entry/exit 131 132 //----------------------------------------------------------------------- 133 // simple spinlock underlying the RWLock 134 // Blocking acquire 135 static inline void __atomic_acquire(volatile bool * ll) { 136 while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) { 137 while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED)) 138 Pause(); 139 } 140 /* paranoid */ verify(*ll); 141 } 142 143 // Non-Blocking acquire 144 static inline bool __atomic_try_acquire(volatile bool * ll) { 145 return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST); 146 } 147 148 // Release 149 static inline void __atomic_unlock(volatile bool * ll) { 150 /* paranoid */ verify(*ll); 151 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 152 } 153 154 //----------------------------------------------------------------------- 155 // Reader-Writer lock protecting the ready-queues 156 // while this lock is mostly generic some aspects 157 // have been hard-coded to for the ready-queue for 158 // simplicity and performance 159 struct __scheduler_RWLock_t { 160 // total cachelines allocated 161 unsigned int max; 162 163 // cachelines currently in use 164 volatile unsigned int alloc; 165 166 // cachelines ready to itereate over 167 // (!= to alloc when thread is in second half of doregister) 168 volatile unsigned int ready; 169 170 // writer lock 171 volatile bool lock; 172 173 // data pointer 174 __scheduler_lock_id_t * data; 175 }; 176 177 void ?{}(__scheduler_RWLock_t & this); 178 void ^?{}(__scheduler_RWLock_t & this); 179 180 extern __scheduler_RWLock_t * __scheduler_lock; 181 182 //----------------------------------------------------------------------- 183 // Reader side : acquire when using the ready queue to schedule but not 184 // creating/destroying queues 185 static inline void ready_schedule_lock(void) with(*__scheduler_lock) { 186 /* paranoid */ verify( ! __preemption_enabled() ); 187 /* paranoid */ verify( kernelTLS().this_proc_id ); 188 189 unsigned iproc = kernelTLS().this_proc_id->id; 190 /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id); 191 /*paranoid*/ verify(iproc < ready); 192 193 // Step 1 : make sure no writer are in the middle of the critical section 194 while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED)) 195 Pause(); 196 197 // Fence needed because we don't want to start trying to acquire the lock 198 // before we read a false. 199 // Not needed on x86 200 // std::atomic_thread_fence(std::memory_order_seq_cst); 201 202 // Step 2 : acquire our local lock 203 __atomic_acquire( &data[iproc].lock ); 204 /*paranoid*/ verify(data[iproc].lock); 205 206 #ifdef __CFA_WITH_VERIFY__ 207 // Debug, check if this is owned for reading 208 data[iproc].owned = true; 209 #endif 210 } 211 212 static inline void ready_schedule_unlock(void) with(*__scheduler_lock) { 213 /* paranoid */ verify( ! __preemption_enabled() ); 214 /* paranoid */ verify( kernelTLS().this_proc_id ); 215 216 unsigned iproc = kernelTLS().this_proc_id->id; 217 /*paranoid*/ verify(data[iproc].handle == kernelTLS().this_proc_id); 218 /*paranoid*/ verify(iproc < ready); 219 /*paranoid*/ verify(data[iproc].lock); 220 /*paranoid*/ verify(data[iproc].owned); 221 #ifdef __CFA_WITH_VERIFY__ 222 // Debug, check if this is owned for reading 223 data[iproc].owned = false; 224 #endif 225 __atomic_unlock(&data[iproc].lock); 226 } 227 228 #ifdef __CFA_WITH_VERIFY__ 229 static inline bool ready_schedule_islocked(void) { 230 /* paranoid */ verify( ! __preemption_enabled() ); 231 /*paranoid*/ verify( kernelTLS().this_proc_id ); 232 __processor_id_t * proc = kernelTLS().this_proc_id; 233 return __scheduler_lock->data[proc->id].owned; 234 } 235 236 static inline bool ready_mutate_islocked() { 237 return __scheduler_lock->lock; 238 } 239 #endif 240 241 //----------------------------------------------------------------------- 242 // Writer side : acquire when changing the ready queue, e.g. adding more 243 // queues or removing them. 244 uint_fast32_t ready_mutate_lock( void ); 245 246 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ ); 247 248 //======================================================================= 249 // Ready-Queue API 250 //----------------------------------------------------------------------- 251 // pop thread from the ready queue of a cluster 252 // returns 0p if empty 253 __attribute__((hot)) bool query(struct cluster * cltr); 254 255 //----------------------------------------------------------------------- 256 // push thread onto a ready queue for a cluster 257 // returns true if the list was previously empty, false otherwise 258 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd); 259 260 //----------------------------------------------------------------------- 261 // pop thread from the ready queue of a cluster 262 // returns 0p if empty 263 // May return 0p spuriously 264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 265 266 //----------------------------------------------------------------------- 267 // pop thread from the ready queue of a cluster 268 // returns 0p if empty 269 // guaranteed to find any threads added before this call 270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 271 272 //----------------------------------------------------------------------- 273 // remove thread from the ready queue of a cluster 274 // returns bool if it wasn't found 275 bool remove_head(struct cluster * cltr, struct $thread * thrd); 276 277 //----------------------------------------------------------------------- 278 // Increase the width of the ready queue (number of lanes) by 4 279 void ready_queue_grow (struct cluster * cltr, int target); 280 281 //----------------------------------------------------------------------- 282 // Decrease the width of the ready queue (number of lanes) by 4 283 void ready_queue_shrink(struct cluster * cltr, int target); 284 120 285 121 286 // Local Variables: // -
libcfa/src/concurrency/monitor.cfa
rbdfc032 reef8dfb 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // monitor_desc.c --7 // $monitor.c -- 8 8 // 9 9 // Author : Thierry Delisle … … 27 27 //----------------------------------------------------------------------------- 28 28 // Forward declarations 29 static inline void set_owner ( monitor_desc * this, thread_desc* owner );30 static inline void set_owner ( monitor_desc * storage [], __lock_size_t count, thread_desc* owner );31 static inline void set_mask ( monitor_desc* storage [], __lock_size_t count, const __waitfor_mask_t & mask );32 static inline void reset_mask( monitor_desc* this );33 34 static inline thread_desc * next_thread( monitor_desc* this );35 static inline bool is_accepted( monitor_desc* this, const __monitor_group_t & monitors );29 static inline void __set_owner ( $monitor * this, $thread * owner ); 30 static inline void __set_owner ( $monitor * storage [], __lock_size_t count, $thread * owner ); 31 static inline void set_mask ( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask ); 32 static inline void reset_mask( $monitor * this ); 33 34 static inline $thread * next_thread( $monitor * this ); 35 static inline bool is_accepted( $monitor * this, const __monitor_group_t & monitors ); 36 36 37 37 static inline void lock_all ( __spinlock_t * locks [], __lock_size_t count ); 38 static inline void lock_all ( monitor_desc* source [], __spinlock_t * /*out*/ locks [], __lock_size_t count );38 static inline void lock_all ( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ); 39 39 static inline void unlock_all( __spinlock_t * locks [], __lock_size_t count ); 40 static inline void unlock_all( monitor_desc* locks [], __lock_size_t count );41 42 static inline void save ( monitor_desc* ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] );43 static inline void restore( monitor_desc* ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] );44 45 static inline void init ( __lock_size_t count, monitor_desc* monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );46 static inline void init_push( __lock_size_t count, monitor_desc* monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] );47 48 static inline thread_desc* check_condition ( __condition_criterion_t * );40 static inline void unlock_all( $monitor * locks [], __lock_size_t count ); 41 42 static inline void save ( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*out*/ recursions [], __waitfor_mask_t /*out*/ masks [] ); 43 static inline void restore( $monitor * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] ); 44 45 static inline void init ( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); 46 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); 47 48 static inline $thread * check_condition ( __condition_criterion_t * ); 49 49 static inline void brand_condition ( condition & ); 50 static inline [ thread_desc *, int] search_entry_queue( const __waitfor_mask_t &, monitor_desc* monitors [], __lock_size_t count );50 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t &, $monitor * monitors [], __lock_size_t count ); 51 51 52 52 forall(dtype T | sized( T )) 53 53 static inline __lock_size_t insert_unique( T * array [], __lock_size_t & size, T * val ); 54 54 static inline __lock_size_t count_max ( const __waitfor_mask_t & mask ); 55 static inline __lock_size_t aggregate ( monitor_desc* storage [], const __waitfor_mask_t & mask );55 static inline __lock_size_t aggregate ( $monitor * storage [], const __waitfor_mask_t & mask ); 56 56 57 57 //----------------------------------------------------------------------------- … … 68 68 69 69 #define monitor_ctx( mons, cnt ) /* Define that create the necessary struct for internal/external scheduling operations */ \ 70 monitor_desc** monitors = mons; /* Save the targeted monitors */ \70 $monitor ** monitors = mons; /* Save the targeted monitors */ \ 71 71 __lock_size_t count = cnt; /* Save the count to a local variable */ \ 72 72 unsigned int recursions[ count ]; /* Save the current recursion levels to restore them later */ \ … … 80 80 //----------------------------------------------------------------------------- 81 81 // Enter/Leave routines 82 83 84 extern "C" { 85 // Enter single monitor 86 static void __enter_monitor_desc( monitor_desc * this, const __monitor_group_t & group ) { 87 // Lock the monitor spinlock 88 lock( this->lock __cfaabi_dbg_ctx2 ); 89 // Interrupts disable inside critical section 90 thread_desc * thrd = kernelTLS.this_thread; 91 92 __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner); 93 94 if( !this->owner ) { 95 // No one has the monitor, just take it 96 set_owner( this, thrd ); 97 98 __cfaabi_dbg_print_safe( "Kernel : mon is free \n" ); 99 } 100 else if( this->owner == thrd) { 101 // We already have the monitor, just note how many times we took it 102 this->recursion += 1; 103 104 __cfaabi_dbg_print_safe( "Kernel : mon already owned \n" ); 105 } 106 else if( is_accepted( this, group) ) { 107 // Some one was waiting for us, enter 108 set_owner( this, thrd ); 109 110 // Reset mask 111 reset_mask( this ); 112 113 __cfaabi_dbg_print_safe( "Kernel : mon accepts \n" ); 114 } 115 else { 116 __cfaabi_dbg_print_safe( "Kernel : blocking \n" ); 117 118 // Some one else has the monitor, wait in line for it 119 append( this->entry_queue, thrd ); 120 121 BlockInternal( &this->lock ); 122 123 __cfaabi_dbg_print_safe( "Kernel : %10p Entered mon %p\n", thrd, this); 124 125 // BlockInternal will unlock spinlock, no need to unlock ourselves 126 return; 127 } 82 // Enter single monitor 83 static void __enter( $monitor * this, const __monitor_group_t & group ) { 84 $thread * thrd = active_thread(); 85 86 // Lock the monitor spinlock 87 lock( this->lock __cfaabi_dbg_ctx2 ); 88 89 __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner); 90 91 if( unlikely(0 != (0x1 & (uintptr_t)this->owner)) ) { 92 abort( "Attempt by thread \"%.256s\" (%p) to access joined monitor %p.", thrd->self_cor.name, thrd, this ); 93 } 94 else if( !this->owner ) { 95 // No one has the monitor, just take it 96 __set_owner( this, thrd ); 97 98 __cfaabi_dbg_print_safe( "Kernel : mon is free \n" ); 99 } 100 else if( this->owner == thrd) { 101 // We already have the monitor, just note how many times we took it 102 this->recursion += 1; 103 104 __cfaabi_dbg_print_safe( "Kernel : mon already owned \n" ); 105 } 106 else if( is_accepted( this, group) ) { 107 // Some one was waiting for us, enter 108 __set_owner( this, thrd ); 109 110 // Reset mask 111 reset_mask( this ); 112 113 __cfaabi_dbg_print_safe( "Kernel : mon accepts \n" ); 114 } 115 else { 116 __cfaabi_dbg_print_safe( "Kernel : blocking \n" ); 117 118 // Some one else has the monitor, wait in line for it 119 /* paranoid */ verify( thrd->link.next == 0p ); 120 append( this->entry_queue, thrd ); 121 /* paranoid */ verify( thrd->link.next == 1p ); 122 123 unlock( this->lock ); 124 park(); 128 125 129 126 __cfaabi_dbg_print_safe( "Kernel : %10p Entered mon %p\n", thrd, this); 130 127 131 // Release the lock and leave 128 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 129 return; 130 } 131 132 __cfaabi_dbg_print_safe( "Kernel : %10p Entered mon %p\n", thrd, this); 133 134 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 135 /* paranoid */ verify( this->lock.lock ); 136 137 // Release the lock and leave 138 unlock( this->lock ); 139 return; 140 } 141 142 static void __dtor_enter( $monitor * this, fptr_t func, bool join ) { 143 $thread * thrd = active_thread(); 144 #if defined( __CFA_WITH_VERIFY__ ) 145 bool is_thrd = this == &thrd->self_mon; 146 #endif 147 148 // Lock the monitor spinlock 149 lock( this->lock __cfaabi_dbg_ctx2 ); 150 151 __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner); 152 153 154 if( !this->owner ) { 155 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this); 156 157 // No one has the monitor, just take it 158 __set_owner( this, thrd ); 159 160 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 161 /* paranoid */ verify( !is_thrd || thrd->state == Halted || thrd->state == Cancelled ); 162 132 163 unlock( this->lock ); 133 164 return; 134 165 } 135 136 static void __enter_monitor_dtor( monitor_desc * this, fptr_t func ) { 137 // Lock the monitor spinlock 138 lock( this->lock __cfaabi_dbg_ctx2 ); 139 // Interrupts disable inside critical section 140 thread_desc * thrd = kernelTLS.this_thread; 141 142 __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner); 143 144 145 if( !this->owner ) { 146 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this); 147 148 // No one has the monitor, just take it 149 set_owner( this, thrd ); 150 151 unlock( this->lock ); 152 return; 166 else if( this->owner == thrd && !join) { 167 // We already have the monitor... but where about to destroy it so the nesting will fail 168 // Abort! 169 abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd ); 170 } 171 // SKULLDUGGERY: join will act as a dtor so it would normally trigger to above check 172 // because join will not release the monitor after it executed. 173 // to avoid that it sets the owner to the special value thrd | 1p before exiting 174 else if( this->owner == ($thread*)(1 | (uintptr_t)thrd) ) { 175 // restore the owner and just return 176 __cfaabi_dbg_print_safe( "Kernel : Destroying free mon %p\n", this); 177 178 // No one has the monitor, just take it 179 __set_owner( this, thrd ); 180 181 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 182 /* paranoid */ verify( !is_thrd || thrd->state == Halted || thrd->state == Cancelled ); 183 184 unlock( this->lock ); 185 return; 186 } 187 188 // The monitor is busy, if this is a thread and the thread owns itself, it better be active 189 /* paranoid */ verify( !is_thrd || this->owner != thrd || (thrd->state != Halted && thrd->state != Cancelled) ); 190 191 __lock_size_t count = 1; 192 $monitor ** monitors = &this; 193 __monitor_group_t group = { &this, 1, func }; 194 if( is_accepted( this, group) ) { 195 __cfaabi_dbg_print_safe( "Kernel : mon accepts dtor, block and signal it \n" ); 196 197 // Wake the thread that is waiting for this 198 __condition_criterion_t * urgent = pop( this->signal_stack ); 199 /* paranoid */ verify( urgent ); 200 201 // Reset mask 202 reset_mask( this ); 203 204 // Create the node specific to this wait operation 205 wait_ctx_primed( thrd, 0 ) 206 207 // Some one else has the monitor, wait for him to finish and then run 208 unlock( this->lock ); 209 210 // Release the next thread 211 /* paranoid */ verifyf( urgent->owner->waiting_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 212 unpark( urgent->owner->waiting_thread ); 213 214 // Park current thread waiting 215 park(); 216 217 // Some one was waiting for us, enter 218 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 219 220 __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this); 221 return; 222 } 223 else { 224 __cfaabi_dbg_print_safe( "Kernel : blocking \n" ); 225 226 wait_ctx( thrd, 0 ) 227 this->dtor_node = &waiter; 228 229 // Some one else has the monitor, wait in line for it 230 /* paranoid */ verify( thrd->link.next == 0p ); 231 append( this->entry_queue, thrd ); 232 /* paranoid */ verify( thrd->link.next == 1p ); 233 unlock( this->lock ); 234 235 // Park current thread waiting 236 park(); 237 238 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 239 return; 240 } 241 } 242 243 // Leave single monitor 244 void __leave( $monitor * this ) { 245 // Lock the monitor spinlock 246 lock( this->lock __cfaabi_dbg_ctx2 ); 247 248 __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", active_thread(), this, this->owner); 249 250 /* paranoid */ verifyf( active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 251 252 // Leaving a recursion level, decrement the counter 253 this->recursion -= 1; 254 255 // If we haven't left the last level of recursion 256 // it means we don't need to do anything 257 if( this->recursion != 0) { 258 __cfaabi_dbg_print_safe( "Kernel : recursion still %d\n", this->recursion); 259 unlock( this->lock ); 260 return; 261 } 262 263 // Get the next thread, will be null on low contention monitor 264 $thread * new_owner = next_thread( this ); 265 266 // Check the new owner is consistent with who we wake-up 267 // new_owner might be null even if someone owns the monitor when the owner is still waiting for another monitor 268 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 269 270 // We can now let other threads in safely 271 unlock( this->lock ); 272 273 //We need to wake-up the thread 274 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 275 unpark( new_owner ); 276 } 277 278 // Leave single monitor for the last time 279 void __dtor_leave( $monitor * this, bool join ) { 280 __cfaabi_dbg_debug_do( 281 if( active_thread() != this->owner ) { 282 abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, active_thread(), this->owner); 153 283 } 154 else if( this->owner == thrd) { 155 // We already have the monitor... but where about to destroy it so the nesting will fail 156 // Abort! 157 abort( "Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.", this, thrd->self_cor.name, thrd ); 284 if( this->recursion != 1 && !join ) { 285 abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1); 158 286 } 159 160 __lock_size_t count = 1; 161 monitor_desc ** monitors = &this; 162 __monitor_group_t group = { &this, 1, func }; 163 if( is_accepted( this, group) ) { 164 __cfaabi_dbg_print_safe( "Kernel : mon accepts dtor, block and signal it \n" ); 165 166 // Wake the thread that is waiting for this 167 __condition_criterion_t * urgent = pop( this->signal_stack ); 168 verify( urgent ); 169 170 // Reset mask 171 reset_mask( this ); 172 173 // Create the node specific to this wait operation 174 wait_ctx_primed( thrd, 0 ) 175 176 // Some one else has the monitor, wait for him to finish and then run 177 BlockInternal( &this->lock, urgent->owner->waiting_thread ); 178 179 // Some one was waiting for us, enter 180 set_owner( this, thrd ); 181 } 182 else { 183 __cfaabi_dbg_print_safe( "Kernel : blocking \n" ); 184 185 wait_ctx( thrd, 0 ) 186 this->dtor_node = &waiter; 187 188 // Some one else has the monitor, wait in line for it 189 append( this->entry_queue, thrd ); 190 BlockInternal( &this->lock ); 191 192 // BlockInternal will unlock spinlock, no need to unlock ourselves 193 return; 194 } 195 196 __cfaabi_dbg_print_safe( "Kernel : Destroying %p\n", this); 197 198 } 199 200 // Leave single monitor 201 void __leave_monitor_desc( monitor_desc * this ) { 202 // Lock the monitor spinlock 203 lock( this->lock __cfaabi_dbg_ctx2 ); 204 205 __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner); 206 207 verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this ); 208 209 // Leaving a recursion level, decrement the counter 210 this->recursion -= 1; 211 212 // If we haven't left the last level of recursion 213 // it means we don't need to do anything 214 if( this->recursion != 0) { 215 __cfaabi_dbg_print_safe( "Kernel : recursion still %d\n", this->recursion); 216 unlock( this->lock ); 217 return; 218 } 219 220 // Get the next thread, will be null on low contention monitor 221 thread_desc * new_owner = next_thread( this ); 222 223 // We can now let other threads in safely 224 unlock( this->lock ); 225 226 //We need to wake-up the thread 227 WakeThread( new_owner ); 228 } 229 230 // Leave single monitor for the last time 231 void __leave_dtor_monitor_desc( monitor_desc * this ) { 232 __cfaabi_dbg_debug_do( 233 if( TL_GET( this_thread ) != this->owner ) { 234 abort( "Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, TL_GET( this_thread ), this->owner); 235 } 236 if( this->recursion != 1 ) { 237 abort( "Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1); 238 } 239 ) 240 } 241 242 // Leave the thread monitor 243 // last routine called by a thread. 244 // Should never return 245 void __leave_thread_monitor() { 246 thread_desc * thrd = TL_GET( this_thread ); 247 monitor_desc * this = &thrd->self_mon; 248 249 // Lock the monitor now 250 lock( this->lock __cfaabi_dbg_ctx2 ); 251 252 disable_interrupts(); 253 254 thrd->self_cor.state = Halted; 255 256 verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 257 258 // Leaving a recursion level, decrement the counter 259 this->recursion -= 1; 260 261 // If we haven't left the last level of recursion 262 // it must mean there is an error 263 if( this->recursion != 0) { abort( "Thread internal monitor has unbalanced recursion" ); } 264 265 // Fetch the next thread, can be null 266 thread_desc * new_owner = next_thread( this ); 267 268 // Leave the thread, this will unlock the spinlock 269 // Use leave thread instead of BlockInternal which is 270 // specialized for this case and supports null new_owner 271 LeaveThread( &this->lock, new_owner ); 272 273 // Control flow should never reach here! 274 } 287 ) 288 289 this->owner = ($thread*)(1 | (uintptr_t)this->owner); 290 } 291 292 void __thread_finish( $thread * thrd ) { 293 $monitor * this = &thrd->self_mon; 294 295 // Lock the monitor now 296 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 297 /* paranoid */ verify( this->lock.lock ); 298 /* paranoid */ verify( thrd->context.SP ); 299 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : $thread %p has been corrupted.\n StackPointer too large.\n", thrd ); 300 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : $thread %p has been corrupted.\n StackPointer too small.\n", thrd ); 301 /* paranoid */ verify( ! __preemption_enabled() ); 302 303 /* paranoid */ verifyf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", thrd, this->owner, this->recursion, this ); 304 /* paranoid */ verify( thrd->state == Halting ); 305 /* paranoid */ verify( this->recursion == 1 ); 306 307 // Leaving a recursion level, decrement the counter 308 this->recursion -= 1; 309 this->owner = 0p; 310 311 // Fetch the next thread, can be null 312 $thread * new_owner = next_thread( this ); 313 314 // Mark the state as fully halted 315 thrd->state = Halted; 316 317 // Release the monitor lock 318 unlock( this->lock ); 319 320 // Unpark the next owner if needed 321 /* paranoid */ verifyf( !new_owner || new_owner == this->owner, "Expected owner to be %p, got %p (m: %p)", new_owner, this->owner, this ); 322 /* paranoid */ verify( ! __preemption_enabled() ); 323 /* paranoid */ verify( thrd->state == Halted ); 324 unpark( new_owner ); 275 325 } 276 326 … … 279 329 static inline void enter( __monitor_group_t monitors ) { 280 330 for( __lock_size_t i = 0; i < monitors.size; i++) { 281 __enter _monitor_desc( monitors[i], monitors );331 __enter( monitors[i], monitors ); 282 332 } 283 333 } … … 285 335 // Leave multiple monitor 286 336 // relies on the monitor array being sorted 287 static inline void leave( monitor_desc* monitors [], __lock_size_t count) {337 static inline void leave($monitor * monitors [], __lock_size_t count) { 288 338 for( __lock_size_t i = count - 1; i >= 0; i--) { 289 __leave _monitor_desc( monitors[i] );339 __leave( monitors[i] ); 290 340 } 291 341 } … … 293 343 // Ctor for monitor guard 294 344 // Sorts monitors before entering 295 void ?{}( monitor_guard_t & this, monitor_desc* m [], __lock_size_t count, fptr_t func ) {296 thread_desc * thrd = TL_GET( this_thread);345 void ?{}( monitor_guard_t & this, $monitor * m [], __lock_size_t count, fptr_t func ) { 346 $thread * thrd = active_thread(); 297 347 298 348 // Store current array … … 329 379 330 380 // Restore thread context 331 TL_GET( this_thread)->monitors = this.prev;381 active_thread()->monitors = this.prev; 332 382 } 333 383 334 384 // Ctor for monitor guard 335 385 // Sorts monitors before entering 336 void ?{}( monitor_dtor_guard_t & this, monitor_desc * m [], fptr_t func) {386 void ?{}( monitor_dtor_guard_t & this, $monitor * m [], fptr_t func, bool join ) { 337 387 // optimization 338 thread_desc * thrd = TL_GET( this_thread);388 $thread * thrd = active_thread(); 339 389 340 390 // Store current array … … 344 394 this.prev = thrd->monitors; 345 395 396 // Save whether we are in a join or not 397 this.join = join; 398 346 399 // Update thread context (needed for conditions) 347 400 (thrd->monitors){m, 1, func}; 348 401 349 __ enter_monitor_dtor( this.m, func);402 __dtor_enter( this.m, func, join ); 350 403 } 351 404 … … 353 406 void ^?{}( monitor_dtor_guard_t & this ) { 354 407 // Leave the monitors in order 355 __ leave_dtor_monitor_desc( this.m);408 __dtor_leave( this.m, this.join ); 356 409 357 410 // Restore thread context 358 TL_GET( this_thread)->monitors = this.prev;411 active_thread()->monitors = this.prev; 359 412 } 360 413 361 414 //----------------------------------------------------------------------------- 362 415 // Internal scheduling types 363 void ?{}(__condition_node_t & this, thread_desc* waiting_thread, __lock_size_t count, uintptr_t user_info ) {416 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info ) { 364 417 this.waiting_thread = waiting_thread; 365 418 this.count = count; … … 375 428 } 376 429 377 void ?{}(__condition_criterion_t & this, monitor_desc* target, __condition_node_t & owner ) {430 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t & owner ) { 378 431 this.ready = false; 379 432 this.target = target; … … 396 449 397 450 // Create the node specific to this wait operation 398 wait_ctx( TL_GET( this_thread), user_info );451 wait_ctx( active_thread(), user_info ); 399 452 400 453 // Append the current wait operation to the ones already queued on the condition 401 454 // We don't need locks for that since conditions must always be waited on inside monitor mutual exclusion 455 /* paranoid */ verify( waiter.next == 0p ); 402 456 append( this.blocked, &waiter ); 457 /* paranoid */ verify( waiter.next == 1p ); 403 458 404 459 // Lock all monitors (aggregates the locks as well) … … 407 462 // Find the next thread(s) to run 408 463 __lock_size_t thread_count = 0; 409 thread_desc* threads[ count ];464 $thread * threads[ count ]; 410 465 __builtin_memset( threads, 0, sizeof( threads ) ); 411 466 … … 415 470 // Remove any duplicate threads 416 471 for( __lock_size_t i = 0; i < count; i++) { 417 thread_desc* new_owner = next_thread( monitors[i] );472 $thread * new_owner = next_thread( monitors[i] ); 418 473 insert_unique( threads, thread_count, new_owner ); 419 474 } 420 475 476 // Unlock the locks, we don't need them anymore 477 for(int i = 0; i < count; i++) { 478 unlock( *locks[i] ); 479 } 480 481 // Wake the threads 482 for(int i = 0; i < thread_count; i++) { 483 unpark( threads[i] ); 484 } 485 421 486 // Everything is ready to go to sleep 422 BlockInternal( locks, count, threads, thread_count);487 park(); 423 488 424 489 // We are back, restore the owners and recursions … … 435 500 //Some more checking in debug 436 501 __cfaabi_dbg_debug_do( 437 thread_desc * this_thrd = TL_GET( this_thread);502 $thread * this_thrd = active_thread(); 438 503 if ( this.monitor_count != this_thrd->monitors.size ) { 439 504 abort( "Signal on condition %p made with different number of monitor(s), expected %zi got %zi", &this, this.monitor_count, this_thrd->monitors.size ); … … 483 548 484 549 // Create the node specific to this wait operation 485 wait_ctx_primed( kernelTLS.this_thread, 0 )550 wait_ctx_primed( active_thread(), 0 ) 486 551 487 552 //save contexts … … 489 554 490 555 //Find the thread to run 491 thread_desc* signallee = pop_head( this.blocked )->waiting_thread;492 set_owner( monitors, count, signallee );556 $thread * signallee = pop_head( this.blocked )->waiting_thread; 557 __set_owner( monitors, count, signallee ); 493 558 494 559 __cfaabi_dbg_print_buffer_decl( "Kernel : signal_block condition %p (s: %p)\n", &this, signallee ); 495 560 561 // unlock all the monitors 562 unlock_all( locks, count ); 563 564 // unpark the thread we signalled 565 unpark( signallee ); 566 496 567 //Everything is ready to go to sleep 497 BlockInternal( locks, count, &signallee, 1);568 park(); 498 569 499 570 … … 536 607 // Create one! 537 608 __lock_size_t max = count_max( mask ); 538 monitor_desc* mon_storage[max];609 $monitor * mon_storage[max]; 539 610 __builtin_memset( mon_storage, 0, sizeof( mon_storage ) ); 540 611 __lock_size_t actual_count = aggregate( mon_storage, mask ); … … 554 625 { 555 626 // Check if the entry queue 556 thread_desc* next; int index;627 $thread * next; int index; 557 628 [next, index] = search_entry_queue( mask, monitors, count ); 558 629 … … 564 635 verifyf( accepted.size == 1, "ERROR: Accepted dtor has more than 1 mutex parameter." ); 565 636 566 monitor_desc* mon2dtor = accepted[0];637 $monitor * mon2dtor = accepted[0]; 567 638 verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." ); 568 639 … … 576 647 577 648 // Create the node specific to this wait operation 578 wait_ctx_primed( kernelTLS.this_thread, 0 );649 wait_ctx_primed( active_thread(), 0 ); 579 650 580 651 // Save monitor states … … 590 661 591 662 // Set the owners to be the next thread 592 set_owner( monitors, count, next ); 593 594 // Everything is ready to go to sleep 595 BlockInternal( locks, count, &next, 1 ); 663 __set_owner( monitors, count, next ); 664 665 // unlock all the monitors 666 unlock_all( locks, count ); 667 668 // unpark the thread we signalled 669 unpark( next ); 670 671 //Everything is ready to go to sleep 672 park(); 596 673 597 674 // We are back, restore the owners and recursions … … 622 699 623 700 // Create the node specific to this wait operation 624 wait_ctx_primed( kernelTLS.this_thread, 0 );701 wait_ctx_primed( active_thread(), 0 ); 625 702 626 703 monitor_save; … … 628 705 629 706 for( __lock_size_t i = 0; i < count; i++) { 630 verify( monitors[i]->owner == kernelTLS.this_thread ); 631 } 707 verify( monitors[i]->owner == active_thread() ); 708 } 709 710 // unlock all the monitors 711 unlock_all( locks, count ); 632 712 633 713 //Everything is ready to go to sleep 634 BlockInternal( locks, count);714 park(); 635 715 636 716 … … 649 729 // Utilities 650 730 651 static inline void set_owner( monitor_desc * this, thread_desc* owner ) {652 / / __cfaabi_dbg_print_safe( "Kernal : Setting owner of %p to %p ( was %p)\n", this, owner, this->owner);731 static inline void __set_owner( $monitor * this, $thread * owner ) { 732 /* paranoid */ verify( this->lock.lock ); 653 733 654 734 //Pass the monitor appropriately … … 659 739 } 660 740 661 static inline void set_owner( monitor_desc * monitors [], __lock_size_t count, thread_desc * owner ) { 662 monitors[0]->owner = owner; 663 monitors[0]->recursion = 1; 741 static inline void __set_owner( $monitor * monitors [], __lock_size_t count, $thread * owner ) { 742 /* paranoid */ verify ( monitors[0]->lock.lock ); 743 /* paranoid */ verifyf( monitors[0]->owner == active_thread(), "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), monitors[0]->owner, monitors[0]->recursion, monitors[0] ); 744 monitors[0]->owner = owner; 745 monitors[0]->recursion = 1; 664 746 for( __lock_size_t i = 1; i < count; i++ ) { 665 monitors[i]->owner = owner; 666 monitors[i]->recursion = 0; 667 } 668 } 669 670 static inline void set_mask( monitor_desc * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) { 747 /* paranoid */ verify ( monitors[i]->lock.lock ); 748 /* paranoid */ verifyf( monitors[i]->owner == active_thread(), "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), monitors[i]->owner, monitors[i]->recursion, monitors[i] ); 749 monitors[i]->owner = owner; 750 monitors[i]->recursion = 0; 751 } 752 } 753 754 static inline void set_mask( $monitor * storage [], __lock_size_t count, const __waitfor_mask_t & mask ) { 671 755 for( __lock_size_t i = 0; i < count; i++) { 672 756 storage[i]->mask = mask; … … 674 758 } 675 759 676 static inline void reset_mask( monitor_desc* this ) {760 static inline void reset_mask( $monitor * this ) { 677 761 this->mask.accepted = 0p; 678 762 this->mask.data = 0p; … … 680 764 } 681 765 682 static inline thread_desc * next_thread( monitor_desc* this ) {766 static inline $thread * next_thread( $monitor * this ) { 683 767 //Check the signaller stack 684 768 __cfaabi_dbg_print_safe( "Kernel : mon %p AS-stack top %p\n", this, this->signal_stack.top); … … 688 772 //regardless of if we are ready to baton pass, 689 773 //we need to set the monitor as in use 690 set_owner( this, urgent->owner->waiting_thread ); 774 /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 775 __set_owner( this, urgent->owner->waiting_thread ); 691 776 692 777 return check_condition( urgent ); … … 695 780 // No signaller thread 696 781 // Get the next thread in the entry_queue 697 thread_desc * new_owner = pop_head( this->entry_queue ); 698 set_owner( this, new_owner ); 782 $thread * new_owner = pop_head( this->entry_queue ); 783 /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 784 /* paranoid */ verify( !new_owner || new_owner->link.next == 0p ); 785 __set_owner( this, new_owner ); 699 786 700 787 return new_owner; 701 788 } 702 789 703 static inline bool is_accepted( monitor_desc* this, const __monitor_group_t & group ) {790 static inline bool is_accepted( $monitor * this, const __monitor_group_t & group ) { 704 791 __acceptable_t * it = this->mask.data; // Optim 705 792 __lock_size_t count = this->mask.size; … … 723 810 } 724 811 725 static inline void init( __lock_size_t count, monitor_desc* monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {812 static inline void init( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) { 726 813 for( __lock_size_t i = 0; i < count; i++) { 727 814 (criteria[i]){ monitors[i], waiter }; … … 731 818 } 732 819 733 static inline void init_push( __lock_size_t count, monitor_desc* monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) {820 static inline void init_push( __lock_size_t count, $monitor * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ) { 734 821 for( __lock_size_t i = 0; i < count; i++) { 735 822 (criteria[i]){ monitors[i], waiter }; … … 747 834 } 748 835 749 static inline void lock_all( monitor_desc* source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) {836 static inline void lock_all( $monitor * source [], __spinlock_t * /*out*/ locks [], __lock_size_t count ) { 750 837 for( __lock_size_t i = 0; i < count; i++ ) { 751 838 __spinlock_t * l = &source[i]->lock; … … 761 848 } 762 849 763 static inline void unlock_all( monitor_desc* locks [], __lock_size_t count ) {850 static inline void unlock_all( $monitor * locks [], __lock_size_t count ) { 764 851 for( __lock_size_t i = 0; i < count; i++ ) { 765 852 unlock( locks[i]->lock ); … … 768 855 769 856 static inline void save( 770 monitor_desc* ctx [],857 $monitor * ctx [], 771 858 __lock_size_t count, 772 859 __attribute((unused)) __spinlock_t * locks [], … … 781 868 782 869 static inline void restore( 783 monitor_desc* ctx [],870 $monitor * ctx [], 784 871 __lock_size_t count, 785 872 __spinlock_t * locks [], … … 799 886 // 2 - Checks if all the monitors are ready to run 800 887 // if so return the thread to run 801 static inline thread_desc* check_condition( __condition_criterion_t * target ) {888 static inline $thread * check_condition( __condition_criterion_t * target ) { 802 889 __condition_node_t * node = target->owner; 803 890 unsigned short count = node->count; … … 817 904 } 818 905 819 __cfaabi_dbg_print_safe( "Kernel : Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread :0p );906 __cfaabi_dbg_print_safe( "Kernel : Runing %i (%p)\n", ready2run, ready2run ? (thread*)node->waiting_thread : (thread*)0p ); 820 907 return ready2run ? node->waiting_thread : 0p; 821 908 } 822 909 823 910 static inline void brand_condition( condition & this ) { 824 thread_desc * thrd = TL_GET( this_thread);911 $thread * thrd = active_thread(); 825 912 if( !this.monitors ) { 826 913 // __cfaabi_dbg_print_safe( "Branding\n" ); … … 828 915 this.monitor_count = thrd->monitors.size; 829 916 830 this.monitors = ( monitor_desc**)malloc( this.monitor_count * sizeof( *this.monitors ) );917 this.monitors = ($monitor **)malloc( this.monitor_count * sizeof( *this.monitors ) ); 831 918 for( int i = 0; i < this.monitor_count; i++ ) { 832 919 this.monitors[i] = thrd->monitors[i]; … … 835 922 } 836 923 837 static inline [ thread_desc *, int] search_entry_queue( const __waitfor_mask_t & mask, monitor_desc* monitors [], __lock_size_t count ) {838 839 __queue_t( thread_desc) & entry_queue = monitors[0]->entry_queue;924 static inline [$thread *, int] search_entry_queue( const __waitfor_mask_t & mask, $monitor * monitors [], __lock_size_t count ) { 925 926 __queue_t($thread) & entry_queue = monitors[0]->entry_queue; 840 927 841 928 // For each thread in the entry-queue 842 for( thread_desc** thrd_it = &entry_queue.head;843 *thrd_it;844 thrd_it = &(*thrd_it)-> next929 for( $thread ** thrd_it = &entry_queue.head; 930 (*thrd_it) != 1p; 931 thrd_it = &(*thrd_it)->link.next 845 932 ) { 846 933 // For each acceptable check if it matches … … 884 971 } 885 972 886 static inline __lock_size_t aggregate( monitor_desc* storage [], const __waitfor_mask_t & mask ) {973 static inline __lock_size_t aggregate( $monitor * storage [], const __waitfor_mask_t & mask ) { 887 974 __lock_size_t size = 0; 888 975 for( __lock_size_t i = 0; i < mask.size; i++ ) { -
libcfa/src/concurrency/monitor.hfa
rbdfc032 reef8dfb 23 23 24 24 trait is_monitor(dtype T) { 25 monitor_desc* get_monitor( T & );25 $monitor * get_monitor( T & ); 26 26 void ^?{}( T & mutex ); 27 27 }; 28 28 29 static inline void ?{}( monitor_desc& this) with( this ) {29 static inline void ?{}($monitor & this) with( this ) { 30 30 lock{}; 31 31 entry_queue{}; … … 39 39 } 40 40 41 static inline void ^?{}( monitor_desc& ) {}41 static inline void ^?{}($monitor & ) {} 42 42 43 43 struct monitor_guard_t { 44 monitor_desc** m;44 $monitor ** m; 45 45 __lock_size_t count; 46 46 __monitor_group_t prev; 47 47 }; 48 48 49 void ?{}( monitor_guard_t & this, monitor_desc** m, __lock_size_t count, void (*func)() );49 void ?{}( monitor_guard_t & this, $monitor ** m, __lock_size_t count, void (*func)() ); 50 50 void ^?{}( monitor_guard_t & this ); 51 51 52 52 struct monitor_dtor_guard_t { 53 monitor_desc* m;53 $monitor * m; 54 54 __monitor_group_t prev; 55 bool join; 55 56 }; 56 57 57 void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, void (*func)());58 void ?{}( monitor_dtor_guard_t & this, $monitor ** m, void (*func)(), bool join ); 58 59 void ^?{}( monitor_dtor_guard_t & this ); 59 60 … … 72 73 73 74 // The monitor this criterion concerns 74 monitor_desc* target;75 $monitor * target; 75 76 76 77 // The parent node to which this criterion belongs … … 87 88 struct __condition_node_t { 88 89 // Thread that needs to be woken when all criteria are met 89 thread_desc* waiting_thread;90 $thread * waiting_thread; 90 91 91 92 // Array of criteria (Criterions are contiguous in memory) … … 106 107 } 107 108 108 void ?{}(__condition_node_t & this, thread_desc* waiting_thread, __lock_size_t count, uintptr_t user_info );109 void ?{}(__condition_node_t & this, $thread * waiting_thread, __lock_size_t count, uintptr_t user_info ); 109 110 void ?{}(__condition_criterion_t & this ); 110 void ?{}(__condition_criterion_t & this, monitor_desc* target, __condition_node_t * owner );111 void ?{}(__condition_criterion_t & this, $monitor * target, __condition_node_t * owner ); 111 112 112 113 struct condition { … … 115 116 116 117 // Array of monitor pointers (Monitors are NOT contiguous in memory) 117 monitor_desc** monitors;118 $monitor ** monitors; 118 119 119 120 // Number of monitors in the array … … 131 132 132 133 void wait ( condition & this, uintptr_t user_info = 0 ); 134 static inline bool is_empty ( condition & this ) { return this.blocked.head == 1p; } 133 135 bool signal ( condition & this ); 134 136 bool signal_block( condition & this ); 135 static inline bool is_empty ( condition & this ) { return !this.blocked.head; }137 static inline bool signal_all ( condition & this ) { bool ret = false; while(!is_empty(this)) { ret = signal(this) || ret; } return ret; } 136 138 uintptr_t front ( condition & this ); 137 139 -
libcfa/src/concurrency/mutex.cfa
rbdfc032 reef8dfb 30 30 this.lock{}; 31 31 this.blocked_threads{}; 32 this.is_locked = false; 32 33 } 33 34 … … 39 40 lock( lock __cfaabi_dbg_ctx2 ); 40 41 if( is_locked ) { 41 append( blocked_threads, kernelTLS.this_thread ); 42 BlockInternal( &lock ); 42 append( blocked_threads, active_thread() ); 43 unlock( lock ); 44 park(); 43 45 } 44 46 else { … … 62 64 lock( this.lock __cfaabi_dbg_ctx2 ); 63 65 this.is_locked = (this.blocked_threads != 0); 64 WakeThread(66 unpark( 65 67 pop_head( this.blocked_threads ) 66 68 ); … … 84 86 lock( lock __cfaabi_dbg_ctx2 ); 85 87 if( owner == 0p ) { 86 owner = kernelTLS.this_thread;88 owner = active_thread(); 87 89 recursion_count = 1; 88 90 unlock( lock ); 89 91 } 90 else if( owner == kernelTLS.this_thread) {92 else if( owner == active_thread() ) { 91 93 recursion_count++; 92 94 unlock( lock ); 93 95 } 94 96 else { 95 append( blocked_threads, kernelTLS.this_thread ); 96 BlockInternal( &lock ); 97 append( blocked_threads, active_thread() ); 98 unlock( lock ); 99 park(); 97 100 } 98 101 } … … 102 105 lock( lock __cfaabi_dbg_ctx2 ); 103 106 if( owner == 0p ) { 104 owner = kernelTLS.this_thread;107 owner = active_thread(); 105 108 recursion_count = 1; 106 109 ret = true; 107 110 } 108 else if( owner == kernelTLS.this_thread) {111 else if( owner == active_thread() ) { 109 112 recursion_count++; 110 113 ret = true; … … 118 121 recursion_count--; 119 122 if( recursion_count == 0 ) { 120 thread_desc* thrd = pop_head( blocked_threads );123 $thread * thrd = pop_head( blocked_threads ); 121 124 owner = thrd; 122 125 recursion_count = (thrd ? 1 : 0); 123 WakeThread( thrd );126 unpark( thrd ); 124 127 } 125 128 unlock( lock ); … … 138 141 void notify_one(condition_variable & this) with(this) { 139 142 lock( lock __cfaabi_dbg_ctx2 ); 140 WakeThread(143 unpark( 141 144 pop_head( this.blocked_threads ) 142 145 ); … … 147 150 lock( lock __cfaabi_dbg_ctx2 ); 148 151 while(this.blocked_threads) { 149 WakeThread(152 unpark( 150 153 pop_head( this.blocked_threads ) 151 154 ); … … 156 159 void wait(condition_variable & this) { 157 160 lock( this.lock __cfaabi_dbg_ctx2 ); 158 append( this.blocked_threads, kernelTLS.this_thread ); 159 BlockInternal( &this.lock ); 161 append( this.blocked_threads, active_thread() ); 162 unlock( this.lock ); 163 park(); 160 164 } 161 165 … … 163 167 void wait(condition_variable & this, L & l) { 164 168 lock( this.lock __cfaabi_dbg_ctx2 ); 165 append( this.blocked_threads, kernelTLS.this_thread ); 166 void __unlock(void) { 167 unlock(l); 168 unlock(this.lock); 169 } 170 BlockInternal( __unlock ); 169 append( this.blocked_threads, active_thread() ); 170 unlock(l); 171 unlock(this.lock); 172 park(); 171 173 lock(l); 172 174 } -
libcfa/src/concurrency/mutex.hfa
rbdfc032 reef8dfb 36 36 37 37 // List of blocked threads 38 __queue_t(struct thread_desc) blocked_threads;38 __queue_t(struct $thread) blocked_threads; 39 39 40 40 // Locked flag … … 55 55 56 56 // List of blocked threads 57 __queue_t(struct thread_desc) blocked_threads;57 __queue_t(struct $thread) blocked_threads; 58 58 59 59 // Current thread owning the lock 60 struct thread_desc* owner;60 struct $thread * owner; 61 61 62 62 // Number of recursion level … … 83 83 84 84 // List of blocked threads 85 __queue_t(struct thread_desc) blocked_threads;85 __queue_t(struct $thread) blocked_threads; 86 86 }; 87 87 -
libcfa/src/concurrency/preemption.cfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Dec 5 16:34:05 201913 // Update Count : 4312 // Last Modified On : Fri Nov 6 07:42:13 2020 13 // Update Count : 54 14 14 // 15 15 … … 19 19 #include <assert.h> 20 20 21 extern "C" {22 21 #include <errno.h> 23 22 #include <stdio.h> … … 25 24 #include <unistd.h> 26 25 #include <limits.h> // PTHREAD_STACK_MIN 27 }28 26 29 27 #include "bits/signal.hfa" 28 #include "kernel_private.hfa" 30 29 31 30 #if !defined(__CFA_DEFAULT_PREEMPTION__) … … 39 38 // FwdDeclarations : timeout handlers 40 39 static void preempt( processor * this ); 41 static void timeout( thread_desc* this );40 static void timeout( $thread * this ); 42 41 43 42 // FwdDeclarations : Signal handlers 44 43 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 44 static void sigHandler_alarm ( __CFA_SIGPARMS__ ); 45 45 static void sigHandler_segv ( __CFA_SIGPARMS__ ); 46 46 static void sigHandler_ill ( __CFA_SIGPARMS__ ); … … 56 56 #elif defined( __x86_64 ) 57 57 #define CFA_REG_IP gregs[REG_RIP] 58 #elif defined( __ ARM_ARCH)58 #elif defined( __arm__ ) 59 59 #define CFA_REG_IP arm_pc 60 #elif defined( __aarch64__ ) 61 #define CFA_REG_IP pc 60 62 #else 61 #error un knownhardware architecture63 #error unsupported hardware architecture 62 64 #endif 63 65 … … 83 85 // Get next expired node 84 86 static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) { 85 if( ! alarms->head) return 0p; // If no alarms return null86 if( alarms->head->alarm >= currtime ) return 0p; // If alarms head not expired return null87 if( ! & (*alarms)`first ) return 0p; // If no alarms return null 88 if( (*alarms)`first.alarm >= currtime ) return 0p; // If alarms head not expired return null 87 89 return pop(alarms); // Otherwise just pop head 88 90 } 89 91 90 92 // Tick one frame of the Discrete Event Simulation for alarms 91 static void tick_preemption( ) {93 static void tick_preemption(void) { 92 94 alarm_node_t * node = 0p; // Used in the while loop but cannot be declared in the while condition 93 95 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 97 99 while( node = get_expired( alarms, currtime ) ) { 98 100 // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" ); 101 Duration period = node->period; 102 if( period == 0) { 103 node->set = false; // Node is one-shot, just mark it as not pending 104 } 99 105 100 106 // Check if this is a kernel 101 if( node-> kernel_alarm) {107 if( node->type == Kernel ) { 102 108 preempt( node->proc ); 103 109 } 110 else if( node->type == User ) { 111 timeout( node->thrd ); 112 } 104 113 else { 105 timeout( node->thrd);114 node->callback(*node); 106 115 } 107 116 108 117 // Check if this is a periodic alarm 109 Duration period = node->period;110 118 if( period > 0 ) { 111 119 // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv ); … … 113 121 insert( alarms, node ); // Reinsert the node for the next time it triggers 114 122 } 115 else {116 node->set = false; // Node is one-shot, just mark it as not pending117 }118 123 } 119 124 120 125 // If there are still alarms pending, reset the timer 121 if( alarms->head) {122 __cfa abi_dbg_print_buffer_decl(" KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);123 Duration delta = alarms->head->alarm - currtime;124 Duration cap ed = max(delta, 50`us);126 if( & (*alarms)`first ) { 127 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv); 128 Duration delta = (*alarms)`first.alarm - currtime; 129 Duration capped = max(delta, 50`us); 125 130 // itimerval tim = { caped }; 126 131 // __cfaabi_dbg_print_buffer_local( " Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec); 127 132 128 __kernel_set_timer( cap ed );133 __kernel_set_timer( capped ); 129 134 } 130 135 } … … 158 163 // Kernel Signal Tools 159 164 //============================================================================================= 160 161 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; ) 165 // In a user-level threading system, there are handful of thread-local variables where this problem occurs on the ARM. 166 // 167 // For each kernel thread running user-level threads, there is a flag variable to indicate if interrupts are 168 // enabled/disabled for that kernel thread. Therefore, this variable is made thread local. 169 // 170 // For example, this code fragment sets the state of the "interrupt" variable in thread-local memory. 171 // 172 // _Thread_local volatile int interrupts; 173 // int main() { 174 // interrupts = 0; // disable interrupts } 175 // 176 // which generates the following code on the ARM 177 // 178 // (gdb) disassemble main 179 // Dump of assembler code for function main: 180 // 0x0000000000000610 <+0>: mrs x1, tpidr_el0 181 // 0x0000000000000614 <+4>: mov w0, #0x0 // #0 182 // 0x0000000000000618 <+8>: add x1, x1, #0x0, lsl #12 183 // 0x000000000000061c <+12>: add x1, x1, #0x10 184 // 0x0000000000000620 <+16>: str wzr, [x1] 185 // 0x0000000000000624 <+20>: ret 186 // 187 // The mrs moves a pointer from coprocessor register tpidr_el0 into register x1. Register w0 is set to 0. The two adds 188 // increase the TLS pointer with the displacement (offset) 0x10, which is the location in the TSL of variable 189 // "interrupts". Finally, 0 is stored into "interrupts" through the pointer in register x1 that points into the 190 // TSL. Now once x1 has the pointer to the location of the TSL for kernel thread N, it can be be preempted at a 191 // user-level and the user thread is put on the user-level ready-queue. When the preempted thread gets to the front of 192 // the user-level ready-queue it is run on kernel thread M. It now stores 0 into "interrupts" back on kernel thread N, 193 // turning off interrupt on the wrong kernel thread. 194 // 195 // On the x86, the following code is generated for the same code fragment. 196 // 197 // (gdb) disassemble main 198 // Dump of assembler code for function main: 199 // 0x0000000000400420 <+0>: movl $0x0,%fs:0xfffffffffffffffc 200 // 0x000000000040042c <+12>: xor %eax,%eax 201 // 0x000000000040042e <+14>: retq 202 // 203 // and there is base-displacement addressing used to atomically reset variable "interrupts" off of the TSL pointer in 204 // register "fs". 205 // 206 // Hence, the ARM has base-displacement address for the general purpose registers, BUT not to the coprocessor 207 // registers. As a result, generating the address for the write into variable "interrupts" is no longer atomic. 208 // 209 // Note this problem does NOT occur when just using multiple kernel threads because the preemption ALWAYS restarts the 210 // thread on the same kernel thread. 211 // 212 // The obvious question is why does ARM use a coprocessor register to store the TSL pointer given that coprocessor 213 // registers are second-class registers with respect to the instruction set. One possible answer is that they did not 214 // want to dedicate one of the general registers to hold the TLS pointer and there was a free coprocessor register 215 // available. 216 217 //----------------------------------------------------------------------------- 218 // Some assembly required 219 #define __cfaasm_label(label, when) when: asm volatile goto(".global __cfaasm_" #label "_" #when "\n" "__cfaasm_" #label "_" #when ":":::"memory":when) 220 221 //---------- 222 // special case for preemption since used often 223 bool __preemption_enabled() { 224 // create a assembler label before 225 // marked as clobber all to avoid movement 226 __cfaasm_label(check, before); 227 228 // access tls as normal 229 bool enabled = __cfaabi_tls.preemption_state.enabled; 230 231 // create a assembler label after 232 // marked as clobber all to avoid movement 233 __cfaasm_label(check, after); 234 return enabled; 235 } 236 237 struct asm_region { 238 void * before; 239 void * after; 240 }; 241 242 static inline bool __cfaasm_in( void * ip, struct asm_region & region ) { 243 return ip >= region.before && ip <= region.after; 244 } 245 246 247 //---------- 248 // Get data from the TLS block 249 // struct asm_region __cfaasm_get; 250 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems 251 uintptr_t __cfatls_get( unsigned long int offset ) { 252 // create a assembler label before 253 // marked as clobber all to avoid movement 254 __cfaasm_label(get, before); 255 256 // access tls as normal (except for pointer arithmetic) 257 uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset); 258 259 // create a assembler label after 260 // marked as clobber all to avoid movement 261 __cfaasm_label(get, after); 262 return val; 263 } 162 264 163 265 extern "C" { 164 266 // Disable interrupts by incrementing the counter 165 267 void disable_interrupts() { 166 with( kernelTLS.preemption_state ) { 268 // create a assembler label before 269 // marked as clobber all to avoid movement 270 __cfaasm_label(dsable, before); 271 272 with( __cfaabi_tls.preemption_state ) { 167 273 #if GCC_VERSION > 50000 168 274 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); … … 181 287 verify( new_val < 65_000u ); // If this triggers someone is disabling interrupts without enabling them 182 288 } 289 290 // create a assembler label after 291 // marked as clobber all to avoid movement 292 __cfaasm_label(dsable, after); 293 183 294 } 184 295 185 296 // Enable interrupts by decrementing the counter 186 // If counter reaches 0, execute any pending CtxSwitch297 // If counter reaches 0, execute any pending __cfactx_switch 187 298 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 188 processor * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store 189 thread_desc * thrd = kernelTLS.this_thread; // Cache the thread now since interrupts can start happening after the atomic store 190 191 with( kernelTLS.preemption_state ){ 299 // Cache the processor now since interrupts can start happening after the atomic store 300 processor * proc = __cfaabi_tls.this_processor; 301 /* paranoid */ verify( proc ); 302 303 with( __cfaabi_tls.preemption_state ){ 192 304 unsigned short prev = disable_count; 193 305 disable_count -= 1; 194 verify( prev != 0u ); // If this triggers someone is enabled already enabled interruptsverify( prev != 0u ); 306 307 // If this triggers someone is enabled already enabled interruptsverify( prev != 0u ); 308 /* paranoid */ verify( prev != 0u ); 195 309 196 310 // Check if we need to prempt the thread because an interrupt was missed 197 311 if( prev == 1 ) { 198 312 #if GCC_VERSION > 50000 199 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");313 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 200 314 #endif 201 315 … … 209 323 if( proc->pending_preemption ) { 210 324 proc->pending_preemption = false; 211 BlockInternal( thrd);325 force_yield( __POLL_PREEMPTION ); 212 326 } 213 327 } … … 219 333 220 334 // Disable interrupts by incrementint the counter 221 // Don't execute any pending CtxSwitch even if counter reaches 0335 // Don't execute any pending __cfactx_switch even if counter reaches 0 222 336 void enable_interrupts_noPoll() { 223 unsigned short prev = kernelTLS.preemption_state.disable_count; 224 kernelTLS.preemption_state.disable_count -= 1; 225 verifyf( prev != 0u, "Incremented from %u\n", prev ); // If this triggers someone is enabled already enabled interrupts 337 unsigned short prev = __cfaabi_tls.preemption_state.disable_count; 338 __cfaabi_tls.preemption_state.disable_count -= 1; 339 // If this triggers someone is enabled already enabled interrupts 340 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev ); 226 341 if( prev == 1 ) { 227 342 #if GCC_VERSION > 50000 228 static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free");343 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free"); 229 344 #endif 230 345 // Set enabled flag to true 231 346 // should be atomic to avoid preemption in the middle of the operation. 232 347 // use memory order RELAXED since there is no inter-thread on this variable requirements 233 __atomic_store_n(& kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED);348 __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED); 234 349 235 350 // Signal the compiler that a fence is needed but only for signal handlers … … 238 353 } 239 354 } 355 356 //----------------------------------------------------------------------------- 357 // Kernel Signal Debug 358 void __cfaabi_check_preemption() { 359 bool ready = __preemption_enabled(); 360 if(!ready) { abort("Preemption should be ready"); } 361 362 __cfaasm_label(debug, before); 363 364 sigset_t oldset; 365 int ret; 366 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 367 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 368 369 ret = sigismember(&oldset, SIGUSR1); 370 if(ret < 0) { abort("ERROR sigismember returned %d", ret); } 371 if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); } 372 373 ret = sigismember(&oldset, SIGALRM); 374 if(ret < 0) { abort("ERROR sigismember returned %d", ret); } 375 if(ret == 0) { abort("ERROR SIGALRM is enabled"); } 376 377 ret = sigismember(&oldset, SIGTERM); 378 if(ret < 0) { abort("ERROR sigismember returned %d", ret); } 379 if(ret == 1) { abort("ERROR SIGTERM is disabled"); } 380 381 __cfaasm_label(debug, after); 382 } 383 384 #ifdef __CFA_WITH_VERIFY__ 385 bool __cfaabi_dbg_in_kernel() { 386 return !__preemption_enabled(); 387 } 388 #endif 389 390 #undef __cfaasm_label 391 392 //----------------------------------------------------------------------------- 393 // Signal handling 240 394 241 395 // sigprocmask wrapper : unblock a single signal … … 257 411 258 412 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 259 413 abort( "internal error, pthread_sigmask" ); 260 414 } 261 415 } … … 268 422 269 423 // reserved for future use 270 static void timeout( thread_desc * this ) { 271 //TODO : implement waking threads 272 } 424 static void timeout( $thread * this ) { 425 unpark( this ); 426 } 427 428 //----------------------------------------------------------------------------- 429 // Some assembly required 430 #if defined( __i386 ) 431 #ifdef __PIC__ 432 #define RELOC_PRELUDE( label ) \ 433 "calll .Lcfaasm_prelude_" #label "$pb\n\t" \ 434 ".Lcfaasm_prelude_" #label "$pb:\n\t" \ 435 "popl %%eax\n\t" \ 436 ".Lcfaasm_prelude_" #label "_end:\n\t" \ 437 "addl $_GLOBAL_OFFSET_TABLE_+(.Lcfaasm_prelude_" #label "_end-.Lcfaasm_prelude_" #label "$pb), %%eax\n\t" 438 #define RELOC_PREFIX "" 439 #define RELOC_SUFFIX "@GOT(%%eax)" 440 #else 441 #define RELOC_PREFIX "$" 442 #define RELOC_SUFFIX "" 443 #endif 444 #define __cfaasm_label( label ) struct asm_region label = \ 445 ({ \ 446 struct asm_region region; \ 447 asm( \ 448 RELOC_PRELUDE( label ) \ 449 "movl " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \ 450 "movl " RELOC_PREFIX "__cfaasm_" #label "_after" RELOC_SUFFIX ", %[va]\n\t" \ 451 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 452 ); \ 453 region; \ 454 }); 455 #elif defined( __x86_64 ) 456 #ifdef __PIC__ 457 #define RELOC_PREFIX "" 458 #define RELOC_SUFFIX "@GOTPCREL(%%rip)" 459 #else 460 #define RELOC_PREFIX "$" 461 #define RELOC_SUFFIX "" 462 #endif 463 #define __cfaasm_label( label ) struct asm_region label = \ 464 ({ \ 465 struct asm_region region; \ 466 asm( \ 467 "movq " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \ 468 "movq " RELOC_PREFIX "__cfaasm_" #label "_after" RELOC_SUFFIX ", %[va]\n\t" \ 469 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 470 ); \ 471 region; \ 472 }); 473 #elif defined( __aarch64__ ) 474 #ifdef __PIC__ 475 // Note that this works only for gcc 476 #define __cfaasm_label( label ) struct asm_region label = \ 477 ({ \ 478 struct asm_region region; \ 479 asm( \ 480 "adrp %[vb], _GLOBAL_OFFSET_TABLE_" "\n\t" \ 481 "ldr %[vb], [%[vb], #:gotpage_lo15:__cfaasm_" #label "_before]" "\n\t" \ 482 "adrp %[va], _GLOBAL_OFFSET_TABLE_" "\n\t" \ 483 "ldr %[va], [%[va], #:gotpage_lo15:__cfaasm_" #label "_after]" "\n\t" \ 484 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 485 ); \ 486 region; \ 487 }); 488 #else 489 #error this is not the right thing to do 490 /* 491 #define __cfaasm_label( label ) struct asm_region label = \ 492 ({ \ 493 struct asm_region region; \ 494 asm( \ 495 "adrp %[vb], __cfaasm_" #label "_before" "\n\t" \ 496 "add %[vb], %[vb], :lo12:__cfaasm_" #label "_before" "\n\t" \ 497 "adrp %[va], :got:__cfaasm_" #label "_after" "\n\t" \ 498 "add %[va], %[va], :lo12:__cfaasm_" #label "_after" "\n\t" \ 499 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 500 ); \ 501 region; \ 502 }); 503 */ 504 #endif 505 #else 506 #error unknown hardware architecture 507 #endif 273 508 274 509 // KERNEL ONLY 275 // Check if a CtxSwitch signal handler shoud defer510 // Check if a __cfactx_switch signal handler shoud defer 276 511 // If true : preemption is safe 277 512 // If false : preemption is unsafe and marked as pending 278 static inline bool preemption_ready() { 513 static inline bool preemption_ready( void * ip ) { 514 // Get all the region for which it is not safe to preempt 515 __cfaasm_label( get ); 516 __cfaasm_label( check ); 517 __cfaasm_label( dsable ); 518 __cfaasm_label( debug ); 519 279 520 // Check if preemption is safe 280 bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress; 281 521 bool ready = true; 522 if( __cfaasm_in( ip, get ) ) { ready = false; goto EXIT; }; 523 if( __cfaasm_in( ip, check ) ) { ready = false; goto EXIT; }; 524 if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; }; 525 if( __cfaasm_in( ip, debug ) ) { ready = false; goto EXIT; }; 526 if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; }; 527 if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; }; 528 529 EXIT: 282 530 // Adjust the pending flag accordingly 283 kernelTLS.this_processor->pending_preemption = !ready;531 __cfaabi_tls.this_processor->pending_preemption = !ready; 284 532 return ready; 285 533 } … … 291 539 // Startup routine to activate preemption 292 540 // Called from kernel_startup 293 void kernel_start_preemption() {541 void __kernel_alarm_startup() { 294 542 __cfaabi_dbg_print_safe( "Kernel : Starting preemption\n" ); 295 543 296 544 // Start with preemption disabled until ready 297 kernelTLS.preemption_state.enabled = false;298 kernelTLS.preemption_state.disable_count = 1;545 __cfaabi_tls.preemption_state.enabled = false; 546 __cfaabi_tls.preemption_state.disable_count = 1; 299 547 300 548 // Initialize the event kernel … … 303 551 304 552 // Setup proper signal handlers 305 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // CtxSwitch handler 553 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler 554 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO | SA_RESTART ); // debug handler 306 555 307 556 signal_block( SIGALRM ); 308 557 309 alarm_stack = create_pthread( &alarm_thread, alarm_loop, 0p );558 alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p ); 310 559 } 311 560 312 561 // Shutdown routine to deactivate preemption 313 562 // Called from kernel_shutdown 314 void kernel_stop_preemption() {563 void __kernel_alarm_shutdown() { 315 564 __cfaabi_dbg_print_safe( "Kernel : Preemption stopping\n" ); 316 565 … … 326 575 // Wait for the preemption thread to finish 327 576 328 pthread_join( alarm_thread, 0p ); 329 free( alarm_stack ); 577 __destroy_pthread( alarm_thread, alarm_stack, 0p ); 330 578 331 579 // Preemption is now fully stopped … … 353 601 // Kernel Signal Handlers 354 602 //============================================================================================= 603 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; ) 355 604 356 605 // Context switch signal handler 357 606 // Receives SIGUSR1 signal and causes the current thread to yield 358 607 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 359 __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); ) 608 void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP); 609 __cfaabi_dbg_debug_do( last_interrupt = ip; ) 360 610 361 611 // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it, 362 612 // the interrupt that is supposed to force the kernel thread to preempt might arrive 363 // before the kernel thread has even started running. When that happens an iterrupt364 // w ea null 'this_processor' will be caught, just ignore it.365 if(! kernelTLS.this_processor ) return;613 // before the kernel thread has even started running. When that happens, an interrupt 614 // with a null 'this_processor' will be caught, just ignore it. 615 if(! __cfaabi_tls.this_processor ) return; 366 616 367 617 choose(sfp->si_value.sival_int) { 368 618 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 369 case PREEMPT_TERMINATE: verify( __atomic_load_n( & kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );619 case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 370 620 default: 371 621 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 373 623 374 624 // Check if it is safe to preempt here 375 if( !preemption_ready( ) ) { return; }376 377 __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", kernelTLS.this_processor, kernelTLS.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );625 if( !preemption_ready( ip ) ) { return; } 626 627 __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) ); 378 628 379 629 // Sync flag : prevent recursive calls to the signal handler 380 kernelTLS.preemption_state.in_progress = true;630 __cfaabi_tls.preemption_state.in_progress = true; 381 631 382 632 // Clear sighandler mask before context switching. … … 388 638 } 389 639 390 // TODO: this should go in finish action391 640 // Clear the in progress flag 392 kernelTLS.preemption_state.in_progress = false;641 __cfaabi_tls.preemption_state.in_progress = false; 393 642 394 643 // Preemption can occur here 395 644 396 BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch 397 } 645 force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch 646 } 647 648 static void sigHandler_alarm( __CFA_SIGPARMS__ ) { 649 abort("SIGALRM should never reach the signal handler"); 650 } 651 652 #if !defined(__CFA_NO_STATISTICS__) 653 int __print_alarm_stats = 0; 654 #endif 398 655 399 656 // Main of the alarm thread 400 657 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 401 658 static void * alarm_loop( __attribute__((unused)) void * args ) { 659 __processor_id_t id; 660 id.full_proc = false; 661 id.id = doregister(&id); 662 __cfaabi_tls.this_proc_id = &id; 663 664 #if !defined(__CFA_NO_STATISTICS__) 665 struct __stats_t local_stats; 666 __cfaabi_tls.this_stats = &local_stats; 667 __init_stats( &local_stats ); 668 #endif 669 402 670 // Block sigalrms to control when they arrive 403 671 sigset_t mask; … … 457 725 EXIT: 458 726 __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" ); 727 unregister(&id); 728 729 #if !defined(__CFA_NO_STATISTICS__) 730 if( 0 != __print_alarm_stats ) { 731 __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p ); 732 } 733 #endif 459 734 return 0p; 460 735 } 461 462 //=============================================================================================463 // Kernel Signal Debug464 //=============================================================================================465 466 void __cfaabi_check_preemption() {467 bool ready = kernelTLS.preemption_state.enabled;468 if(!ready) { abort("Preemption should be ready"); }469 470 sigset_t oldset;471 int ret;472 ret = pthread_sigmask(0, 0p, &oldset);473 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); }474 475 ret = sigismember(&oldset, SIGUSR1);476 if(ret < 0) { abort("ERROR sigismember returned %d", ret); }477 if(ret == 1) { abort("ERROR SIGUSR1 is disabled"); }478 479 ret = sigismember(&oldset, SIGALRM);480 if(ret < 0) { abort("ERROR sigismember returned %d", ret); }481 if(ret == 0) { abort("ERROR SIGALRM is enabled"); }482 483 ret = sigismember(&oldset, SIGTERM);484 if(ret < 0) { abort("ERROR sigismember returned %d", ret); }485 if(ret == 1) { abort("ERROR SIGTERM is disabled"); }486 }487 488 #ifdef __CFA_WITH_VERIFY__489 bool __cfaabi_dbg_in_kernel() {490 return !kernelTLS.preemption_state.enabled;491 }492 #endif493 736 494 737 // Local Variables: // -
libcfa/src/concurrency/preemption.hfa
rbdfc032 reef8dfb 16 16 #pragma once 17 17 18 #include "bits/locks.hfa" 18 19 #include "alarm.hfa" 19 #include "kernel_private.hfa"20 20 21 void kernel_start_preemption(); 22 void kernel_stop_preemption(); 21 struct event_kernel_t { 22 alarm_list_t alarms; 23 __spinlock_t lock; 24 }; 25 26 extern event_kernel_t * event_kernel; 27 23 28 void update_preemption( processor * this, Duration duration ); 24 29 -
libcfa/src/concurrency/thread.cfa
rbdfc032 reef8dfb 19 19 20 20 #include "kernel_private.hfa" 21 #include "exception.hfa" 21 22 22 23 #define __CFA_INVOKE_PRIVATE__ 23 24 #include "invoke.h" 24 25 25 extern "C" {26 #include <fenv.h>27 #include <stddef.h>28 }29 30 //extern volatile thread_local processor * this_processor;31 32 26 //----------------------------------------------------------------------------- 33 27 // Thread ctors and dtors 34 void ?{}( thread_desc& this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {28 void ?{}($thread & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) { 35 29 context{ 0p, 0p }; 36 30 self_cor{ name, storage, storageSize }; 31 ticket = TICKET_RUNNING; 37 32 state = Start; 33 preempted = __NO_PREEMPTION; 38 34 curr_cor = &self_cor; 39 35 self_mon.owner = &this; … … 41 37 self_mon_p = &self_mon; 42 38 curr_cluster = &cl; 43 next = 0p; 39 link.next = 0p; 40 link.prev = 0p; 41 link.preferred = -1; 42 #if defined( __CFA_WITH_VERIFY__ ) 43 canary = 0x0D15EA5E0D15EA5Ep; 44 #endif 45 46 seqable.next = 0p; 47 seqable.back = 0p; 44 48 45 49 node.next = 0p; … … 50 54 } 51 55 52 void ^?{}(thread_desc& this) with( this ) { 56 void ^?{}($thread& this) with( this ) { 57 #if defined( __CFA_WITH_VERIFY__ ) 58 canary = 0xDEADDEADDEADDEADp; 59 #endif 53 60 unregister(curr_cluster, this); 54 61 ^self_cor{}; 55 62 } 56 63 64 FORALL_DATA_INSTANCE(ThreadCancelled, (dtype thread_t), (thread_t)) 65 66 forall(dtype T) 67 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) { 68 dst->virtual_table = src->virtual_table; 69 dst->the_thread = src->the_thread; 70 dst->the_exception = src->the_exception; 71 } 72 73 forall(dtype T) 74 const char * msg(ThreadCancelled(T) *) { 75 return "ThreadCancelled"; 76 } 77 78 forall(dtype T) 79 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 80 abort( "Unhandled thread cancellation.\n" ); 81 } 82 83 forall(dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 84 void ?{}( thread_dtor_guard_t & this, 85 T & thrd, void(*defaultResumptionHandler)(ThreadCancelled(T) &)) { 86 $monitor * m = get_monitor(thrd); 87 $thread * desc = get_thread(thrd); 88 89 // Setup the monitor guard 90 void (*dtor)(T& mutex this) = ^?{}; 91 bool join = defaultResumptionHandler != (void(*)(ThreadCancelled(T)&))0; 92 (this.mg){&m, (void(*)())dtor, join}; 93 94 95 /* paranoid */ verifyf( Halted == desc->state || Cancelled == desc->state, "Expected thread to be Halted or Cancelled, was %d\n", (int)desc->state ); 96 97 // After the guard set-up and any wait, check for cancellation. 98 struct _Unwind_Exception * cancellation = desc->self_cor.cancellation; 99 if ( likely( 0p == cancellation ) ) { 100 return; 101 } else if ( Cancelled == desc->state ) { 102 return; 103 } 104 desc->state = Cancelled; 105 if (!join) { 106 defaultResumptionHandler = default_thread_cancel_handler; 107 } 108 109 ThreadCancelled(T) except; 110 // TODO: Remove explitate vtable set once trac#186 is fixed. 111 except.virtual_table = &get_exception_vtable(&except); 112 except.the_thread = &thrd; 113 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 114 throwResume except; 115 116 except.the_exception->virtual_table->free( except.the_exception ); 117 free( cancellation ); 118 desc->self_cor.cancellation = 0p; 119 } 120 121 void ^?{}( thread_dtor_guard_t & this ) { 122 ^(this.mg){}; 123 } 124 125 //----------------------------------------------------------------------------- 126 // Starting and stopping threads 127 forall( dtype T | is_thread(T) ) 128 void __thrd_start( T & this, void (*main_p)(T &) ) { 129 $thread * this_thrd = get_thread(this); 130 131 disable_interrupts(); 132 __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread); 133 134 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 135 /* paranoid */ verify( this_thrd->context.SP ); 136 137 __schedule_thread( this_thrd ); 138 enable_interrupts( __cfaabi_dbg_ctx ); 139 } 140 141 //----------------------------------------------------------------------------- 142 // Support for threads that don't ues the thread keyword 57 143 forall( dtype T | sized(T) | is_thread(T) | { void ?{}(T&); } ) 58 144 void ?{}( scoped(T)& this ) with( this ) { … … 73 159 74 160 //----------------------------------------------------------------------------- 75 // Starting and stopping threads 76 forall( dtype T | is_thread(T) ) 77 void __thrd_start( T & this, void (*main_p)(T &) ) { 78 thread_desc * this_thrd = get_thread(this); 79 thread_desc * curr_thrd = TL_GET( this_thread ); 80 81 disable_interrupts(); 82 CtxStart(main_p, get_coroutine(this), this, CtxInvokeThread); 83 84 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 85 verify( this_thrd->context.SP ); 86 // CtxSwitch( &curr_thrd->context, &this_thrd->context ); 87 88 ScheduleThread(this_thrd); 89 enable_interrupts( __cfaabi_dbg_ctx ); 161 forall(dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))) 162 T & join( T & this ) { 163 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; 164 return this; 90 165 } 91 166 92 void yield( void ) { 93 // Safety note : This could cause some false positives due to preemption 94 verify( TL_GET( preemption_state.enabled ) ); 95 BlockInternal( TL_GET( this_thread ) ); 96 // Safety note : This could cause some false positives due to preemption 97 verify( TL_GET( preemption_state.enabled ) ); 98 } 99 100 void yield( unsigned times ) { 101 for( unsigned i = 0; i < times; i++ ) { 102 yield(); 103 } 167 uint64_t thread_rand() { 168 disable_interrupts(); 169 uint64_t ret = __tls_rand(); 170 enable_interrupts( __cfaabi_dbg_ctx ); 171 return ret; 104 172 } 105 173 -
libcfa/src/concurrency/thread.hfa
rbdfc032 reef8dfb 22 22 #include "kernel.hfa" 23 23 #include "monitor.hfa" 24 #include "exception.hfa" 24 25 25 26 //----------------------------------------------------------------------------- 26 27 // thread trait 27 28 trait is_thread(dtype T) { 28 29 30 thread_desc* get_thread(T& this);29 void ^?{}(T& mutex this); 30 void main(T& this); 31 $thread* get_thread(T& this); 31 32 }; 32 33 33 #define DECL_THREAD(X) thread_desc* get_thread(X& this) { return &this.__thrd; } void main(X& this) 34 FORALL_DATA_EXCEPTION(ThreadCancelled, (dtype thread_t), (thread_t)) ( 35 thread_t * the_thread; 36 exception_t * the_exception; 37 ); 38 39 forall(dtype T) 40 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src); 41 42 forall(dtype T) 43 const char * msg(ThreadCancelled(T) *); 44 45 // define that satisfies the trait without using the thread keyword 46 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this) 47 48 // Inline getters for threads/coroutines/monitors 49 forall( dtype T | is_thread(T) ) 50 static inline $coroutine* get_coroutine(T & this) __attribute__((const)) { return &get_thread(this)->self_cor; } 34 51 35 52 forall( dtype T | is_thread(T) ) 36 static inline coroutine_desc* get_coroutine(T & this) { 37 return &get_thread(this)->self_cor; 38 } 53 static inline $monitor * get_monitor (T & this) __attribute__((const)) { return &get_thread(this)->self_mon; } 39 54 40 forall( dtype T | is_thread(T) ) 41 static inline monitor_desc* get_monitor(T & this) { 42 return &get_thread(this)->self_mon; 43 } 55 static inline $coroutine* get_coroutine($thread * this) __attribute__((const)) { return &this->self_cor; } 56 static inline $monitor * get_monitor ($thread * this) __attribute__((const)) { return &this->self_mon; } 44 57 45 static inline coroutine_desc* get_coroutine(thread_desc * this) { 46 return &this->self_cor; 47 } 48 49 static inline monitor_desc* get_monitor(thread_desc * this) { 50 return &this->self_mon; 51 } 52 58 //----------------------------------------------------------------------------- 59 // forward declarations needed for threads 53 60 extern struct cluster * mainCluster; 54 61 … … 58 65 //----------------------------------------------------------------------------- 59 66 // Ctors and dtors 60 void ?{}( thread_desc& this, const char * const name, struct cluster & cl, void * storage, size_t storageSize );61 void ^?{}( thread_desc& this);67 void ?{}($thread & this, const char * const name, struct cluster & cl, void * storage, size_t storageSize ); 68 void ^?{}($thread & this); 62 69 63 static inline void ?{}(thread_desc & this) { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; } 64 static inline void ?{}(thread_desc & this, size_t stackSize ) { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; } 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, 0p, 65000 }; } 67 static inline void ?{}(thread_desc & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, 0p, stackSize }; } 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, 0p, 65000 }; } 70 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl ) { this{ name, cl, 0p, 65000 }; } 71 static inline void ?{}(thread_desc & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; } 70 static inline void ?{}($thread & this) { this{ "Anonymous Thread", *mainCluster, 0p, 65000 }; } 71 static inline void ?{}($thread & this, size_t stackSize ) { this{ "Anonymous Thread", *mainCluster, 0p, stackSize }; } 72 static inline void ?{}($thread & this, void * storage, size_t storageSize ) { this{ "Anonymous Thread", *mainCluster, storage, storageSize }; } 73 static inline void ?{}($thread & this, struct cluster & cl ) { this{ "Anonymous Thread", cl, 0p, 65000 }; } 74 static inline void ?{}($thread & this, struct cluster & cl, size_t stackSize ) { this{ "Anonymous Thread", cl, 0p, stackSize }; } 75 static inline void ?{}($thread & this, struct cluster & cl, void * storage, size_t storageSize ) { this{ "Anonymous Thread", cl, storage, storageSize }; } 76 static inline void ?{}($thread & this, const char * const name) { this{ name, *mainCluster, 0p, 65000 }; } 77 static inline void ?{}($thread & this, const char * const name, struct cluster & cl ) { this{ name, cl, 0p, 65000 }; } 78 static inline void ?{}($thread & this, const char * const name, struct cluster & cl, size_t stackSize ) { this{ name, cl, 0p, stackSize }; } 79 80 struct thread_dtor_guard_t { 81 monitor_dtor_guard_t mg; 82 }; 83 84 forall( dtype T | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) ) 85 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) ); 86 void ^?{}( thread_dtor_guard_t & this ); 72 87 73 88 //----------------------------------------------------------------------------- … … 88 103 void ^?{}( scoped(T)& this ); 89 104 90 void yield(); 91 void yield( unsigned times ); 105 //----------------------------------------------------------------------------- 106 // Scheduler API 92 107 93 static inline struct thread_desc * active_thread () { return TL_GET( this_thread ); } 108 //---------- 109 // Park thread: block until corresponding call to unpark, won't block if unpark is already called 110 void park( void ); 111 112 //---------- 113 // Unpark a thread, if the thread is already blocked, schedule it 114 // if the thread is not yet block, signal that it should rerun immediately 115 void unpark( $thread * this ); 116 117 forall( dtype T | is_thread(T) ) 118 static inline void unpark( T & this ) { if(!&this) return; unpark( get_thread( this ) );} 119 120 //---------- 121 // Yield: force thread to block and be rescheduled 122 bool force_yield( enum __Preemption_Reason ); 123 124 //---------- 125 // sleep: force thread to block and be rescheduled after Duration duration 126 void sleep( Duration duration ); 127 128 //---------- 129 // join 130 forall( dtype T | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) ) 131 T & join( T & this ); 94 132 95 133 // Local Variables: // -
libcfa/src/containers/vector.hfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Jul 5 18:00:07 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 10:01:18 201713 // Update Count : 312 // Last Modified On : Wed Jun 17 11:02:46 2020 13 // Update Count : 4 14 14 // 15 15 16 16 #pragma once 17 17 18 extern "C" {19 18 #include <stdbool.h> 20 }21 19 22 20 //------------------------------------------------------------------------------ -
libcfa/src/exception.c
rbdfc032 reef8dfb 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T hu Feb 22 18:17:34 201813 // Update Count : 1111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 16:27:00 2020 13 // Update Count : 35 14 14 // 15 15 16 // Normally we would get this from the CFA prelude. 16 17 #include <stddef.h> // for size_t 17 18 19 #include <unwind.h> // for struct _Unwind_Exception {...}; 20 18 21 #include "exception.h" 19 20 // Implementation of the secret header.21 22 22 23 #include <stdlib.h> 23 24 #include <stdio.h> 24 #include <unwind.h>25 25 #include <bits/debug.hfa> 26 27 // FIX ME: temporary hack to keep ARM build working 26 #include "concurrency/invoke.h" 27 #include "stdhdr/assert.h" 28 29 #if defined( __ARM_ARCH ) 30 #warning FIX ME: temporary hack to keep ARM build working 28 31 #ifndef _URC_FATAL_PHASE1_ERROR 29 #define _URC_FATAL_PHASE1_ERROR 232 #define _URC_FATAL_PHASE1_ERROR 3 30 33 #endif // ! _URC_FATAL_PHASE1_ERROR 31 34 #ifndef _URC_FATAL_PHASE2_ERROR 32 35 #define _URC_FATAL_PHASE2_ERROR 2 33 36 #endif // ! _URC_FATAL_PHASE2_ERROR 37 #endif // __ARM_ARCH 34 38 35 39 #include "lsda.h" 36 40 41 /* The exception class for our exceptions. Because of the vendor component 42 * its value would not be standard. 43 * Vendor: UWPL 44 * Language: CFA\0 45 */ 46 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643; 37 47 38 48 // Base exception vtable is abstract, you should not have base exceptions. 39 struct __cfa abi_ehm__base_exception_t_vtable40 ___cfa abi_ehm__base_exception_t_vtable_instance = {49 struct __cfaehm_base_exception_t_vtable 50 ___cfaehm_base_exception_t_vtable_instance = { 41 51 .parent = NULL, 42 52 .size = 0, … … 47 57 48 58 49 // Temperary global exception context. Does not work with concurency.50 struct exception_context_t {51 struct __cfaabi_ehm__try_resume_node * top_resume;52 struct __cfaabi_ehm__try_resume_node * current_resume;53 54 exception_t * current_exception;55 int current_handler_index;56 } shared_stack = {NULL, NULL, 0, 0};57 58 59 // Get the current exception context. 59 60 // There can be a single global until multithreading occurs, then each stack 60 // needs its own. It will have to be updated to handle that. 61 struct exception_context_t * this_exception_context() { 61 // needs its own. We get this from libcfathreads (no weak attribute). 62 __attribute__((weak)) struct exception_context_t * this_exception_context() { 63 static struct exception_context_t shared_stack = {NULL, NULL}; 62 64 return &shared_stack; 63 65 } 64 //#define SAVE_EXCEPTION_CONTEXT(to_name)65 //struct exception_context_t * to_name = this_exception_context();66 //exception * this_exception() {67 // return this_exception_context()->current_exception;68 //}69 70 71 // This macro should be the only thing that needs to change across machines.72 // Used in the personality function, way down in termination.73 // struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception_t *)74 #define MATCHER_FROM_CONTEXT(ptr_to_context) \75 (*(_Unwind_Reason_Code(**)(exception_t *))(_Unwind_GetCFA(ptr_to_context) + 8))76 66 77 67 78 68 // RESUMPTION ================================================================ 79 69 80 void __cfaabi_ehm__throw_resume(exception_t * except) { 81 82 __cfaabi_dbg_print_safe("Throwing resumption exception\n"); 83 84 struct __cfaabi_ehm__try_resume_node * original_head = shared_stack.current_resume; 85 struct __cfaabi_ehm__try_resume_node * current = 86 (original_head) ? original_head->next : shared_stack.top_resume; 87 88 for ( ; current ; current = current->next) { 89 shared_stack.current_resume = current; 90 if (current->handler(except)) { 91 shared_stack.current_resume = original_head; 92 return; 70 static void reset_top_resume(struct __cfaehm_try_resume_node ** store) { 71 this_exception_context()->top_resume = *store; 72 } 73 74 void __cfaehm_throw_resume(exception_t * except, void (*defaultHandler)(exception_t *)) { 75 struct exception_context_t * context = this_exception_context(); 76 77 __cfadbg_print_safe(exception, "Throwing resumption exception\n"); 78 79 { 80 __attribute__((cleanup(reset_top_resume))) 81 struct __cfaehm_try_resume_node * original_head = context->top_resume; 82 struct __cfaehm_try_resume_node * current = context->top_resume; 83 84 for ( ; current ; current = current->next) { 85 context->top_resume = current->next; 86 if (current->handler(except)) { 87 return; 88 } 93 89 } 94 } 95 96 __cfaabi_dbg_print_safe("Unhandled exception\n"); 97 shared_stack.current_resume = original_head; 98 99 // Fall back to termination: 100 __cfaabi_ehm__throw_terminate(except); 101 // TODO: Default handler for resumption. 90 } // End the search and return to the top of the stack. 91 92 // No handler found, fall back to the default operation. 93 __cfadbg_print_safe(exception, "Unhandled exception\n"); 94 defaultHandler(except); 102 95 } 103 96 … … 106 99 // be added after the node is built but before it is made the top node. 107 100 108 void __cfa abi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,101 void __cfaehm_try_resume_setup(struct __cfaehm_try_resume_node * node, 109 102 _Bool (*handler)(exception_t * except)) { 110 node->next = shared_stack.top_resume; 103 struct exception_context_t * context = this_exception_context(); 104 node->next = context->top_resume; 111 105 node->handler = handler; 112 shared_stack.top_resume = node; 113 } 114 115 void __cfaabi_ehm__try_resume_cleanup(struct __cfaabi_ehm__try_resume_node * node) { 116 shared_stack.top_resume = node->next; 117 } 118 119 120 // TERMINATION =============================================================== 121 122 // MEMORY MANAGEMENT (still for integers) 123 // May have to move to cfa for constructors and destructors (references). 124 125 struct __cfaabi_ehm__node { 126 struct __cfaabi_ehm__node * next; 127 }; 106 context->top_resume = node; 107 } 108 109 void __cfaehm_try_resume_cleanup(struct __cfaehm_try_resume_node * node) { 110 struct exception_context_t * context = this_exception_context(); 111 context->top_resume = node->next; 112 } 113 114 115 // MEMORY MANAGEMENT ========================================================= 128 116 129 117 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node))) 130 #define EXCEPT_TO_NODE(except) ((struct __cfaabi_ehm__node *)(except) - 1) 118 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1) 119 #define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind)) 120 #define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL) 121 122 // How to clean up an exception in various situations. 123 static void __cfaehm_exception_cleanup( 124 _Unwind_Reason_Code reason, 125 struct _Unwind_Exception * exception) { 126 switch (reason) { 127 case _URC_FOREIGN_EXCEPTION_CAUGHT: 128 // This one we could clean-up to allow cross-language exceptions. 129 case _URC_FATAL_PHASE1_ERROR: 130 case _URC_FATAL_PHASE2_ERROR: 131 default: 132 abort(); 133 } 134 } 131 135 132 136 // Creates a copy of the indicated exception and sets current_exception to it. 133 static void __cfa abi_ehm__allocate_exception( exception_t * except ) {137 static void __cfaehm_allocate_exception( exception_t * except ) { 134 138 struct exception_context_t * context = this_exception_context(); 135 139 136 140 // Allocate memory for the exception. 137 struct __cfa abi_ehm__node * store = malloc(138 sizeof( struct __cfa abi_ehm__node ) + except->virtual_table->size );141 struct __cfaehm_node * store = malloc( 142 sizeof( struct __cfaehm_node ) + except->virtual_table->size ); 139 143 140 144 if ( ! store ) { … … 143 147 } 144 148 149 // Initialize the node: 150 exception_t * except_store = NODE_TO_EXCEPT(store); 151 store->unwind_exception.exception_class = __cfaehm_exception_class; 152 store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup; 153 store->handler_index = 0; 154 except->virtual_table->copy( except_store, except ); 155 145 156 // Add the node to the list: 146 store->next = EXCEPT_TO_NODE(context->current_exception); 147 context->current_exception = NODE_TO_EXCEPT(store); 148 149 // Copy the exception to storage. 150 except->virtual_table->copy( context->current_exception, except ); 157 store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception); 158 context->current_exception = except_store; 151 159 } 152 160 153 161 // Delete the provided exception, unsetting current_exception if relivant. 154 static void __cfa abi_ehm__delete_exception( exception_t * except ) {155 struct exception_context_t * context = this_exception_context(); 156 157 __cfa abi_dbg_print_safe("Deleting Exception\n");162 static void __cfaehm_delete_exception( exception_t * except ) { 163 struct exception_context_t * context = this_exception_context(); 164 165 __cfadbg_print_safe(exception, "Deleting Exception\n"); 158 166 159 167 // Remove the exception from the list. 160 struct __cfa abi_ehm__node * to_free = EXCEPT_TO_NODE(except);161 struct __cfa abi_ehm__node * node;168 struct __cfaehm_node * to_free = EXCEPT_TO_NODE(except); 169 struct __cfaehm_node * node; 162 170 163 171 if ( context->current_exception == except ) { 164 172 node = to_free->next; 165 context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;173 context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node); 166 174 } else { 167 175 node = EXCEPT_TO_NODE(context->current_exception); 168 176 // It may always be in the first or second position. 169 while ( to_free != node->next ) {177 while ( to_free != node->next ) { 170 178 node = node->next; 171 179 } … … 178 186 } 179 187 180 // If this isn't a rethrow (*except==0), delete the provided exception. 181 void __cfaabi_ehm__cleanup_terminate( void * except ) { 182 if ( *(void**)except ) __cfaabi_ehm__delete_exception( *(exception_t **)except ); 183 } 184 185 186 // We need a piece of storage to raise the exception 187 struct _Unwind_Exception this_exception_storage; 188 // CANCELLATION ============================================================== 188 189 189 190 // Function needed by force unwind … … 192 193 int version, 193 194 _Unwind_Action actions, 194 _Unwind_Exception_Class exception Class,195 _Unwind_Exception_Class exception_class, 195 196 struct _Unwind_Exception * unwind_exception, 196 struct _Unwind_Context * context, 197 void * some_param) { 198 if( actions & _UA_END_OF_STACK ) exit(1); 199 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 200 201 return _URC_FATAL_PHASE2_ERROR; 197 struct _Unwind_Context * unwind_context, 198 void * stop_param) { 199 // Verify actions follow the rules we expect. 200 verify(actions & _UA_CLEANUP_PHASE); 201 verify(actions & _UA_FORCE_UNWIND); 202 verify(!(actions & _UA_SEARCH_PHASE)); 203 verify(!(actions & _UA_HANDLER_FRAME)); 204 205 if ( actions & _UA_END_OF_STACK ) { 206 abort(); 207 } else { 208 return _URC_NO_REASON; 209 } 210 } 211 212 __attribute__((weak)) _Unwind_Reason_Code 213 __cfaehm_cancellation_unwind( struct _Unwind_Exception * exception ) { 214 return _Unwind_ForcedUnwind( exception, _Stop_Fn, (void*)0x22 ); 215 } 216 217 // Cancel the current stack, prefroming approprate clean-up and messaging. 218 void __cfaehm_cancel_stack( exception_t * exception ) { 219 __cfaehm_allocate_exception( exception ); 220 221 struct exception_context_t * context = this_exception_context(); 222 struct __cfaehm_node * node = EXCEPT_TO_NODE(context->current_exception); 223 224 // Preform clean-up of any extra active exceptions. 225 while ( node->next ) { 226 struct __cfaehm_node * to_free = node->next; 227 node->next = to_free->next; 228 exception_t * except = NODE_TO_EXCEPT( to_free ); 229 except->virtual_table->free( except ); 230 free( to_free ); 231 } 232 233 _Unwind_Reason_Code ret; 234 ret = __cfaehm_cancellation_unwind( &node->unwind_exception ); 235 printf("UNWIND ERROR %d after force unwind\n", ret); 236 abort(); 237 } 238 239 240 // TERMINATION =============================================================== 241 242 // If this isn't a rethrow (*except==0), delete the provided exception. 243 void __cfaehm_cleanup_terminate( void * except ) { 244 if ( *(void**)except ) __cfaehm_delete_exception( *(exception_t **)except ); 245 } 246 247 static void __cfaehm_cleanup_default( exception_t ** except ) { 248 __cfaehm_delete_exception( *except ); 249 *except = NULL; 202 250 } 203 251 204 252 // The exception that is being thrown must already be stored. 205 __attribute__((noreturn)) void __cfaabi_ehm__begin_unwind(void) { 206 if ( ! this_exception_context()->current_exception ) { 253 static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) { 254 struct exception_context_t * context = this_exception_context(); 255 if ( NULL == context->current_exception ) { 207 256 printf("UNWIND ERROR missing exception in begin unwind\n"); 208 257 abort(); 209 258 } 210 259 struct _Unwind_Exception * storage = 260 &EXCEPT_TO_NODE(context->current_exception)->unwind_exception; 211 261 212 262 // Call stdlibc to raise the exception 213 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 263 __cfadbg_print_safe(exception, "Begin unwinding (storage &p, context %p)\n", storage, context); 264 _Unwind_Reason_Code ret = _Unwind_RaiseException( storage ); 214 265 215 266 // If we reach here it means something happened. For resumption to work we need to find a way … … 220 271 // the whole stack. 221 272 222 if( ret == _URC_END_OF_STACK ) { 223 // No proper handler was found. This can be handled in many ways, C++ calls std::terminate. 224 // Here we force unwind the stack, basically raising a cancellation. 225 printf("Uncaught exception %p\n", &this_exception_storage); 226 227 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 ); 228 printf("UNWIND ERROR %d after force unwind\n", ret); 273 // We did not simply reach the end of the stack without finding a handler. This is an error. 274 if ( ret != _URC_END_OF_STACK ) { 275 printf("UNWIND ERROR %d after raise exception\n", ret); 229 276 abort(); 230 277 } 231 278 232 // We did not simply reach the end of the stack without finding a handler. This is an error. 233 printf("UNWIND ERROR %d after raise exception\n", ret); 279 // No handler found, go to the default operation. 280 __cfadbg_print_safe(exception, "Uncaught exception %p\n", storage); 281 282 __attribute__((cleanup(__cfaehm_cleanup_default))) 283 exception_t * exception = context->current_exception; 284 defaultHandler( exception ); 285 } 286 287 void __cfaehm_throw_terminate( exception_t * val, void (*defaultHandler)(exception_t *) ) { 288 __cfadbg_print_safe(exception, "Throwing termination exception\n"); 289 290 __cfaehm_allocate_exception( val ); 291 __cfaehm_begin_unwind( defaultHandler ); 292 } 293 294 static __attribute__((noreturn)) void __cfaehm_rethrow_adapter( exception_t * except ) { 295 // TODO: Print some error message. 296 (void)except; 234 297 abort(); 235 298 } 236 299 237 void __cfaabi_ehm__throw_terminate( exception_t * val ) { 238 __cfaabi_dbg_print_safe("Throwing termination exception\n"); 239 240 __cfaabi_ehm__allocate_exception( val ); 241 __cfaabi_ehm__begin_unwind(); 242 } 243 244 void __cfaabi_ehm__rethrow_terminate(void) { 245 __cfaabi_dbg_print_safe("Rethrowing termination exception\n"); 246 247 __cfaabi_ehm__begin_unwind(); 248 } 249 250 #if defined(PIC) 251 #warning Exceptions not yet supported when using Position-Independent Code 252 __attribute__((noinline)) 253 void __cfaabi_ehm__try_terminate(void (*try_block)(), 254 void (*catch_block)(int index, exception_t * except), 255 __attribute__((unused)) int (*match_block)(exception_t * except)) { 300 void __cfaehm_rethrow_terminate(void) { 301 __cfadbg_print_safe(exception, "Rethrowing termination exception\n"); 302 303 __cfaehm_begin_unwind( __cfaehm_rethrow_adapter ); 256 304 abort(); 257 305 } 258 #else // PIC 306 307 #if defined( __x86_64 ) || defined( __i386 ) 259 308 // This is our personality routine. For every stack frame annotated with 260 309 // ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding. 261 310 // Once in the search phase and once in the cleanup phase. 262 _Unwind_Reason_Code __gcfa_personality_v0 ( 263 int version, _Unwind_Action actions, unsigned long long exceptionClass, 264 struct _Unwind_Exception* unwind_exception, 265 struct _Unwind_Context* context) 311 _Unwind_Reason_Code __gcfa_personality_v0( 312 int version, 313 _Unwind_Action actions, 314 unsigned long long exception_class, 315 struct _Unwind_Exception * unwind_exception, 316 struct _Unwind_Context * unwind_context) 266 317 { 267 318 268 //__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context)); 269 __cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", 270 version, actions, exceptionClass, unwind_exception, context); 271 272 // If we've reached the end of the stack then there is nothing much we can do... 273 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK; 274 319 //__cfadbg_print_safe(exception, "CFA: 0x%lx\n", _Unwind_GetCFA(context)); 320 __cfadbg_print_safe(exception, "Personality function (%d, %x, %llu, %p, %p):", 321 version, actions, exception_class, unwind_exception, unwind_context); 322 323 // Verify that actions follow the rules we expect. 324 // This function should never be called at the end of the stack. 325 verify(!(actions & _UA_END_OF_STACK)); 326 // Either only the search phase flag is set or... 275 327 if (actions & _UA_SEARCH_PHASE) { 276 __cfaabi_dbg_print_safe(" lookup phase"); 277 } 278 else if (actions & _UA_CLEANUP_PHASE) { 279 __cfaabi_dbg_print_safe(" cleanup phase"); 280 } 281 // Just in case, probably can't actually happen 282 else { 283 printf(" error\n"); 284 return _URC_FATAL_PHASE1_ERROR; 328 verify(actions == _UA_SEARCH_PHASE); 329 __cfadbg_print_safe(exception, " lookup phase"); 330 // ... we are in clean-up phase. 331 } else { 332 verify(actions & _UA_CLEANUP_PHASE); 333 __cfadbg_print_safe(exception, " cleanup phase"); 334 // We shouldn't be the handler frame during forced unwind. 335 if (actions & _UA_HANDLER_FRAME) { 336 verify(!(actions & _UA_FORCE_UNWIND)); 337 __cfadbg_print_safe(exception, " (handler frame)"); 338 } else if (actions & _UA_FORCE_UNWIND) { 339 __cfadbg_print_safe(exception, " (force unwind)"); 340 } 285 341 } 286 342 287 343 // Get a pointer to the language specific data from which we will read what we need 288 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData(context );289 290 if ( !lsd ) { //Nothing to do, keep unwinding344 const unsigned char * lsd = _Unwind_GetLanguageSpecificData( unwind_context ); 345 346 if ( !lsd ) { //Nothing to do, keep unwinding 291 347 printf(" no LSD"); 292 348 goto UNWIND; … … 295 351 // Get the instuction pointer and a reading pointer into the exception table 296 352 lsda_header_info lsd_info; 297 const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info); 298 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context ); 353 const unsigned char * cur_ptr = parse_lsda_header(unwind_context, lsd, &lsd_info); 354 _Unwind_Ptr instruction_ptr = _Unwind_GetIP(unwind_context); 355 356 struct exception_context_t * context = this_exception_context(); 299 357 300 358 // Linearly search the table for stuff to do 301 while ( cur_ptr < lsd_info.action_table ) {359 while ( cur_ptr < lsd_info.action_table ) { 302 360 _Unwind_Ptr callsite_start; 303 361 _Unwind_Ptr callsite_len; … … 312 370 313 371 // Have we reach the correct frame info yet? 314 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {372 if ( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) { 315 373 #ifdef __CFA_DEBUG_PRINT__ 316 374 void * ls = (void*)lsd_info.Start; … … 320 378 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len; 321 379 void * ip = (void*)instruction_ptr; 322 __cfa abi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",380 __cfadbg_print_safe(exception, "\nfound %p - %p (%p, %p, %p), looking for %p\n", 323 381 bp, ep, ls, cs, cl, ip); 324 382 #endif // __CFA_DEBUG_PRINT__ … … 327 385 328 386 // Have we gone too far? 329 if ( lsd_info.Start + callsite_start > instruction_ptr ) {387 if ( lsd_info.Start + callsite_start > instruction_ptr ) { 330 388 printf(" gone too far"); 331 389 break; 332 390 } 333 391 334 // Something to do? 335 if( callsite_landing_pad ) { 336 // Which phase are we in 337 if (actions & _UA_SEARCH_PHASE) { 338 // In search phase, these means we found a potential handler we must check. 339 340 // We have arbitrarily decided that 0 means nothing to do and 1 means there is 341 // a potential handler. This doesn't seem to conflict the gcc default behavior. 342 if (callsite_action != 0) { 343 // Now we want to run some code to see if the handler matches 344 // This is the tricky part where we want to the power to run arbitrary code 345 // However, generating a new exception table entry and try routine every time 346 // is way more expansive than we might like 347 // The information we have is : 348 // - The GR (Series of registers) 349 // GR1=GP Global Pointer of frame ref by context 350 // - The instruction pointer 351 // - The instruction pointer info (???) 352 // - The CFA (Canonical Frame Address) 353 // - The BSP (Probably the base stack pointer) 354 355 356 // The current apprach uses one exception table entry per try block 357 _uleb128_t imatcher; 358 // Get the relative offset to the {...}? 359 cur_ptr = read_uleb128(cur_ptr, &imatcher); 360 361 _Unwind_Reason_Code (*matcher)(exception_t *) = 362 MATCHER_FROM_CONTEXT(context); 363 int index = matcher(shared_stack.current_exception); 364 _Unwind_Reason_Code ret = (0 == index) 365 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 366 shared_stack.current_handler_index = index; 367 368 // Based on the return value, check if we matched the exception 369 if( ret == _URC_HANDLER_FOUND) { 370 __cfaabi_dbg_print_safe(" handler found\n"); 371 } else { 372 __cfaabi_dbg_print_safe(" no handler\n"); 373 } 374 return ret; 392 // Check for what we must do: 393 if ( 0 == callsite_landing_pad ) { 394 // Nothing to do, move along 395 __cfadbg_print_safe(exception, " no landing pad"); 396 } else if (actions & _UA_SEARCH_PHASE) { 397 // In search phase, these means we found a potential handler we must check. 398 399 // We have arbitrarily decided that 0 means nothing to do and 1 means there is 400 // a potential handler. This doesn't seem to conflict the gcc default behavior. 401 if (callsite_action != 0) { 402 // Now we want to run some code to see if the handler matches 403 // This is the tricky part where we want to the power to run arbitrary code 404 // However, generating a new exception table entry and try routine every time 405 // is way more expansive than we might like 406 // The information we have is : 407 // - The GR (Series of registers) 408 // GR1=GP Global Pointer of frame ref by context 409 // - The instruction pointer 410 // - The instruction pointer info (???) 411 // - The CFA (Canonical Frame Address) 412 // - The BSP (Probably the base stack pointer) 413 414 // The current apprach uses one exception table entry per try block 415 _uleb128_t imatcher; 416 // Get the relative offset to the {...}? 417 cur_ptr = read_uleb128(cur_ptr, &imatcher); 418 419 _Unwind_Word match_pos = 420 # if defined( __x86_64 ) 421 _Unwind_GetCFA(unwind_context) + 8; 422 # elif defined( __i386 ) 423 _Unwind_GetCFA(unwind_context) + 24; 424 # elif defined( __ARM_ARCH ) 425 # warning FIX ME: check if anything needed for ARM 426 42; 427 # endif 428 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos; 429 430 int index = matcher(context->current_exception); 431 _Unwind_Reason_Code ret = (0 == index) 432 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 433 UNWIND_TO_NODE(unwind_exception)->handler_index = index; 434 435 // Based on the return value, check if we matched the exception 436 if (ret == _URC_HANDLER_FOUND) { 437 __cfadbg_print_safe(exception, " handler found\n"); 438 } else { 439 // TODO: Continue the search if there is more in the table. 440 __cfadbg_print_safe(exception, " no handler\n"); 375 441 } 376 377 // This is only a cleanup handler, ignore it 378 __cfaabi_dbg_print_safe(" no action"); 442 return ret; 379 443 } 380 else if (actions & _UA_CLEANUP_PHASE) { 381 382 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 383 // If this is a potential exception handler 384 // but not the one that matched the exception in the seach phase, 385 // just ignore it 386 goto UNWIND; 387 } 388 389 // We need to run some clean-up or a handler 390 // These statment do the right thing but I don't know any specifics at all 391 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception ); 392 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 ); 393 394 // I assume this sets the instruction pointer to the adress of the landing pad 395 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT 396 _Unwind_SetIP( context, ((lsd_info.LPStart) + (callsite_landing_pad)) ); 397 398 __cfaabi_dbg_print_safe(" action\n"); 399 400 // Return have some action to run 401 return _URC_INSTALL_CONTEXT; 444 445 // This is only a cleanup handler, ignore it 446 __cfadbg_print_safe(exception, " no action"); 447 } else { 448 // In clean-up phase, no destructors here but this could be the handler. 449 450 if ( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 451 // If this is a potential exception handler 452 // but not the one that matched the exception in the seach phase, 453 // just ignore it 454 goto UNWIND; 402 455 } 456 457 // We need to run some clean-up or a handler 458 // These statment do the right thing but I don't know any specifics at all 459 _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(0), 460 (_Unwind_Ptr)unwind_exception ); 461 _Unwind_SetGR( unwind_context, __builtin_eh_return_data_regno(1), 0 ); 462 463 // I assume this sets the instruction pointer to the adress of the landing pad 464 // It doesn't actually set it, it only state the value that needs to be set once we 465 // return _URC_INSTALL_CONTEXT 466 _Unwind_SetIP( unwind_context, ((lsd_info.LPStart) + (callsite_landing_pad)) ); 467 468 __cfadbg_print_safe(exception, " action\n"); 469 470 // Return have some action to run 471 return _URC_INSTALL_CONTEXT; 403 472 } 404 405 // Nothing to do, move along406 __cfaabi_dbg_print_safe(" no landing pad");407 473 } 408 474 // No handling found 409 __cfa abi_dbg_print_safe(" table end reached\n");475 __cfadbg_print_safe(exception, " table end reached"); 410 476 411 477 UNWIND: 412 __cfa abi_dbg_print_safe(" unwind\n");478 __cfadbg_print_safe(exception, " unwind\n"); 413 479 414 480 // Keep unwinding the stack 415 481 return _URC_CONTINUE_UNWIND; 416 482 } 483 484 #pragma GCC push_options 485 #pragma GCC optimize(0) 417 486 418 487 // Try statements are hoisted out see comments for details. While this could probably be unique 419 488 // and simply linked from libcfa but there is one problem left, see the exception table for details 420 489 __attribute__((noinline)) 421 void __cfa abi_ehm__try_terminate(void (*try_block)(),490 void __cfaehm_try_terminate(void (*try_block)(), 422 491 void (*catch_block)(int index, exception_t * except), 423 492 __attribute__((unused)) int (*match_block)(exception_t * except)) { … … 425 494 //! printf("%p %p %p %p\n", &try_block, &catch_block, &match_block, &xy); 426 495 427 // Setup statments: These 2 statments won't actually result in any code, they only setup global tables.428 // However, they clobber gcc cancellation support from gcc. We can replace the personality routine but429 // replacing the exception table gcc generates is not really doable, it generates labels based on how the430 // assembly works.431 432 496 // Setup the personality routine and exception table. 497 // Unforturnately these clobber gcc cancellation support which means we can't get access to 498 // the attribute cleanup tables at the same time. We would have to inspect the assembly to 499 // create a new set ourselves. 500 #ifdef __PIC__ 501 asm volatile (".cfi_personality 0x9b,CFA.ref.__gcfa_personality_v0"); 502 asm volatile (".cfi_lsda 0x1b, .LLSDACFA2"); 503 #else 433 504 asm volatile (".cfi_personality 0x3,__gcfa_personality_v0"); 434 505 asm volatile (".cfi_lsda 0x3, .LLSDACFA2"); 506 #endif 435 507 436 508 // Label which defines the start of the area for which the handler is setup. … … 450 522 // Label which defines the end of the area for which the handler is setup. 451 523 asm volatile (".TRYEND:"); 452 // Label which defines the start of the exception landing pad. Basically what is called when the exception is453 // caught. Note, if multiple handlers are given, the multiplexing should be done by the generated code, not the454 // exception runtime.524 // Label which defines the start of the exception landing pad. Basically what is called when 525 // the exception is caught. Note, if multiple handlers are given, the multiplexing should be 526 // done by the generated code, not the exception runtime. 455 527 asm volatile (".CATCH:"); 456 528 457 529 // Exception handler 458 catch_block( shared_stack.current_handler_index, 459 shared_stack.current_exception ); 530 // Note: Saving the exception context on the stack breaks termination exceptions. 531 catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index, 532 this_exception_context()->current_exception ); 460 533 } 461 534 … … 464 537 // have a single call to the try routine. 465 538 466 #if defined( __i386 ) || defined( __x86_64 ) 539 #ifdef __PIC__ 540 asm ( 541 // HEADER 542 ".LFECFA1:\n" 543 " .globl __gcfa_personality_v0\n" 544 " .section .gcc_except_table,\"a\",@progbits\n" 545 // TABLE HEADER (important field is the BODY length at the end) 546 ".LLSDACFA2:\n" 547 " .byte 0xff\n" 548 " .byte 0xff\n" 549 " .byte 0x1\n" 550 " .uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n" 551 // BODY (language specific data) 552 // This uses language specific data and can be modified arbitrarily 553 // We use handled area offset, handled area length, 554 // handler landing pad offset and 1 (action code, gcc seems to use 0). 555 ".LLSDACSBCFA2:\n" 556 " .uleb128 .TRYSTART-__cfaehm_try_terminate\n" 557 " .uleb128 .TRYEND-.TRYSTART\n" 558 " .uleb128 .CATCH-__cfaehm_try_terminate\n" 559 " .uleb128 1\n" 560 ".LLSDACSECFA2:\n" 561 // TABLE FOOTER 562 " .text\n" 563 " .size __cfaehm_try_terminate, .-__cfaehm_try_terminate\n" 564 ); 565 566 // Somehow this piece of helps with the resolution of debug symbols. 567 __attribute__((unused)) static const int dummy = 0; 568 569 asm ( 570 // Add a hidden symbol which points at the function. 571 " .hidden CFA.ref.__gcfa_personality_v0\n" 572 " .weak CFA.ref.__gcfa_personality_v0\n" 573 // No clue what this does specifically 574 " .section .data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n" 575 " .align 8\n" 576 " .type CFA.ref.__gcfa_personality_v0, @object\n" 577 " .size CFA.ref.__gcfa_personality_v0, 8\n" 578 "CFA.ref.__gcfa_personality_v0:\n" 579 #if defined( __x86_64 ) 580 " .quad __gcfa_personality_v0\n" 581 #else // then __i386 582 " .long __gcfa_personality_v0\n" 583 #endif 584 ); 585 #else // __PIC__ 467 586 asm ( 468 587 // HEADER … … 479 598 ".LLSDACSBCFA2:\n" 480 599 // Handled area start (relative to start of function) 481 " .uleb128 .TRYSTART-__cfa abi_ehm__try_terminate\n"600 " .uleb128 .TRYSTART-__cfaehm_try_terminate\n" 482 601 // Handled area length 483 602 " .uleb128 .TRYEND-.TRYSTART\n" 484 603 // Handler landing pad address (relative to start of function) 485 " .uleb128 .CATCH-__cfa abi_ehm__try_terminate\n"604 " .uleb128 .CATCH-__cfaehm_try_terminate\n" 486 605 // Action code, gcc seems to always use 0. 487 606 " .uleb128 1\n" … … 489 608 ".LLSDACSECFA2:\n" 490 609 " .text\n" 491 " .size __cfa abi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"610 " .size __cfaehm_try_terminate, .-__cfaehm_try_terminate\n" 492 611 " .ident \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n" 493 //" .section .note.GNU-stack,\"x\",@progbits\n"612 " .section .note.GNU-stack,\"x\",@progbits\n" 494 613 ); 495 #endif // __i386 || __x86_64 496 #endif // PIC 614 #endif // __PIC__ 615 616 #pragma GCC pop_options 617 618 #elif defined( __ARM_ARCH ) 619 _Unwind_Reason_Code __gcfa_personality_v0( 620 int version, 621 _Unwind_Action actions, 622 unsigned long long exception_class, 623 struct _Unwind_Exception * unwind_exception, 624 struct _Unwind_Context * unwind_context) { 625 return _URC_CONTINUE_UNWIND; 626 } 627 628 __attribute__((noinline)) 629 void __cfaehm_try_terminate(void (*try_block)(), 630 void (*catch_block)(int index, exception_t * except), 631 __attribute__((unused)) int (*match_block)(exception_t * except)) { 632 } 633 #else 634 #error unsupported hardware architecture 635 #endif // __x86_64 || __i386 -
libcfa/src/exception.h
rbdfc032 reef8dfb 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // exception.h -- Builtins for exception handling.7 // exception.h -- Internal exception handling definitions. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T hu Feb 22 18:11:15 201813 // Update Count : 811 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 14:45:00 2020 13 // Update Count : 11 14 14 // 15 15 16 16 #pragma once 17 17 18 // This could be considered several headers. All are internal to the exception 19 // system but needed to depending on whether they are C/Cforall code and 20 // whether or not they are part of the builtins. 18 21 19 22 #ifdef __cforall … … 21 24 #endif 22 25 23 struct __cfaabi_ehm__base_exception_t; 24 typedef struct __cfaabi_ehm__base_exception_t exception_t; 25 struct __cfaabi_ehm__base_exception_t_vtable { 26 const struct __cfaabi_ehm__base_exception_t_vtable * parent; 26 // Included in C code or the built-ins. 27 #if !defined(__cforall) || defined(__cforall_builtins__) 28 29 struct __cfaehm_base_exception_t; 30 typedef struct __cfaehm_base_exception_t exception_t; 31 struct __cfaehm_base_exception_t_vtable { 32 const struct __cfaehm_base_exception_t_vtable * parent; 27 33 size_t size; 28 void (*copy)(struct __cfa abi_ehm__base_exception_t *this,29 struct __cfa abi_ehm__base_exception_t * other);30 void (*free)(struct __cfa abi_ehm__base_exception_t *this);31 const char * (*msg)(struct __cfa abi_ehm__base_exception_t *this);34 void (*copy)(struct __cfaehm_base_exception_t *this, 35 struct __cfaehm_base_exception_t * other); 36 void (*free)(struct __cfaehm_base_exception_t *this); 37 const char * (*msg)(struct __cfaehm_base_exception_t *this); 32 38 }; 33 struct __cfa abi_ehm__base_exception_t {34 struct __cfa abi_ehm__base_exception_t_vtable const * virtual_table;39 struct __cfaehm_base_exception_t { 40 struct __cfaehm_base_exception_t_vtable const * virtual_table; 35 41 }; 36 extern struct __cfa abi_ehm__base_exception_t_vtable37 ___cfa abi_ehm__base_exception_t_vtable_instance;42 extern struct __cfaehm_base_exception_t_vtable 43 ___cfaehm_base_exception_t_vtable_instance; 38 44 39 45 46 void __cfaehm_cancel_stack(exception_t * except) __attribute__((noreturn)); 47 40 48 // Used in throw statement translation. 41 void __cfa abi_ehm__throw_terminate(exception_t * except) __attribute__((noreturn));42 void __cfa abi_ehm__rethrow_terminate() __attribute__((noreturn));43 void __cfa abi_ehm__throw_resume(exception_t * except);49 void __cfaehm_throw_terminate(exception_t * except, void (*)(exception_t *)); 50 void __cfaehm_rethrow_terminate() __attribute__((noreturn)); 51 void __cfaehm_throw_resume(exception_t * except, void (*)(exception_t *)); 44 52 45 53 // Function catches termination exceptions. 46 void __cfa abi_ehm__try_terminate(47 48 49 54 void __cfaehm_try_terminate( 55 void (*try_block)(), 56 void (*catch_block)(int index, exception_t * except), 57 int (*match_block)(exception_t * except)); 50 58 51 59 // Clean-up the exception in catch blocks. 52 void __cfa abi_ehm__cleanup_terminate(void * except);60 void __cfaehm_cleanup_terminate(void * except); 53 61 54 62 // Data structure creates a list of resume handlers. 55 struct __cfa abi_ehm__try_resume_node {56 struct __cfaabi_ehm__try_resume_node * next;57 63 struct __cfaehm_try_resume_node { 64 struct __cfaehm_try_resume_node * next; 65 _Bool (*handler)(exception_t * except); 58 66 }; 59 67 60 68 // These act as constructor and destructor for the resume node. 61 void __cfa abi_ehm__try_resume_setup(62 struct __cfaabi_ehm__try_resume_node * node,63 64 void __cfa abi_ehm__try_resume_cleanup(65 struct __cfaabi_ehm__try_resume_node * node);69 void __cfaehm_try_resume_setup( 70 struct __cfaehm_try_resume_node * node, 71 _Bool (*handler)(exception_t * except)); 72 void __cfaehm_try_resume_cleanup( 73 struct __cfaehm_try_resume_node * node); 66 74 67 75 // Check for a standard way to call fake deconstructors. 68 struct __cfaabi_ehm__cleanup_hook {}; 76 struct __cfaehm_cleanup_hook {}; 77 78 #endif 79 80 // Included in C code and the library. 81 #if !defined(__cforall) || !defined(__cforall_builtins__) 82 struct __cfaehm_node { 83 struct _Unwind_Exception unwind_exception; 84 struct __cfaehm_node * next; 85 int handler_index; 86 }; 87 88 static inline exception_t * __cfaehm_cancellation_exception( 89 struct _Unwind_Exception * unwind_exception ) { 90 return (exception_t *)(1 + (struct __cfaehm_node *)unwind_exception); 91 } 92 #endif 69 93 70 94 #ifdef __cforall 71 95 } 96 97 // Built-ins not visible in C. 98 #if defined(__cforall_builtins__) 99 100 // Not all the built-ins can be expressed in C. These can't be 101 // implemented in the .c file either so they all have to be inline. 102 103 trait is_exception(dtype exceptT, dtype virtualT) { 104 /* The first field must be a pointer to a virtual table. 105 * That virtual table must be a decendent of the base exception virtual table. 106 */ 107 virtualT const & get_exception_vtable(exceptT *); 108 // Always returns the virtual table for this type (associated types hack). 109 }; 110 111 trait is_termination_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) { 112 void defaultTerminationHandler(exceptT &); 113 }; 114 115 trait is_resumption_exception(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) { 116 void defaultResumptionHandler(exceptT &); 117 }; 118 119 forall(dtype exceptT, dtype virtualT | is_termination_exception(exceptT, virtualT)) 120 static inline void $throw(exceptT & except) { 121 __cfaehm_throw_terminate( 122 (exception_t *)&except, 123 (void(*)(exception_t *))defaultTerminationHandler 124 ); 125 } 126 127 forall(dtype exceptT, dtype virtualT | is_resumption_exception(exceptT, virtualT)) 128 static inline void $throwResume(exceptT & except) { 129 __cfaehm_throw_resume( 130 (exception_t *)&except, 131 (void(*)(exception_t *))defaultResumptionHandler 132 ); 133 } 134 135 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) 136 static inline void cancel_stack(exceptT & except) __attribute__((noreturn)) { 137 __cfaehm_cancel_stack( (exception_t *)&except ); 138 } 139 140 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) 141 static inline void defaultTerminationHandler(exceptT & except) { 142 return cancel_stack( except ); 143 } 144 145 forall(dtype exceptT, dtype virtualT | is_exception(exceptT, virtualT)) 146 static inline void defaultResumptionHandler(exceptT & except) { 147 throw except; 148 } 149 72 150 #endif 151 152 #endif -
libcfa/src/executor.cfa
rbdfc032 reef8dfb 4 4 // buffer. 5 5 6 #include <bits/containers.hfa>7 6 #include <thread.hfa> 8 #include < stdio.h>7 #include <containers/list.hfa> 9 8 10 forall( dtype T ) 11 monitor Buffer { // unbounded buffer 12 __queue_t( T ) queue; // unbounded list of work requests 13 condition delay; 14 }; // Buffer 15 forall( dtype T | is_node(T) ) { 16 void insert( Buffer( T ) & mutex buf, T * elem ) with(buf) { 17 append( queue, elem ); // insert element into buffer 18 signal( delay ); // restart 19 } // insert 9 forall( dtype T | $dlistable(T, T) ) { 10 monitor Buffer { // unbounded buffer 11 dlist( T, T ) queue; // unbounded list of work requests 12 condition delay; 13 }; // Buffer 20 14 21 T * remove( Buffer( T ) & mutex buf) with(buf) {22 if ( queue.head != 0 ) wait( delay ); // no request to process ? => wait23 // return pop_head( queue ); 24 } // remove 25 } // distribution 15 void insert( Buffer(T) & mutex buf, T * elem ) with(buf) { 16 dlist( T, T ) * qptr = &queue; // workaround https://cforall.uwaterloo.ca/trac/ticket/166 17 insert_last( *qptr, *elem ); // insert element into buffer 18 signal( delay ); // restart 19 } // insert 26 20 27 struct WRequest { // client request, no return 28 void (* action)( void ); 29 WRequest * next; // intrusive queue field 21 T * remove( Buffer(T) & mutex buf ) with(buf) { 22 dlist( T, T ) * qptr = &queue; // workaround https://cforall.uwaterloo.ca/trac/ticket/166 23 // if ( (*qptr)`is_empty ) wait( delay ); // no request to process ? => wait 24 if ( (*qptr)`is_empty ) return 0p; // no request to process ? => wait 25 return &pop_first( *qptr ); 26 } // remove 27 } // forall 28 29 struct WRequest { // client request, no return 30 void (* action)( void ); 31 DLISTED_MGD_IMPL_IN(WRequest) 30 32 }; // WRequest 33 DLISTED_MGD_IMPL_OUT(WRequest) 31 34 32 WRequest *& get_next( WRequest & this ) { return this.next; } 33 void ?{}( WRequest & req ) with(req) { action = 0; next = 0; } 34 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; next = 0; } 35 void ?{}( WRequest & req ) with(req) { action = 0; } 36 void ?{}( WRequest & req, void (* action)( void ) ) with(req) { req.action = action; } 35 37 bool stop( WRequest & req ) { return req.action == 0; } 36 38 void doit( WRequest & req ) { req.action(); } 37 39 38 // Each worker has its own work buffer to reduce contention between client and server. Hence, work requests arrive and39 // a re distributed into buffers in a roughly round-robin order.40 // Each worker has its own set (when requests buffers > workers) of work buffers to reduce contention between client 41 // and server, where work requests arrive and are distributed into buffers in a roughly round-robin order. 40 42 41 43 thread Worker { 42 Buffer( WRequest ) * requests; 43 unsigned int start, range; 44 Buffer(WRequest) * requests; 45 WRequest * request; 46 unsigned int start, range; 44 47 }; // Worker 45 48 46 49 void main( Worker & w ) with(w) { 47 48 WRequest *request = remove( requests[i + start] );49 50 51 doit( *request );52 delete( request );53 50 for ( int i = 0;; i = (i + 1) % range ) { 51 request = remove( requests[i + start] ); 52 if ( ! request ) { yield(); continue; } 53 if ( stop( *request ) ) break; 54 doit( *request ); 55 delete( request ); 56 } // for 54 57 } // Worker::main 55 58 56 void ?{}( Worker & worker, cluster * wc, Buffer( WRequest) * requests, unsigned int start, unsigned int range ) {57 (*get_thread(worker)){ *wc }; // create on given cluster 58 worker.[requests, start, range] = [requests, start, range];59 void ?{}( Worker & worker, cluster * wc, Buffer(WRequest) * requests, unsigned int start, unsigned int range ) { 60 ((thread &)worker){ *wc }; 61 worker.[requests, request, start, range] = [requests, 0p, start, range]; 59 62 } // ?{} 60 63 64 WRequest * current_request( Worker & worker ) { return worker.request; } 65 61 66 struct Executor { 62 cluster * cluster; // if workers execute on separate cluster 63 processor ** processors; // array of virtual processors adding parallelism for workers 64 Buffer( WRequest ) * requests; // list of work requests 65 Worker ** workers; // array of workers executing work requests 66 unsigned int nprocessors, nworkers, nmailboxes; // number of mailboxes/workers/processor tasks 67 bool sepClus; // use same or separate cluster for executor 67 cluster * cluster; // if workers execute on separate cluster 68 processor ** processors; // array of virtual processors adding parallelism for workers 69 Buffer(WRequest) * requests; // list of work requests 70 Worker ** workers; // array of workers executing work requests 71 unsigned int nprocessors, nworkers, nrqueues; // number of processors/threads/request queues 72 bool sepClus; // use same or separate cluster for executor 73 unsigned int next; // demultiplexed across worker buffers 68 74 }; // Executor 69 75 70 static thread_local unsigned int next; // demultiplexed across worker buffers71 76 unsigned int tickets( Executor & ex ) with(ex) { 72 //return uFetchAdd( next, 1 ) % nmailboxes;73 return next++ % nmailboxes;// no locking, interference randomizes77 //return uFetchAdd( next, 1 ) % nrqueues; 78 return next++ % nrqueues; // no locking, interference randomizes 74 79 } // tickets 75 80 76 void ?{}( Executor & ex, unsigned int np, unsigned int nw, unsigned int n m, bool sc = false ) with(ex) {77 [nprocessors, nworkers, nmailboxes, sepClus] = [np, nw, nm, sc];78 assert( nmailboxes >= nworkers );79 80 processors = (processor **)anew( nprocessors );81 requests = anew( nmailboxes );82 workers = (Worker **)anew( nworkers );81 void ?{}( Executor & ex, unsigned int np, unsigned int nw, unsigned int nr, bool sc = false ) with(ex) { 82 [nprocessors, nworkers, nrqueues, sepClus] = [np, nw, nr, sc]; 83 assert( nrqueues >= nworkers ); 84 cluster = sepClus ? new( "Executor" ) : active_cluster(); 85 processors = aalloc( nprocessors ); 86 requests = anew( nrqueues ); 87 workers = aalloc( nworkers ); 83 88 84 85 processors[ i] = new( *cluster );86 89 for ( i; nprocessors ) { 90 processors[i] = new( *cluster ); 91 } // for 87 92 88 unsigned int reqPerWorker = nmailboxes / nworkers, extras = nmailboxes % nworkers; 89 for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker + ( i < extras ? 1 : 0 ) ) { 90 workers[ i ] = new( cluster, requests, step, reqPerWorker + ( i < extras ? 1 : 0 ) ); 91 } // for 93 unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers; 94 // for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) { 95 for ( i; nworkers : start; 0u ~ @ ~ range : range; ) { 96 range = reqPerWorker + ( i < extras ? 1 : 0 ); 97 workers[i] = new( cluster, requests, start, range ); 98 } // for 92 99 } // ?{} 93 100 94 101 void ?{}( Executor & ex, unsigned int nprocessors, unsigned int nworkers, bool sepClus = false ) { 95 102 ex{ nprocessors, nworkers, nworkers, sepClus }; 96 103 } 97 104 void ?{}( Executor & ex, unsigned int nprocessors, bool sepClus = false ) { 98 105 ex{ nprocessors, nprocessors, nprocessors, sepClus }; 99 106 } 100 void ?{}( Executor & ex ) { // special for current cluster101 107 void ?{}( Executor & ex ) { // special for current cluster, no processors added 108 ex{ 0, active_cluster()->nprocessors, false }; 102 109 } 103 110 void ^?{}( Executor & ex ) with(ex) { 104 // Add one sentinel per worker to stop them. Since in destructor, no new work should be queued. Cannot combine next105 // two loops and only have a single sentinel because workers arrive in arbitrary order, so worker1 may take the 106 //single sentinel while waiting for worker 0 to end.111 // Add one sentinel per worker to stop them. Since in destructor, no new external work should be queued. Cannot 112 // combine next two loops and only have a single sentinel because workers arrive in arbitrary order, so worker1 may 113 // take the single sentinel while waiting for worker 0 to end. 107 114 108 109 unsigned int reqPerWorker = nmailboxes / nworkers;110 111 insert( requests[step], &sentinel[i] );// force eventually termination112 113 114 delete( workers[ i] );115 116 117 delete( processors[ i] );118 115 WRequest sentinel[nworkers]; 116 unsigned int reqPerWorker = nrqueues / nworkers; 117 for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) { 118 insert( requests[step], &sentinel[i] ); // force eventually termination 119 } // for 120 for ( i; nworkers ) { 121 delete( workers[i] ); 122 } // for 123 for ( i; nprocessors ) { 124 delete( processors[i] ); 125 } // for 119 126 120 delete( workers ); 121 delete( requests ); 122 delete( processors ); 123 if ( sepClus ) { delete( cluster ); } 127 free( workers ); 128 // adelete( nrqueues, requests ); 129 for ( i; nrqueues ) ^?{}( requests[i] ); // FIX ME: problem with resolver 130 free( requests ); 131 free( processors ); 132 if ( sepClus ) { delete( cluster ); } 124 133 } // ^?{} 125 134 126 135 void send( Executor & ex, void (* action)( void ) ) { // asynchronous call, no return value 127 128 136 WRequest * node = new( action ); 137 insert( ex.requests[tickets( ex )], node ); 129 138 } // send 139 130 140 131 141 int counter = 0; 132 142 133 void work ie( void ) {134 135 //fprintf( stderr, "workie\n" );143 void work( void ) { 144 __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST ); 145 // fprintf( stderr, "workie\n" ); 136 146 } 137 147 138 int main() { 139 { 140 Executor exector; 141 for ( i; 3000 ) { 142 send( exector, workie ); 143 if ( i % 100 ) yield(); 144 } // for 145 } 146 printf( "%d\n", counter ); 148 int main( int argc, char * argv[] ) { 149 int times = 1_000_000; 150 if ( argc == 2 ) times = atoi( argv[1] ); 151 processor p[7]; 152 { 153 Executor exector; 154 for ( i; times ) { 155 send( exector, work ); 156 if ( i % 100 == 0 ) yield(); 157 } // for 158 } 159 printf( "%d\n", counter ); 147 160 } 148 161 149 162 // Local Variables: // 163 // tab-width: 4" // 150 164 // compile-command: "cfa executor.cfa" // 151 165 // End: // -
libcfa/src/fstream.cfa
rbdfc032 reef8dfb 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 29 06:56:46 201913 // Update Count : 3 5512 // Last Modified On : Fri Jun 19 16:24:54 2020 13 // Update Count : 384 14 14 // 15 15 … … 26 26 27 27 28 // *********************************** ofstream ***********************************28 // *********************************** ofstream *********************************** 29 29 30 30 … … 32 32 33 33 void ?{}( ofstream & os, void * file ) { 34 os.file = file; 35 os.sepDefault = true; 36 os.sepOnOff = false; 37 os.nlOnOff = true; 38 os.prt = false; 39 os.sawNL = false; 34 os.$file = file; 35 os.$sepDefault = true; 36 os.$sepOnOff = false; 37 os.$nlOnOff = true; 38 os.$prt = false; 39 os.$sawNL = false; 40 $sepSetCur( os, sepGet( os ) ); 40 41 sepSet( os, " " ); 41 sepSetCur( os, sepGet( os ) );42 42 sepSetTuple( os, ", " ); 43 43 } // ?{} 44 44 45 45 // private 46 bool sepPrt( ofstream & os ) { setNL( os, false ); return os.sepOnOff; }47 void sepReset( ofstream & os ) { os.sepOnOff = os.sepDefault; }48 void sepReset( ofstream & os, bool reset ) { os.sepDefault = reset; os.sepOnOff = os.sepDefault; }49 const char * sepGetCur( ofstream & os ) { return os.sepCur; }50 void sepSetCur( ofstream & os, const char * sepCur ) { os.sepCur = sepCur; }51 bool getNL( ofstream & os ) { return os.sawNL; }52 void setNL( ofstream & os, bool state ) { os.sawNL = state; }53 bool getANL( ofstream & os ) { return os.nlOnOff; }54 bool getPrt( ofstream & os ) { return os.prt; }55 void setPrt( ofstream & os, bool state ) { os.prt = state; }46 bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; } 47 void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; } 48 void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; } 49 const char * $sepGetCur( ofstream & os ) { return os.$sepCur; } 50 void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; } 51 bool $getNL( ofstream & os ) { return os.$sawNL; } 52 void $setNL( ofstream & os, bool state ) { os.$sawNL = state; } 53 bool $getANL( ofstream & os ) { return os.$nlOnOff; } 54 bool $getPrt( ofstream & os ) { return os.$prt; } 55 void $setPrt( ofstream & os, bool state ) { os.$prt = state; } 56 56 57 57 // public 58 void ?{}( ofstream & os ) { os. file = 0; }59 60 void ?{}( ofstream & os, const char * name, const char * mode) {58 void ?{}( ofstream & os ) { os.$file = 0p; } 59 60 void ?{}( ofstream & os, const char name[], const char mode[] ) { 61 61 open( os, name, mode ); 62 62 } // ?{} 63 63 64 void ?{}( ofstream & os, const char * name) {64 void ?{}( ofstream & os, const char name[] ) { 65 65 open( os, name, "w" ); 66 66 } // ?{} … … 70 70 } // ^?{} 71 71 72 void sepOn( ofstream & os ) { os. sepOnOff = !getNL( os ); }73 void sepOff( ofstream & os ) { os. sepOnOff = false; }72 void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); } 73 void sepOff( ofstream & os ) { os.$sepOnOff = false; } 74 74 75 75 bool sepDisable( ofstream & os ) { 76 bool temp = os. sepDefault;77 os. sepDefault = false;78 sepReset( os );76 bool temp = os.$sepDefault; 77 os.$sepDefault = false; 78 $sepReset( os ); 79 79 return temp; 80 80 } // sepDisable 81 81 82 82 bool sepEnable( ofstream & os ) { 83 bool temp = os. sepDefault;84 os. sepDefault = true;85 if ( os. sepOnOff ) sepReset( os );// start of line ?83 bool temp = os.$sepDefault; 84 os.$sepDefault = true; 85 if ( os.$sepOnOff ) $sepReset( os ); // start of line ? 86 86 return temp; 87 87 } // sepEnable 88 88 89 void nlOn( ofstream & os ) { os. nlOnOff = true; }90 void nlOff( ofstream & os ) { os. nlOnOff = false; }91 92 const char * sepGet( ofstream & os ) { return os. separator; }93 void sepSet( ofstream & os, const char * s) {89 void nlOn( ofstream & os ) { os.$nlOnOff = true; } 90 void nlOff( ofstream & os ) { os.$nlOnOff = false; } 91 92 const char * sepGet( ofstream & os ) { return os.$separator; } 93 void sepSet( ofstream & os, const char s[] ) { 94 94 assert( s ); 95 strncpy( os. separator, s, sepSize - 1 );96 os. separator[sepSize - 1] = '\0';95 strncpy( os.$separator, s, sepSize - 1 ); 96 os.$separator[sepSize - 1] = '\0'; 97 97 } // sepSet 98 98 99 const char * sepGetTuple( ofstream & os ) { return os. tupleSeparator; }100 void sepSetTuple( ofstream & os, const char * s) {99 const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; } 100 void sepSetTuple( ofstream & os, const char s[] ) { 101 101 assert( s ); 102 strncpy( os. tupleSeparator, s, sepSize - 1 );103 os. tupleSeparator[sepSize - 1] = '\0';102 strncpy( os.$tupleSeparator, s, sepSize - 1 ); 103 os.$tupleSeparator[sepSize - 1] = '\0'; 104 104 } // sepSet 105 105 106 106 void ends( ofstream & os ) { 107 if ( getANL( os ) ) nl( os );108 else setPrt( os, false ); // turn off107 if ( $getANL( os ) ) nl( os ); 108 else $setPrt( os, false ); // turn off 109 109 if ( &os == &exit ) exit( EXIT_FAILURE ); 110 110 if ( &os == &abort ) abort(); … … 112 112 113 113 int fail( ofstream & os ) { 114 return os. file == 0 || ferror( (FILE *)(os.file) );114 return os.$file == 0 || ferror( (FILE *)(os.$file) ); 115 115 } // fail 116 116 117 117 int flush( ofstream & os ) { 118 return fflush( (FILE *)(os. file) );118 return fflush( (FILE *)(os.$file) ); 119 119 } // flush 120 120 121 void open( ofstream & os, const char * name, const char * mode) {121 void open( ofstream & os, const char name[], const char mode[] ) { 122 122 FILE * file = fopen( name, mode ); 123 123 #ifdef __CFA_DEBUG__ 124 if ( file == 0 ) { 125 abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 124 if ( file == 0p ) { 125 throw (Open_Failure){ os }; 126 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 126 127 } // if 127 128 #endif // __CFA_DEBUG__ … … 129 130 } // open 130 131 131 void open( ofstream & os, const char * name) {132 void open( ofstream & os, const char name[] ) { 132 133 open( os, name, "w" ); 133 134 } // open 134 135 135 136 void close( ofstream & os ) { 136 if ( (FILE *)(os.file) == stdout || (FILE *)(os.file) == stderr ) return; 137 138 if ( fclose( (FILE *)(os.file) ) == EOF ) { 137 if ( (FILE *)(os.$file) == 0p ) return; 138 if ( (FILE *)(os.$file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return; 139 140 if ( fclose( (FILE *)(os.$file) ) == EOF ) { 139 141 abort | IO_MSG "close output" | nl | strerror( errno ); 140 142 } // if 143 os.$file = 0p; 141 144 } // close 142 145 143 ofstream & write( ofstream & os, const char * data, size_t size ) {146 ofstream & write( ofstream & os, const char data[], size_t size ) { 144 147 if ( fail( os ) ) { 145 148 abort | IO_MSG "attempt write I/O on failed stream"; 146 149 } // if 147 150 148 if ( fwrite( data, 1, size, (FILE *)(os. file) ) != size ) {151 if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) { 149 152 abort | IO_MSG "write" | nl | strerror( errno ); 150 153 } // if … … 155 158 va_list args; 156 159 va_start( args, format ); 157 int len = vfprintf( (FILE *)(os. file), format, args );160 int len = vfprintf( (FILE *)(os.$file), format, args ); 158 161 if ( len == EOF ) { 159 if ( ferror( (FILE *)(os. file) ) ) {162 if ( ferror( (FILE *)(os.$file) ) ) { 160 163 abort | IO_MSG "invalid write"; 161 164 } // if … … 163 166 va_end( args ); 164 167 165 setPrt( os, true );// called in output cascade166 sepReset( os );// reset separator168 $setPrt( os, true ); // called in output cascade 169 $sepReset( os ); // reset separator 167 170 return len; 168 171 } // fmt … … 179 182 180 183 181 // *********************************** ifstream ***********************************184 // *********************************** ifstream *********************************** 182 185 183 186 184 187 // private 185 188 void ?{}( ifstream & is, void * file ) { 186 is. file = file;187 is. nlOnOff = false;189 is.$file = file; 190 is.$nlOnOff = false; 188 191 } // ?{} 189 192 190 193 // public 191 void ?{}( ifstream & is ) { is.file = 0; }192 193 void ?{}( ifstream & is, const char * name, const char * mode) {194 void ?{}( ifstream & is ) { is.$file = 0p; } 195 196 void ?{}( ifstream & is, const char name[], const char mode[] ) { 194 197 open( is, name, mode ); 195 198 } // ?{} 196 199 197 void ?{}( ifstream & is, const char * name) {200 void ?{}( ifstream & is, const char name[] ) { 198 201 open( is, name, "r" ); 199 202 } // ?{} … … 203 206 } // ^?{} 204 207 205 void nlOn( ifstream & os ) { os. nlOnOff = true; }206 void nlOff( ifstream & os ) { os. nlOnOff = false; }207 bool getANL( ifstream & os ) { return os. nlOnOff; }208 void nlOn( ifstream & os ) { os.$nlOnOff = true; } 209 void nlOff( ifstream & os ) { os.$nlOnOff = false; } 210 bool getANL( ifstream & os ) { return os.$nlOnOff; } 208 211 209 212 int fail( ifstream & is ) { 210 return is. file == 0 || ferror( (FILE *)(is.file) );213 return is.$file == 0p || ferror( (FILE *)(is.$file) ); 211 214 } // fail 212 215 213 216 int eof( ifstream & is ) { 214 return feof( (FILE *)(is. file) );217 return feof( (FILE *)(is.$file) ); 215 218 } // eof 216 219 217 void open( ifstream & is, const char * name, const char * mode) {220 void open( ifstream & is, const char name[], const char mode[] ) { 218 221 FILE * file = fopen( name, mode ); 219 222 #ifdef __CFA_DEBUG__ 220 if ( file == 0 ) { 221 abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 223 if ( file == 0p ) { 224 throw (Open_Failure){ is }; 225 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 222 226 } // if 223 227 #endif // __CFA_DEBUG__ 224 is. file = file;228 is.$file = file; 225 229 } // open 226 230 227 void open( ifstream & is, const char * name) {231 void open( ifstream & is, const char name[] ) { 228 232 open( is, name, "r" ); 229 233 } // open 230 234 231 235 void close( ifstream & is ) { 232 if ( (FILE *)(is.file) == stdin ) return; 233 234 if ( fclose( (FILE *)(is.file) ) == EOF ) { 236 if ( (FILE *)(is.$file) == 0p ) return; 237 if ( (FILE *)(is.$file) == (FILE *)stdin ) return; 238 239 if ( fclose( (FILE *)(is.$file) ) == EOF ) { 235 240 abort | IO_MSG "close input" | nl | strerror( errno ); 236 241 } // if 242 is.$file = 0p; 237 243 } // close 238 244 … … 242 248 } // if 243 249 244 if ( fread( data, size, 1, (FILE *)(is. file) ) == 0 ) {250 if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) { 245 251 abort | IO_MSG "read" | nl | strerror( errno ); 246 252 } // if … … 253 259 } // if 254 260 255 if ( ungetc( c, (FILE *)(is. file) ) == EOF ) {261 if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) { 256 262 abort | IO_MSG "ungetc" | nl | strerror( errno ); 257 263 } // if … … 263 269 264 270 va_start( args, format ); 265 int len = vfscanf( (FILE *)(is. file), format, args );271 int len = vfscanf( (FILE *)(is.$file), format, args ); 266 272 if ( len == EOF ) { 267 if ( ferror( (FILE *)(is. file) ) ) {273 if ( ferror( (FILE *)(is.$file) ) ) { 268 274 abort | IO_MSG "invalid read"; 269 275 } // if … … 276 282 ifstream & sin = sinFile, & stdin = sinFile; 277 283 284 285 // *********************************** exceptions *********************************** 286 287 288 void ?{}( Open_Failure & this, ofstream & ostream ) { 289 VTABLE_INIT(this, Open_Failure); 290 this.ostream = &ostream; 291 this.tag = 1; 292 } 293 void ?{}( Open_Failure & this, ifstream & istream ) { 294 VTABLE_INIT(this, Open_Failure); 295 this.istream = &istream; 296 this.tag = 0; 297 } 298 const char * Open_Failure_msg(Open_Failure * this) { 299 return "Open_Failure"; 300 } 301 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg); 302 void throwOpen_Failure( ofstream & ostream ) { 303 Open_Failure exc = { ostream }; 304 } 305 void throwOpen_Failure( ifstream & istream ) { 306 Open_Failure exc = { istream }; 307 } 308 278 309 // Local Variables: // 279 310 // tab-width: 4 // -
libcfa/src/fstream.hfa
rbdfc032 reef8dfb 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 29 06:56:02 201913 // Update Count : 1 6812 // Last Modified On : Fri Jun 19 16:29:17 2020 13 // Update Count : 189 14 14 // 15 15 … … 17 17 18 18 #include "iostream.hfa" 19 #include <exception.hfa> 19 20 20 21 21 // *********************************** ofstream ***********************************22 // *********************************** ofstream *********************************** 22 23 23 24 24 25 enum { sepSize = 16 }; 25 26 struct ofstream { 26 void * file;27 bool sepDefault;28 bool sepOnOff;29 bool nlOnOff;30 bool prt; // print text31 bool sawNL;32 const char * sepCur;33 char separator[sepSize];34 char tupleSeparator[sepSize];27 void * $file; 28 bool $sepDefault; 29 bool $sepOnOff; 30 bool $nlOnOff; 31 bool $prt; // print text 32 bool $sawNL; 33 const char * $sepCur; 34 char $separator[sepSize]; 35 char $tupleSeparator[sepSize]; 35 36 }; // ofstream 36 37 37 38 // private 38 bool sepPrt( ofstream & );39 void sepReset( ofstream & );40 void sepReset( ofstream &, bool );41 const char * sepGetCur( ofstream & );42 void sepSetCur( ofstream &, const char *);43 bool getNL( ofstream & );44 void setNL( ofstream &, bool );45 bool getANL( ofstream & );46 bool getPrt( ofstream & );47 void setPrt( ofstream &, bool );39 bool $sepPrt( ofstream & ); 40 void $sepReset( ofstream & ); 41 void $sepReset( ofstream &, bool ); 42 const char * $sepGetCur( ofstream & ); 43 void $sepSetCur( ofstream &, const char [] ); 44 bool $getNL( ofstream & ); 45 void $setNL( ofstream &, bool ); 46 bool $getANL( ofstream & ); 47 bool $getPrt( ofstream & ); 48 void $setPrt( ofstream &, bool ); 48 49 49 50 // public … … 56 57 57 58 const char * sepGet( ofstream & ); 58 void sepSet( ofstream &, const char *);59 void sepSet( ofstream &, const char [] ); 59 60 const char * sepGetTuple( ofstream & ); 60 void sepSetTuple( ofstream &, const char *);61 void sepSetTuple( ofstream &, const char [] ); 61 62 62 63 void ends( ofstream & os ); 63 64 int fail( ofstream & ); 64 65 int flush( ofstream & ); 65 void open( ofstream &, const char * name, const char * mode);66 void open( ofstream &, const char * name);66 void open( ofstream &, const char name[], const char mode[] ); 67 void open( ofstream &, const char name[] ); 67 68 void close( ofstream & ); 68 ofstream & write( ofstream &, const char * data, size_t size );69 int fmt( ofstream &, const char format[], ... ) ;69 ofstream & write( ofstream &, const char data[], size_t size ); 70 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 70 71 71 72 void ?{}( ofstream & os ); 72 void ?{}( ofstream & os, const char * name, const char * mode);73 void ?{}( ofstream & os, const char * name);73 void ?{}( ofstream & os, const char name[], const char mode[] ); 74 void ?{}( ofstream & os, const char name[] ); 74 75 void ^?{}( ofstream & os ); 75 76 … … 78 79 79 80 80 // *********************************** ifstream ***********************************81 // *********************************** ifstream *********************************** 81 82 82 83 83 84 struct ifstream { 84 void * file;85 bool nlOnOff;85 void * $file; 86 bool $nlOnOff; 86 87 }; // ifstream 87 88 … … 92 93 int fail( ifstream & is ); 93 94 int eof( ifstream & is ); 94 void open( ifstream & is, const char * name, const char * mode);95 void open( ifstream & is, const char * name);95 void open( ifstream & is, const char name[], const char mode[] ); 96 void open( ifstream & is, const char name[] ); 96 97 void close( ifstream & is ); 97 98 ifstream & read( ifstream & is, char * data, size_t size ); 98 99 ifstream & ungetc( ifstream & is, char c ); 99 int fmt( ifstream &, const char format[], ... ) ;100 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 100 101 101 102 void ?{}( ifstream & is ); 102 void ?{}( ifstream & is, const char * name, const char * mode);103 void ?{}( ifstream & is, const char * name);103 void ?{}( ifstream & is, const char name[], const char mode[] ); 104 void ?{}( ifstream & is, const char name[] ); 104 105 void ^?{}( ifstream & is ); 105 106 106 107 extern ifstream & sin, & stdin; // aliases 108 109 110 // *********************************** exceptions *********************************** 111 112 113 DATA_EXCEPTION(Open_Failure)( 114 union { 115 ofstream * ostream; 116 ifstream * istream; 117 }; 118 // TEMPORARY: need polymorphic exceptions 119 int tag; // 1 => ostream; 0 => istream 120 ); 121 122 void ?{}( Open_Failure & this, ofstream & ostream ); 123 void ?{}( Open_Failure & this, ifstream & istream ); 107 124 108 125 // Local Variables: // -
libcfa/src/gmp.hfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Jul 13 15:25:05 201913 // Update Count : 2712 // Last Modified On : Sun Feb 9 09:56:54 2020 13 // Update Count : 31 14 14 // 15 15 … … 24 24 25 25 static inline { 26 // constructor 26 // constructor, zero_t/one_t are unnecessary because of relationship with signed/unsigned int 27 27 void ?{}( Int & this ) { mpz_init( this.mpz ); } 28 28 void ?{}( Int & this, Int init ) { mpz_init_set( this.mpz, init.mpz ); } 29 void ?{}( Int & this, zero_t ) { mpz_init_set_si( this.mpz, 0 ); }30 void ?{}( Int & this, one_t ) { mpz_init_set_si( this.mpz, 1 ); }31 29 void ?{}( Int & this, signed long int init ) { mpz_init_set_si( this.mpz, init ); } 32 30 void ?{}( Int & this, unsigned long int init ) { mpz_init_set_ui( this.mpz, init ); } 33 void ?{}( Int & this, const char * val) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); }31 void ?{}( Int & this, const char val[] ) { if ( mpz_init_set_str( this.mpz, val, 0 ) ) abort(); } 34 32 void ^?{}( Int & this ) { mpz_clear( this.mpz ); } 35 33 … … 37 35 Int ?`mp( signed long int init ) { return (Int){ init }; } 38 36 Int ?`mp( unsigned long int init ) { return (Int){ init }; } 39 Int ?`mp( const char * init) { return (Int){ init }; }37 Int ?`mp( const char init[] ) { return (Int){ init }; } 40 38 41 39 // assignment … … 43 41 Int ?=?( Int & lhs, long int rhs ) { mpz_set_si( lhs.mpz, rhs ); return lhs; } 44 42 Int ?=?( Int & lhs, unsigned long int rhs ) { mpz_set_ui( lhs.mpz, rhs ); return lhs; } 45 Int ?=?( Int & lhs, const char * rhs) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; }43 Int ?=?( Int & lhs, const char rhs[] ) { if ( mpz_set_str( lhs.mpz, rhs, 0 ) ) { abort | "invalid string conversion"; } return lhs; } 46 44 47 45 char ?=?( char & lhs, Int rhs ) { char val = mpz_get_si( rhs.mpz ); lhs = val; return lhs; } … … 265 263 forall( dtype ostype | ostream( ostype ) ) { 266 264 ostype & ?|?( ostype & os, Int mp ) { 267 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );265 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 268 266 gmp_printf( "%Zd", mp.mpz ); 269 267 sepOn( os ); -
libcfa/src/heap.cfa
rbdfc032 reef8dfb 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // heap.c --7 // heap.cfa -- 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Dec 8 21:01:31 201913 // Update Count : 64712 // Last Modified On : Wed Dec 16 12:28:25 2020 13 // Update Count : 1023 14 14 // 15 15 16 16 #include <unistd.h> // sbrk, sysconf 17 #include <stdlib.h> // EXIT_FAILURE 17 18 #include <stdbool.h> // true, false 18 19 #include <stdio.h> // snprintf, fileno 19 20 #include <errno.h> // errno 20 21 #include <string.h> // memset, memcpy 21 extern "C" { 22 #include <limits.h> // ULONG_MAX 23 #include <malloc.h> // memalign, malloc_usable_size 22 24 #include <sys/mman.h> // mmap, munmap 23 } // extern "C" 24 25 // #comment TD : Many of these should be merged into math I believe 26 #include "bits/align.hfa" // libPow2 25 26 #include "bits/align.hfa" // libAlign 27 27 #include "bits/defs.hfa" // likely, unlikely 28 28 #include "bits/locks.hfa" // __spinlock_t 29 29 #include "startup.hfa" // STARTUP_PRIORITY_MEMORY 30 //#include "stdlib.hfa" // bsearchl 31 #include "malloc.h" 32 33 #define MIN(x, y) (y > x ? x : y) 30 #include "math.hfa" // ceiling 31 #include "bitmanip.hfa" // is_pow2, ceiling2 34 32 35 33 static bool traceHeap = false; … … 74 72 // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address, 75 73 // the brk address is extended by the extension amount. 76 __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),74 __CFA_DEFAULT_HEAP_EXPANSION__ = (10 * 1024 * 1024), 77 75 78 76 // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets; … … 91 89 92 90 #ifdef __CFA_DEBUG__ 93 static unsigned int allocFree;// running total of allocations minus frees91 static size_t allocUnfreed; // running total of allocations minus frees 94 92 95 93 static void prtUnfreed() { 96 if ( alloc Free!= 0 ) {94 if ( allocUnfreed != 0 ) { 97 95 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 98 96 char helpText[512]; 99 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with % u(0x%x) bytes of storage allocated but not freed.\n"97 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n" 100 98 "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 101 (long int)getpid(), alloc Free, allocFree); // always print the UNIX pid99 (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid 102 100 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug 103 101 } // if … … 106 104 extern "C" { 107 105 void heapAppStart() { // called by __cfaabi_appready_startup 108 alloc Free= 0;106 allocUnfreed = 0; 109 107 } // heapAppStart 110 108 … … 118 116 119 117 // statically allocated variables => zero filled. 120 static size_t pageSize; // architecture pagesize 118 size_t __page_size; // architecture pagesize 119 int __map_prot; // common mmap/mprotect protection 121 120 static size_t heapExpand; // sbrk advance 122 121 static size_t mmapStart; // cross over point for mmap … … 127 126 #define LOCKFREE 1 128 127 #define BUCKETLOCK SPINLOCK 129 #if BUCKETLOCK == LOCKFREE 130 #include <uStackLF.h> 128 #if BUCKETLOCK == SPINLOCK 129 #elif BUCKETLOCK == LOCKFREE 130 #include <stackLockFree.hfa> 131 #else 132 #error undefined lock type for bucket lock 131 133 #endif // LOCKFREE 132 134 … … 136 138 137 139 struct HeapManager { 138 // struct FreeHeader; // forward declaration139 140 140 struct Storage { 141 141 struct Header { // header … … 145 145 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 146 146 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 147 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header147 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 148 148 #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 149 149 150 150 union { 151 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 151 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 152 // 2nd low-order bit => zero filled 152 153 void * home; // allocated block points back to home locations (must overlay alignment) 153 154 size_t blockSize; // size for munmap (must overlay alignment) 154 #if BUCK LOCK == SPINLOCK155 #if BUCKETLOCK == SPINLOCK 155 156 Storage * next; // freed block points next freed block of same size 156 157 #endif // SPINLOCK 157 158 }; 159 size_t size; // allocation size in bytes 158 160 159 161 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 160 uint 32_t padding; // unused, force home/blocksize to overlay alignment in fake header162 uint64_t padding; // unused, force home/blocksize to overlay alignment in fake header 161 163 #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4 162 164 }; 163 // future code 164 #if BUCKLOCK == LOCKFREE 165 Stack<Storage>::Link next; // freed block points next freed block of same size (double-wide) 165 #if BUCKETLOCK == LOCKFREE 166 Link(Storage) next; // freed block points next freed block of same size (double-wide) 166 167 #endif // LOCKFREE 167 168 }; 168 169 } real; // RealHeader 170 169 171 struct FakeHeader { 170 172 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 171 uint32_t alignment; // low-order bits of home/blockSize used for tricks173 uint32_t alignment; // 1st low-order bit => fake header & alignment 172 174 #endif // __ORDER_LITTLE_ENDIAN__ 173 175 … … 187 189 188 190 struct FreeHeader { 189 #if BUCK LOCK == SPINLOCK191 #if BUCKETLOCK == SPINLOCK 190 192 __spinlock_t lock; // must be first field for alignment 191 193 Storage * freeList; 192 #elif BUCKLOCK == LOCKFREE193 // future code194 StackLF<Storage> freeList;195 194 #else 196 #error undefined lock type for bucket lock197 #endif // SPINLOCK195 StackLF(Storage) freeList; 196 #endif // BUCKETLOCK 198 197 size_t blockSize; // size of allocations on this list 199 198 }; // FreeHeader … … 208 207 }; // HeapManager 209 208 209 #if BUCKETLOCK == LOCKFREE 210 static inline { 211 Link(HeapManager.Storage) * ?`next( HeapManager.Storage * this ) { return &this->header.kind.real.next; } 212 void ?{}( HeapManager.FreeHeader & ) {} 213 void ^?{}( HeapManager.FreeHeader & ) {} 214 } // distribution 215 #endif // LOCKFREE 216 210 217 static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; } 211 218 … … 214 221 #define __STATISTICS__ 215 222 216 // Bucket size must be multiple of 16. 217 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size. 223 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16. 224 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size. 225 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed. 218 226 static const unsigned int bucketSizes[] @= { // different bucket sizes 219 16 , 32, 48, 64 + sizeof(HeapManager.Storage), // 4220 96 , 112, 128 + sizeof(HeapManager.Storage), // 3227 16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4 228 96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3 221 229 160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4 222 230 320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4 … … 236 244 }; 237 245 238 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );246 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" ); 239 247 240 248 #ifdef FASTLOOKUP … … 243 251 #endif // FASTLOOKUP 244 252 245 static int mmapFd = -1;// fake or actual fd for anonymous file253 static const off_t mmapFd = -1; // fake or actual fd for anonymous file 246 254 #ifdef __CFA_DEBUG__ 247 255 static bool heapBoot = 0; // detect recursion during boot 248 256 #endif // __CFA_DEBUG__ 257 258 // The constructor for heapManager is called explicitly in memory_startup. 249 259 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 250 260 … … 252 262 #ifdef __STATISTICS__ 253 263 // Heap statistics counters. 264 static unsigned int malloc_calls; 265 static unsigned long long int malloc_storage; 266 static unsigned int aalloc_calls; 267 static unsigned long long int aalloc_storage; 268 static unsigned int calloc_calls; 269 static unsigned long long int calloc_storage; 270 static unsigned int memalign_calls; 271 static unsigned long long int memalign_storage; 272 static unsigned int amemalign_calls; 273 static unsigned long long int amemalign_storage; 274 static unsigned int cmemalign_calls; 275 static unsigned long long int cmemalign_storage; 276 static unsigned int resize_calls; 277 static unsigned long long int resize_storage; 278 static unsigned int realloc_calls; 279 static unsigned long long int realloc_storage; 280 static unsigned int free_calls; 281 static unsigned long long int free_storage; 282 static unsigned int mmap_calls; 254 283 static unsigned long long int mmap_storage; 255 static unsigned int m map_calls;284 static unsigned int munmap_calls; 256 285 static unsigned long long int munmap_storage; 257 static unsigned int munmap_calls;286 static unsigned int sbrk_calls; 258 287 static unsigned long long int sbrk_storage; 259 static unsigned int sbrk_calls;260 static unsigned long long int malloc_storage;261 static unsigned int malloc_calls;262 static unsigned long long int free_storage;263 static unsigned int free_calls;264 static unsigned long long int calloc_storage;265 static unsigned int calloc_calls;266 static unsigned long long int memalign_storage;267 static unsigned int memalign_calls;268 static unsigned long long int cmemalign_storage;269 static unsigned int cmemalign_calls;270 static unsigned long long int realloc_storage;271 static unsigned int realloc_calls;272 288 // Statistics file descriptor (changed by malloc_stats_fd). 273 static int stat fd = STDERR_FILENO; // default stderr289 static int stat_fd = STDERR_FILENO; // default stderr 274 290 275 291 // Use "write" because streams may be shutdown when calls are made. 276 292 static void printStats() { 277 char helpText[ 512];293 char helpText[1024]; 278 294 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 279 295 "\nHeap statistics:\n" 280 296 " malloc: calls %u / storage %llu\n" 297 " aalloc: calls %u / storage %llu\n" 281 298 " calloc: calls %u / storage %llu\n" 282 299 " memalign: calls %u / storage %llu\n" 300 " amemalign: calls %u / storage %llu\n" 283 301 " cmemalign: calls %u / storage %llu\n" 302 " resize: calls %u / storage %llu\n" 284 303 " realloc: calls %u / storage %llu\n" 285 304 " free: calls %u / storage %llu\n" … … 288 307 " sbrk: calls %u / storage %llu\n", 289 308 malloc_calls, malloc_storage, 309 aalloc_calls, aalloc_storage, 290 310 calloc_calls, calloc_storage, 291 311 memalign_calls, memalign_storage, 312 amemalign_calls, amemalign_storage, 292 313 cmemalign_calls, cmemalign_storage, 314 resize_calls, resize_storage, 293 315 realloc_calls, realloc_storage, 294 316 free_calls, free_storage, … … 300 322 301 323 static int printStatsXML( FILE * stream ) { // see malloc_info 302 char helpText[ 512];324 char helpText[1024]; 303 325 int len = snprintf( helpText, sizeof(helpText), 304 326 "<malloc version=\"1\">\n" … … 307 329 "</sizes>\n" 308 330 "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n" 331 "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n" 309 332 "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n" 310 333 "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n" 334 "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n" 311 335 "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n" 336 "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n" 312 337 "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n" 313 338 "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n" … … 317 342 "</malloc>", 318 343 malloc_calls, malloc_storage, 344 aalloc_calls, aalloc_storage, 319 345 calloc_calls, calloc_storage, 320 346 memalign_calls, memalign_storage, 347 amemalign_calls, amemalign_storage, 321 348 cmemalign_calls, cmemalign_storage, 349 resize_calls, resize_storage, 322 350 realloc_calls, realloc_storage, 323 351 free_calls, free_storage, … … 332 360 333 361 334 // static inline void noMemory() {335 // abort( "Heap memory exhausted at %zu bytes.\n"336 // "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",337 // ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );338 // } // noMemory339 340 341 static inline void checkAlign( size_t alignment ) {342 if ( alignment < libAlign() || ! libPow2( alignment ) ) {343 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );344 } // if345 } // checkAlign346 347 348 static inline bool setHeapExpand( size_t value ) {349 if ( heapExpand < pageSize ) return true;350 heapExpand = value;351 return false;352 } // setHeapExpand353 354 355 362 // thunk problem 356 363 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 369 376 370 377 static inline bool setMmapStart( size_t value ) { // true => mmapped, false => sbrk 371 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;378 if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false; 372 379 mmapStart = value; // set global 373 380 … … 376 383 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 377 384 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 378 return false;385 return true; 379 386 } // setMmapStart 380 387 381 388 382 static inline void checkHeader( bool check, const char * name, void * addr ) { 389 // <-------+----------------------------------------------------> bsize (bucket size) 390 // |header |addr 391 //================================================================================== 392 // align/offset | 393 // <-----------------<------------+-----------------------------> bsize (bucket size) 394 // |fake-header | addr 395 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) )) 396 #define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset)) 397 398 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size) 399 // |header |addr 400 //================================================================================== 401 // align/offset | 402 // <------------------------------<<---------- dsize --------->>> bsize (bucket size) 403 // |fake-header |addr 404 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header )) 405 406 407 static inline void checkAlign( size_t alignment ) { 408 if ( alignment < libAlign() || ! is_pow2( alignment ) ) { 409 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() ); 410 } // if 411 } // checkAlign 412 413 414 static inline void checkHeader( bool check, const char name[], void * addr ) { 383 415 if ( unlikely( check ) ) { // bad address ? 384 416 abort( "Attempt to %s storage %p with address outside the heap.\n" … … 391 423 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) { 392 424 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ? 393 size_t offset = header->kind.fake.offset;394 425 alignment = header->kind.fake.alignment & -2; // remove flag from value 395 426 #ifdef __CFA_DEBUG__ 396 427 checkAlign( alignment ); // check alignment 397 428 #endif // __CFA_DEBUG__ 398 header = (HeapManager.Storage.Header *)((char *)header - offset); 429 header = realHeader( header ); // backup from fake to real header 430 } else { 431 alignment = libAlign(); // => no fake header 399 432 } // if 400 433 } // fakeHeader 401 434 402 435 403 // <-------+----------------------------------------------------> bsize (bucket size) 404 // |header |addr 405 //================================================================================== 406 // | alignment 407 // <-----------------<------------+-----------------------------> bsize (bucket size) 408 // |fake-header | addr 409 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) )) 410 411 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size) 412 // |header |addr 413 //================================================================================== 414 // | alignment 415 // <------------------------------<<---------- dsize --------->>> bsize (bucket size) 416 // |fake-header |addr 417 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header )) 418 419 420 static inline bool headers( const char * name __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) { 436 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, 437 size_t & size, size_t & alignment ) with( heapManager ) { 421 438 header = headerAddr( addr ); 422 439 423 if ( unlikely( heapEnd < addr ) ) {// mmapped ?440 if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ? 424 441 fakeHeader( header, alignment ); 425 442 size = header->kind.real.blockSize & -3; // mmap size … … 428 445 429 446 #ifdef __CFA_DEBUG__ 430 checkHeader( addr < heapBegin ||header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?447 checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ? 431 448 #endif // __CFA_DEBUG__ 432 449 … … 449 466 } // headers 450 467 451 452 static inline void * extend( size_t size ) with ( heapManager ) { 468 #ifdef __CFA_DEBUG__ 469 #if __SIZEOF_POINTER__ == 4 470 #define MASK 0xdeadbeef 471 #else 472 #define MASK 0xdeadbeefdeadbeef 473 #endif 474 #define STRIDE size_t 475 476 static void * Memset( void * addr, STRIDE size ) { // debug only 477 if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) ); 478 if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) ); 479 480 STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE); 481 for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK; 482 return addr; 483 } // Memset 484 #endif // __CFA_DEBUG__ 485 486 487 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes." 488 489 static inline void * extend( size_t size ) with( heapManager ) { 453 490 lock( extlock __cfaabi_dbg_ctx2 ); 454 491 ptrdiff_t rem = heapRemaining - size; … … 456 493 // If the size requested is bigger than the current remaining storage, increase the size of the heap. 457 494 458 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() ); 459 if ( sbrk( increase ) == (void *)-1 ) { 495 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size ); 496 // Do not call abort or strerror( errno ) as they may call malloc. 497 if ( sbrk( increase ) == (void *)-1 ) { // failed, no memory ? 460 498 unlock( extlock ); 461 errno = ENOMEM; 462 return 0p; 499 __cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size ); 500 _exit( EXIT_FAILURE ); 501 } // if 502 if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) { 503 unlock( extlock ); 504 __cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno ); 505 _exit( EXIT_FAILURE ); 463 506 } // if 464 507 #ifdef __STATISTICS__ … … 468 511 #ifdef __CFA_DEBUG__ 469 512 // Set new memory to garbage so subsequent uninitialized usages might fail. 470 memset( (char *)heapEnd + heapRemaining, '\377', increase ); 513 memset( (char *)heapEnd + heapRemaining, '\xde', increase ); 514 //Memset( (char *)heapEnd + heapRemaining, increase ); 471 515 #endif // __CFA_DEBUG__ 472 516 rem = heapRemaining + increase - size; … … 481 525 482 526 483 static inline void * doMalloc( size_t size ) with 527 static inline void * doMalloc( size_t size ) with( heapManager ) { 484 528 HeapManager.Storage * block; // pointer to new block of storage 485 529 … … 487 531 // along with the block and is a multiple of the alignment size. 488 532 489 if ( unlikely( size > ~0ul- sizeof(HeapManager.Storage) ) ) return 0p;533 if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p; 490 534 size_t tsize = size + sizeof(HeapManager.Storage); 491 535 if ( likely( tsize < mmapStart ) ) { // small size => sbrk … … 497 541 posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed ); 498 542 HeapManager.FreeHeader * freeElem = &freeLists[posn]; 499 // #ifdef FASTLOOKUP 500 // if ( tsize < LookupSizes ) 501 // freeElem = &freeLists[lookup[tsize]]; 502 // else 503 // #endif // FASTLOOKUP 504 // freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search 505 // HeapManager.FreeHeader * freeElem = 506 // #ifdef FASTLOOKUP 507 // tsize < LookupSizes ? &freeLists[lookup[tsize]] : 508 // #endif // FASTLOOKUP 509 // bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search 510 assert( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ? 511 assert( tsize <= freeElem->blockSize ); // search failure ? 543 verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ? 544 verify( tsize <= freeElem->blockSize ); // search failure ? 512 545 tsize = freeElem->blockSize; // total space needed for request 513 546 514 547 // Spin until the lock is acquired for this particular size of block. 515 548 516 #if defined( SPINLOCK )549 #if BUCKETLOCK == SPINLOCK 517 550 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 518 551 block = freeElem->freeList; // remove node from stack 519 552 #else 520 block = freeElem->freeList.pop();521 #endif // SPINLOCK553 block = pop( freeElem->freeList ); 554 #endif // BUCKETLOCK 522 555 if ( unlikely( block == 0p ) ) { // no free block ? 523 #if defined( SPINLOCK )556 #if BUCKETLOCK == SPINLOCK 524 557 unlock( freeElem->lock ); 525 #endif // SPINLOCK558 #endif // BUCKETLOCK 526 559 527 560 // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more … … 529 562 530 563 block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call 531 if ( unlikely( block == 0p ) ) return 0p; 532 #if defined( SPINLOCK ) 564 #if BUCKETLOCK == SPINLOCK 533 565 } else { 534 566 freeElem->freeList = block->header.kind.real.next; 535 567 unlock( freeElem->lock ); 536 #endif // SPINLOCK568 #endif // BUCKETLOCK 537 569 } // if 538 570 539 571 block->header.kind.real.home = freeElem; // pointer back to free list of apropriate size 540 572 } else { // large size => mmap 541 if ( unlikely( size > ~0ul - pageSize ) ) return 0p;542 tsize = libCeiling( tsize, pageSize ); // must be multiple of page size573 if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p; 574 tsize = ceiling2( tsize, __page_size ); // must be multiple of page size 543 575 #ifdef __STATISTICS__ 544 576 __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST ); 545 577 __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST ); 546 578 #endif // __STATISTICS__ 547 block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 ); 548 if ( block == (HeapManager.Storage *)MAP_FAILED ) { 579 580 block = (HeapManager.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 ); 581 if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ? 582 if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory 549 583 // Do not call strerror( errno ) as it may call malloc. 550 abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu err or:%d.", &heapManager, tsize, errno );551 } // 584 abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno ); 585 } //if 552 586 #ifdef __CFA_DEBUG__ 553 587 // Set new memory to garbage so subsequent uninitialized usages might fail. 554 memset( block, '\377', tsize ); 588 memset( block, '\xde', tsize ); 589 //Memset( block, tsize ); 555 590 #endif // __CFA_DEBUG__ 556 591 block->header.kind.real.blockSize = tsize; // storage size for munmap 557 592 } // if 558 593 594 block->header.kind.real.size = size; // store allocation size 559 595 void * addr = &(block->data); // adjust off header to user bytes 596 verify( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ? 560 597 561 598 #ifdef __CFA_DEBUG__ 562 assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ? 563 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST ); 599 __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST ); 564 600 if ( traceHeap() ) { 565 601 enum { BufferSize = 64 }; 566 602 char helpText[BufferSize]; 567 603 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize ); 568 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );569 604 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug 570 605 } // if … … 575 610 576 611 577 static inline void doFree( void * addr ) with 612 static inline void doFree( void * addr ) with( heapManager ) { 578 613 #ifdef __CFA_DEBUG__ 579 614 if ( unlikely( heapManager.heapBegin == 0p ) ) { … … 592 627 #endif // __STATISTICS__ 593 628 if ( munmap( header, size ) == -1 ) { 594 #ifdef __CFA_DEBUG__595 629 abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n" 596 630 "Possible cause is invalid pointer.", 597 631 addr ); 598 #endif // __CFA_DEBUG__599 632 } // if 600 633 } else { 601 634 #ifdef __CFA_DEBUG__ 602 635 // Set free memory to garbage so subsequent usages might fail. 603 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) ); 636 memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) ); 637 //Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) ); 604 638 #endif // __CFA_DEBUG__ 605 639 … … 607 641 free_storage += size; 608 642 #endif // __STATISTICS__ 609 #if defined( SPINLOCK )643 #if BUCKETLOCK == SPINLOCK 610 644 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 611 645 header->kind.real.next = freeElem->freeList; // push on stack … … 613 647 unlock( freeElem->lock ); // release spin lock 614 648 #else 615 freeElem->freeList.push(*(HeapManager.Storage *)header );616 #endif // SPINLOCK649 push( freeElem->freeList, *(HeapManager.Storage *)header ); 650 #endif // BUCKETLOCK 617 651 } // if 618 652 619 653 #ifdef __CFA_DEBUG__ 620 __atomic_add_fetch( &alloc Free, -size, __ATOMIC_SEQ_CST );654 __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST ); 621 655 if ( traceHeap() ) { 622 enum { BufferSize = 64 }; 623 char helpText[BufferSize]; 656 char helpText[64]; 624 657 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 625 658 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug … … 629 662 630 663 631 size_t prtFree( HeapManager & manager ) with 664 size_t prtFree( HeapManager & manager ) with( manager ) { 632 665 size_t total = 0; 633 666 #ifdef __STATISTICS__ … … 641 674 #endif // __STATISTICS__ 642 675 643 #if defined( SPINLOCK )676 #if BUCKETLOCK == SPINLOCK 644 677 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 645 678 #else 646 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) { 647 #endif // SPINLOCK 679 for(;;) { 680 // for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) { 681 // for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) { 682 // HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works` 683 // typeof(p) temp = (( p )`next)->top; // FIX ME: direct assignent fails, initialization works` 684 // p = temp; 685 #endif // BUCKETLOCK 648 686 total += size; 649 687 #ifdef __STATISTICS__ … … 665 703 666 704 667 static void ?{}( HeapManager & manager ) with ( manager ) { 668 pageSize = sysconf( _SC_PAGESIZE ); 705 static void ?{}( HeapManager & manager ) with( manager ) { 706 __page_size = sysconf( _SC_PAGESIZE ); 707 __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC; 669 708 670 709 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists … … 680 719 #endif // FASTLOOKUP 681 720 682 if ( setMmapStart( default_mmap_start() ) ) {721 if ( ! setMmapStart( default_mmap_start() ) ) { 683 722 abort( "HeapManager : internal error, mmap start initialization failure." ); 684 723 } // if … … 686 725 687 726 char * end = (char *)sbrk( 0 ); 688 sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment 689 heapBegin = heapEnd = sbrk( 0 ); // get new start point 727 heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment 690 728 } // HeapManager 691 729 … … 695 733 if ( traceHeapTerm() ) { 696 734 printStats(); 697 // if ( prtfree() ) prtFree( heapManager, true );735 // prtUnfreed() called in heapAppStop() 698 736 } // if 699 737 #endif // __STATISTICS__ … … 704 742 void memory_startup( void ) { 705 743 #ifdef __CFA_DEBUG__ 706 if ( unlikely( heapBoot ) ) { // check for recursion during system boot 707 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 744 if ( heapBoot ) { // check for recursion during system boot 708 745 abort( "boot() : internal error, recursively invoked during system boot." ); 709 746 } // if … … 711 748 #endif // __CFA_DEBUG__ 712 749 713 // assert( heapManager.heapBegin != 0 );750 //verify( heapManager.heapBegin != 0 ); 714 751 //heapManager{}; 715 if ( heapManager.heapBegin == 0p ) heapManager{}; 752 if ( heapManager.heapBegin == 0p ) heapManager{}; // sanity check 716 753 } // memory_startup 717 754 … … 723 760 724 761 static inline void * mallocNoStats( size_t size ) { // necessary for malloc statistics 725 //assert( heapManager.heapBegin != 0 ); 726 if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ? 727 void * addr = doMalloc( size ); 728 if ( unlikely( addr == 0p ) ) errno = ENOMEM; // POSIX 729 return addr; 762 verify( heapManager.heapBegin != 0p ); // called before memory_startup ? 763 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 764 765 #if __SIZEOF_POINTER__ == 8 766 verify( size < ((typeof(size_t))1 << 48) ); 767 #endif // __SIZEOF_POINTER__ == 8 768 return doMalloc( size ); 730 769 } // mallocNoStats 731 770 732 771 733 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) { 734 size_t size = noOfElems * elemSize; 772 static inline void * callocNoStats( size_t dim, size_t elemSize ) { 773 size_t size = dim * elemSize; 774 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 735 775 char * addr = (char *)mallocNoStats( size ); 736 if ( unlikely( addr == 0p ) ) return 0p;737 776 738 777 HeapManager.Storage.Header * header; 739 778 HeapManager.FreeHeader * freeElem; 740 779 size_t bsize, alignment; 741 bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );742 780 #ifndef __CFA_DEBUG__ 781 bool mapped = 782 #endif // __CFA_DEBUG__ 783 headers( "calloc", addr, header, freeElem, bsize, alignment ); 784 #ifndef __CFA_DEBUG__ 785 743 786 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 744 787 if ( ! mapped ) 745 788 #endif // __CFA_DEBUG__ 746 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works. 747 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size) 789 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined 748 790 // `-header`-addr `-size 749 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) );// set to zeros791 memset( addr, '\0', size ); // set to zeros 750 792 751 793 header->kind.real.blockSize |= 2; // mark as zero filled … … 754 796 755 797 756 static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics 798 static inline void * memalignNoStats( size_t alignment, size_t size ) { 799 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 800 757 801 #ifdef __CFA_DEBUG__ 758 802 checkAlign( alignment ); // check alignment … … 772 816 // add sizeof(Storage) for fake header 773 817 char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 774 if ( unlikely( addr == 0p ) ) return addr;775 818 776 819 // address in the block of the "next" alignment address 777 char * user = (char *) libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );820 char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment ); 778 821 779 822 // address of header from malloc 780 823 HeapManager.Storage.Header * realHeader = headerAddr( addr ); 824 realHeader->kind.real.size = size; // correct size to eliminate above alignment offset 781 825 // address of fake header * before* the alignment location 782 826 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); … … 790 834 791 835 792 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) { 793 size_t size = noOfElems * elemSize; 836 static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) { 837 size_t size = dim * elemSize; 838 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 794 839 char * addr = (char *)memalignNoStats( alignment, size ); 795 if ( unlikely( addr == 0p ) ) return 0p; 840 796 841 HeapManager.Storage.Header * header; 797 842 HeapManager.FreeHeader * freeElem; 798 843 size_t bsize; 799 bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );800 844 #ifndef __CFA_DEBUG__ 845 bool mapped = 846 #endif // __CFA_DEBUG__ 847 headers( "cmemalign", addr, header, freeElem, bsize, alignment ); 848 801 849 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 850 #ifndef __CFA_DEBUG__ 802 851 if ( ! mapped ) 803 852 #endif // __CFA_DEBUG__ 804 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros 805 header->kind.real.blockSize |= 2; // mark as zero filled 806 853 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined 854 // `-header`-addr `-size 855 memset( addr, '\0', size ); // set to zeros 856 857 header->kind.real.blockSize |= 2; // mark as zero filled 807 858 return addr; 808 859 } // cmemalignNoStats 809 860 810 861 811 // supported mallopt options812 #ifndef M_MMAP_THRESHOLD813 #define M_MMAP_THRESHOLD (-1)814 #endif // M_TOP_PAD815 #ifndef M_TOP_PAD816 #define M_TOP_PAD (-2)817 #endif // M_TOP_PAD818 819 820 862 extern "C" { 821 // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not 822 // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be 823 // successfully passed to free(). 863 // Allocates size bytes and returns a pointer to the allocated memory. The contents are undefined. If size is 0, 864 // then malloc() returns a unique pointer value that can later be successfully passed to free(). 824 865 void * malloc( size_t size ) { 825 866 #ifdef __STATISTICS__ … … 831 872 } // malloc 832 873 833 // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to 834 // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a 835 // unique pointer value that can later be successfully passed to free(). 836 void * calloc( size_t noOfElems, size_t elemSize ) { 874 875 // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes. 876 void * aalloc( size_t dim, size_t elemSize ) { 877 size_t size = dim * elemSize; 878 #ifdef __STATISTICS__ 879 __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST ); 880 __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST ); 881 #endif // __STATISTICS__ 882 883 return mallocNoStats( size ); 884 } // aalloc 885 886 887 // Same as aalloc() with memory set to zero. 888 void * calloc( size_t dim, size_t elemSize ) { 837 889 #ifdef __STATISTICS__ 838 890 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST ); 839 __atomic_add_fetch( &calloc_storage, noOfElems* elemSize, __ATOMIC_SEQ_CST );840 #endif // __STATISTICS__ 841 842 return callocNoStats( noOfElems, elemSize );891 __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST ); 892 #endif // __STATISTICS__ 893 894 return callocNoStats( dim, elemSize ); 843 895 } // calloc 844 896 845 // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be 846 // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size 847 // is larger than the old size, the added memory will not be initialized. If ptr is 0p, then the call is 848 // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call 849 // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(), 850 // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done. 851 void * realloc( void * oaddr, size_t size ) { 852 #ifdef __STATISTICS__ 853 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 897 898 // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined. If oaddr is 899 // 0p, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and oaddr is 900 // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier 901 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 902 void * resize( void * oaddr, size_t size ) { 903 #ifdef __STATISTICS__ 904 __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST ); 854 905 #endif // __STATISTICS__ 855 906 856 907 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 857 if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases 858 if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size ); 908 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases 909 if ( unlikely( oaddr == 0p ) ) { 910 #ifdef __STATISTICS__ 911 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST ); 912 #endif // __STATISTICS__ 913 return mallocNoStats( size ); 914 } // if 859 915 860 916 HeapManager.Storage.Header * header; 861 917 HeapManager.FreeHeader * freeElem; 862 size_t bsize, oalign = 0; 918 size_t bsize, oalign; 919 headers( "resize", oaddr, header, freeElem, bsize, oalign ); 920 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket 921 922 // same size, DO NOT preserve STICKY PROPERTIES. 923 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size 924 header->kind.real.blockSize &= -2; // no alignment and turn off 0 fill 925 header->kind.real.size = size; // reset allocation size 926 return oaddr; 927 } // if 928 929 #ifdef __STATISTICS__ 930 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST ); 931 #endif // __STATISTICS__ 932 933 // change size, DO NOT preserve STICKY PROPERTIES. 934 free( oaddr ); 935 return mallocNoStats( size ); // create new area 936 } // resize 937 938 939 // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of 940 // the old and new sizes. 941 void * realloc( void * oaddr, size_t size ) { 942 #ifdef __STATISTICS__ 943 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 944 #endif // __STATISTICS__ 945 946 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 947 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases 948 if ( unlikely( oaddr == 0p ) ) { 949 #ifdef __STATISTICS__ 950 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 951 #endif // __STATISTICS__ 952 return mallocNoStats( size ); 953 } // if 954 955 HeapManager.Storage.Header * header; 956 HeapManager.FreeHeader * freeElem; 957 size_t bsize, oalign; 863 958 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 864 959 865 960 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket 866 if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size 867 // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know 868 // where to start filling, i.e., do not overwrite existing values in space. 869 // 870 // This case does not result in a new profiler entry because the previous one still exists and it must match with 871 // the free for this memory. Hence, this realloc does not appear in the profiler output. 961 size_t osize = header->kind.real.size; // old allocation size 962 bool ozfill = (header->kind.real.blockSize & 2); // old allocation zero filled 963 if ( unlikely( size <= odsize ) && odsize <= size * 2 ) { // allow up to 50% wasted storage 964 header->kind.real.size = size; // reset allocation size 965 if ( unlikely( ozfill ) && size > osize ) { // previous request zero fill and larger ? 966 memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage 967 } // if 872 968 return oaddr; 873 969 } // if 874 970 875 971 #ifdef __STATISTICS__ 876 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );972 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 877 973 #endif // __STATISTICS__ 878 974 … … 880 976 881 977 void * naddr; 882 if ( unlikely( oalign != 0 ) ) { // previous request memalign? 883 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill 884 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area 885 } else { 886 naddr = memalignNoStats( oalign, size ); // create new aligned area 978 if ( likely( oalign == libAlign() ) ) { // previous request not aligned ? 979 naddr = mallocNoStats( size ); // create new area 980 } else { 981 naddr = memalignNoStats( oalign, size ); // create new aligned area 982 } // if 983 984 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 985 memcpy( naddr, oaddr, min( osize, size ) ); // copy bytes 986 free( oaddr ); 987 988 if ( unlikely( ozfill ) ) { // previous request zero fill ? 989 header->kind.real.blockSize |= 2; // mark new request as zero filled 990 if ( size > osize ) { // previous request larger ? 991 memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage 887 992 } // if 888 } else { 889 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill 890 naddr = callocNoStats( 1, size ); // create new area 891 } else { 892 naddr = mallocNoStats( size ); // create new area 893 } // if 894 } // if 895 if ( unlikely( naddr == 0p ) ) return 0p; 896 897 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 898 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket 899 // To preserve prior fill, the entire bucket must be copied versus the size. 900 memcpy( naddr, oaddr, MIN( odsize, ndsize ) ); // copy bytes 901 free( oaddr ); 993 } // if 902 994 return naddr; 903 995 } // realloc 904 996 905 // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory 906 // address will be a multiple of alignment, which must be a power of two.997 998 // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete) 907 999 void * memalign( size_t alignment, size_t size ) { 908 1000 #ifdef __STATISTICS__ … … 915 1007 916 1008 917 // The cmemalign() function is the same as calloc() with memory alignment. 918 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) { 1009 // Same as aalloc() with memory alignment. 1010 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) { 1011 size_t size = dim * elemSize; 919 1012 #ifdef __STATISTICS__ 920 1013 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 921 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST ); 922 #endif // __STATISTICS__ 923 924 return cmemalignNoStats( alignment, noOfElems, elemSize ); 1014 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST ); 1015 #endif // __STATISTICS__ 1016 1017 return memalignNoStats( alignment, size ); 1018 } // amemalign 1019 1020 1021 // Same as calloc() with memory alignment. 1022 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) { 1023 #ifdef __STATISTICS__ 1024 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 1025 __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST ); 1026 #endif // __STATISTICS__ 1027 1028 return cmemalignNoStats( alignment, dim, elemSize ); 925 1029 } // cmemalign 926 1030 927 // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a 928 // multiple of alignment. 1031 1032 // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple 1033 // of alignment. This requirement is universally ignored. 929 1034 void * aligned_alloc( size_t alignment, size_t size ) { 930 1035 return memalign( alignment, size ); … … 932 1037 933 1038 934 // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The935 // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of936 // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later937 // be successfully passed tofree(3).1039 // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated 1040 // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size 1041 // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to 1042 // free(3). 938 1043 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 939 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment1044 if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment 940 1045 * memptr = memalign( alignment, size ); 941 if ( unlikely( * memptr == 0p ) ) return ENOMEM;942 1046 return 0; 943 1047 } // posix_memalign 944 1048 945 // The obsolete function valloc() allocates size bytes and returns a pointer to the allocated memory. The memory 946 // address will be a multiple of the page size. It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 1049 1050 // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the 1051 // page size. It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 947 1052 void * valloc( size_t size ) { 948 return memalign( pageSize, size );1053 return memalign( __page_size, size ); 949 1054 } // valloc 950 1055 951 1056 952 // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to 953 // malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior 954 // occurs. If ptr is 0p, no operation is performed. 1057 // Same as valloc but rounds size to multiple of page size. 1058 void * pvalloc( size_t size ) { 1059 return memalign( __page_size, ceiling2( size, __page_size ) ); 1060 } // pvalloc 1061 1062 1063 // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() 1064 // or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is 1065 // 0p, no operation is performed. 955 1066 void free( void * addr ) { 956 1067 #ifdef __STATISTICS__ … … 973 1084 974 1085 975 // The malloc_alignment() function returns the alignment of theallocation.1086 // Returns the alignment of an allocation. 976 1087 size_t malloc_alignment( void * addr ) { 977 1088 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment … … 980 1091 return header->kind.fake.alignment & -2; // remove flag from value 981 1092 } else { 982 return libAlign 1093 return libAlign(); // minimum alignment 983 1094 } // if 984 1095 } // malloc_alignment 985 1096 986 1097 987 // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc(). 1098 // Set the alignment for an the allocation and return previous alignment or 0 if no alignment. 1099 size_t $malloc_alignment_set( void * addr, size_t alignment ) { 1100 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment 1101 size_t ret; 1102 HeapManager.Storage.Header * header = headerAddr( addr ); 1103 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? 1104 ret = header->kind.fake.alignment & -2; // remove flag from old value 1105 header->kind.fake.alignment = alignment | 1; // add flag to new value 1106 } else { 1107 ret = 0; // => no alignment to change 1108 } // if 1109 return ret; 1110 } // $malloc_alignment_set 1111 1112 1113 // Returns true if the allocation is zero filled, e.g., allocated by calloc(). 988 1114 bool malloc_zero_fill( void * addr ) { 989 1115 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 990 1116 HeapManager.Storage.Header * header = headerAddr( addr ); 991 1117 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? 992 header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);993 } // if 994 return (header->kind.real.blockSize & 2) != 0; // zero filled (calloc/cmemalign)?1118 header = realHeader( header ); // backup from fake to real header 1119 } // if 1120 return (header->kind.real.blockSize & 2) != 0; // zero filled ? 995 1121 } // malloc_zero_fill 996 1122 997 998 // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to 999 // a block of memory allocated by malloc(3) or a related function. 1123 // Set allocation is zero filled and return previous zero filled. 1124 bool $malloc_zero_fill_set( void * addr ) { 1125 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 1126 HeapManager.Storage.Header * header = headerAddr( addr ); 1127 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? 1128 header = realHeader( header ); // backup from fake to real header 1129 } // if 1130 bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ? 1131 header->kind.real.blockSize |= 2; // mark as zero filled 1132 return ret; 1133 } // $malloc_zero_fill_set 1134 1135 1136 // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T). 1137 size_t malloc_size( void * addr ) { 1138 if ( unlikely( addr == 0p ) ) return 0; // null allocation has zero size 1139 HeapManager.Storage.Header * header = headerAddr( addr ); 1140 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? 1141 header = realHeader( header ); // backup from fake to real header 1142 } // if 1143 return header->kind.real.size; 1144 } // malloc_size 1145 1146 // Set allocation size and return previous size. 1147 size_t $malloc_size_set( void * addr, size_t size ) { 1148 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1149 HeapManager.Storage.Header * header = headerAddr( addr ); 1150 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? 1151 header = realHeader( header ); // backup from fake to real header 1152 } // if 1153 size_t ret = header->kind.real.size; 1154 header->kind.real.size = size; 1155 return ret; 1156 } // $malloc_size_set 1157 1158 1159 // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by 1160 // malloc or a related function. 1000 1161 size_t malloc_usable_size( void * addr ) { 1001 1162 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size … … 1005 1166 1006 1167 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment ); 1007 return dataStorage( bsize, addr, header ); // data storage in bucket1168 return dataStorage( bsize, addr, header ); // data storage in bucket 1008 1169 } // malloc_usable_size 1009 1170 1010 1171 1011 // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and 1012 // related functions. 1172 // Prints (on default standard error) statistics about memory allocated by malloc and related functions. 1013 1173 void malloc_stats( void ) { 1014 1174 #ifdef __STATISTICS__ … … 1018 1178 } // malloc_stats 1019 1179 1020 // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics. 1180 1181 // Changes the file descripter where malloc_stats() writes statistics. 1021 1182 int malloc_stats_fd( int fd __attribute__(( unused )) ) { 1022 1183 #ifdef __STATISTICS__ 1023 int temp = stat fd;1024 stat fd = fd;1184 int temp = stat_fd; 1185 stat_fd = fd; 1025 1186 return temp; 1026 1187 #else … … 1030 1191 1031 1192 1032 // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see 1033 // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that 1034 // parameter. 1193 // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument 1194 // specifies the parameter to be modified, and value specifies the new value for that parameter. 1035 1195 int mallopt( int option, int value ) { 1036 1196 choose( option ) { 1037 1197 case M_TOP_PAD: 1038 if ( setHeapExpand( value ) )return 1;1198 heapExpand = ceiling2( value, __page_size ); return 1; 1039 1199 case M_MMAP_THRESHOLD: 1040 1200 if ( setMmapStart( value ) ) return 1; 1201 break; 1041 1202 } // switch 1042 1203 return 0; // error, unsupported 1043 1204 } // mallopt 1044 1205 1045 // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a 1046 // suitable argument).1206 1207 // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument). 1047 1208 int malloc_trim( size_t ) { 1048 1209 return 0; // => impossible to release memory … … 1050 1211 1051 1212 1052 // The malloc_info() function exports an XML string that describes the current state of the memory-allocation1053 // implementation in the caller. The string is printed on the file stream stream. The exported string includes1054 // information about all arenas (see malloc(3)).1213 // Exports an XML string that describes the current state of the memory-allocation implementation in the caller. 1214 // The string is printed on the file stream stream. The exported string includes information about all arenas (see 1215 // malloc). 1055 1216 int malloc_info( int options, FILE * stream ) { 1056 if ( options != 0 ) { errno = EINVAL; return -1; } 1217 if ( options != 0 ) { errno = EINVAL; return -1; } 1218 #ifdef __STATISTICS__ 1057 1219 return printStatsXML( stream ); 1220 #else 1221 return 0; // unsupported 1222 #endif // __STATISTICS__ 1058 1223 } // malloc_info 1059 1224 1060 1225 1061 // The malloc_get_state() function records the current state of all malloc(3) internal bookkeeping variables (but1062 // not the actual contents of the heap or the state of malloc_hook(3) functions pointers). The state is recorded in1063 // a system-dependent opaque data structure dynamically allocated via malloc(3), and a pointer to that data1064 // structure is returned as the function result. (It is the caller's responsibility to free(3)this memory.)1226 // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap 1227 // or the state of malloc_hook functions pointers). The state is recorded in a system-dependent opaque data 1228 // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function 1229 // result. (The caller must free this memory.) 1065 1230 void * malloc_get_state( void ) { 1066 1231 return 0p; // unsupported … … 1068 1233 1069 1234 1070 // The malloc_set_state() function restores the state of all malloc(3) internal bookkeeping variables to the values1071 // recorded in the opaque datastructure pointed to by state.1072 int malloc_set_state( void * ptr) {1235 // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data 1236 // structure pointed to by state. 1237 int malloc_set_state( void * ) { 1073 1238 return 0; // unsupported 1074 1239 } // malloc_set_state … … 1077 1242 1078 1243 // Must have CFA linkage to overload with C linkage realloc. 1079 void * re alloc( void * oaddr, size_t nalign, size_t size ) {1244 void * resize( void * oaddr, size_t nalign, size_t size ) { 1080 1245 #ifdef __STATISTICS__ 1081 __atomic_add_fetch( &re alloc_calls, 1, __ATOMIC_SEQ_CST );1246 __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST ); 1082 1247 #endif // __STATISTICS__ 1083 1248 1084 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1085 if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases 1086 if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size ); 1087 1088 if ( unlikely( nalign == 0 ) ) nalign = libAlign(); // reset alignment to minimum 1249 if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum 1089 1250 #ifdef __CFA_DEBUG__ 1090 1251 else … … 1092 1253 #endif // __CFA_DEBUG__ 1093 1254 1094 HeapManager.Storage.Header * header; 1095 HeapManager.FreeHeader * freeElem; 1096 size_t bsize, oalign = 0; 1097 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 1098 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket 1099 1100 if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out 1101 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same) 1102 return realloc( oaddr, size ); 1255 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1256 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases 1257 if ( unlikely( oaddr == 0p ) ) { 1258 #ifdef __STATISTICS__ 1259 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST ); 1260 #endif // __STATISTICS__ 1261 return memalignNoStats( nalign, size ); 1262 } // if 1263 1264 // Attempt to reuse existing alignment. 1265 HeapManager.Storage.Header * header = headerAddr( oaddr ); 1266 bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ? 1267 size_t oalign; 1268 if ( isFakeHeader ) { 1269 oalign = header->kind.fake.alignment & -2; // old alignment 1270 if ( (uintptr_t)oaddr % nalign == 0 // lucky match ? 1271 && ( oalign <= nalign // going down 1272 || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ? 1273 ) { 1274 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same) 1275 HeapManager.FreeHeader * freeElem; 1276 size_t bsize, oalign; 1277 headers( "resize", oaddr, header, freeElem, bsize, oalign ); 1278 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket 1279 1280 if ( size <= odsize && odsize <= size * 2 ) { // allow 50% wasted data storage 1281 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same) 1282 1283 header->kind.real.blockSize &= -2; // turn off 0 fill 1284 header->kind.real.size = size; // reset allocation size 1285 return oaddr; 1286 } // if 1287 } // if 1288 } else if ( ! isFakeHeader // old real header (aligned on libAlign) ? 1289 && nalign == libAlign() ) { // new alignment also on libAlign => no fake header needed 1290 return resize( oaddr, size ); // duplicate special case checks 1103 1291 } // if 1104 1292 1105 1293 #ifdef __STATISTICS__ 1294 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST ); 1295 #endif // __STATISTICS__ 1296 1297 // change size, DO NOT preserve STICKY PROPERTIES. 1298 free( oaddr ); 1299 return memalignNoStats( nalign, size ); // create new aligned area 1300 } // resize 1301 1302 1303 void * realloc( void * oaddr, size_t nalign, size_t size ) { 1304 if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum 1305 #ifdef __CFA_DEBUG__ 1306 else 1307 checkAlign( nalign ); // check alignment 1308 #endif // __CFA_DEBUG__ 1309 1310 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1311 if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases 1312 if ( unlikely( oaddr == 0p ) ) { 1313 #ifdef __STATISTICS__ 1314 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 1315 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 1316 #endif // __STATISTICS__ 1317 return memalignNoStats( nalign, size ); 1318 } // if 1319 1320 // Attempt to reuse existing alignment. 1321 HeapManager.Storage.Header * header = headerAddr( oaddr ); 1322 bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ? 1323 size_t oalign; 1324 if ( isFakeHeader ) { 1325 oalign = header->kind.fake.alignment & -2; // old alignment 1326 if ( (uintptr_t)oaddr % nalign == 0 // lucky match ? 1327 && ( oalign <= nalign // going down 1328 || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ? 1329 ) { 1330 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same) 1331 return realloc( oaddr, size ); // duplicate alignment and special case checks 1332 } // if 1333 } else if ( ! isFakeHeader // old real header (aligned on libAlign) ? 1334 && nalign == libAlign() ) // new alignment also on libAlign => no fake header needed 1335 return realloc( oaddr, size ); // duplicate alignment and special case checks 1336 1337 #ifdef __STATISTICS__ 1338 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 1106 1339 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 1107 1340 #endif // __STATISTICS__ 1108 1341 1342 HeapManager.FreeHeader * freeElem; 1343 size_t bsize; 1344 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 1345 1109 1346 // change size and copy old content to new storage 1110 1347 1111 void * naddr; 1112 if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill 1113 naddr = cmemalignNoStats( nalign, 1, size ); // create new aligned area 1114 } else { 1115 naddr = memalignNoStats( nalign, size ); // create new aligned area 1116 } // if 1348 size_t osize = header->kind.real.size; // old allocation size 1349 bool ozfill = (header->kind.real.blockSize & 2); // old allocation zero filled 1350 1351 void * naddr = memalignNoStats( nalign, size ); // create new aligned area 1117 1352 1118 1353 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 1119 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket 1120 // To preserve prior fill, the entire bucket must be copied versus the size. 1121 memcpy( naddr, oaddr, MIN( odsize, ndsize ) ); // copy bytes 1354 memcpy( naddr, oaddr, min( osize, size ) ); // copy bytes 1122 1355 free( oaddr ); 1356 1357 if ( unlikely( ozfill ) ) { // previous request zero fill ? 1358 header->kind.real.blockSize |= 2; // mark new request as zero filled 1359 if ( size > osize ) { // previous request larger ? 1360 memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage 1361 } // if 1362 } // if 1123 1363 return naddr; 1124 1364 } // realloc -
libcfa/src/interpose.cfa
rbdfc032 reef8dfb 10 10 // Created On : Wed Mar 29 16:10:31 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 30 17:47:32202013 // Update Count : 1 5612 // Last Modified On : Fri Mar 13 17:35:37 2020 13 // Update Count : 178 14 14 // 15 15 16 16 #include <stdarg.h> // va_start, va_end 17 #include <stdio.h> 17 18 #include <string.h> // strlen 18 19 #include <unistd.h> // _exit, getpid … … 29 30 #include "bits/signal.hfa" // sigHandler_? 30 31 #include "startup.hfa" // STARTUP_PRIORITY_CORE 32 #include <assert.h> 31 33 32 34 //============================================================================================= … … 40 42 41 43 typedef void (* generic_fptr_t)(void); 42 generic_fptr_t interpose_symbol( const char * symbol, const char * version) {44 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 43 45 const char * error; 44 46 … … 142 144 void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )); 143 145 void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 146 void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )); 144 147 145 148 extern "C" { 146 149 void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) { 147 abort( false, NULL ); // FIX ME: 0p does not work150 abort( false, "%s", "" ); 148 151 } 149 152 … … 151 154 va_list argp; 152 155 va_start( argp, fmt ); 153 abort( false, fmt, argp );156 __abort( false, fmt, argp ); 154 157 va_end( argp ); 155 158 } … … 161 164 162 165 void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; } 163 void kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}166 void kernel_abort_msg( void * data, char buffer[], int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {} 164 167 // See concurrency/kernel.cfa for strong definition used in multi-processor mode. 165 168 int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; } … … 169 172 170 173 static void __cfaabi_backtrace( int start ) { 171 enum { 172 Frames = 50, // maximum number of stack frames 173 }; 174 enum { Frames = 50, }; // maximum number of stack frames 174 175 int last = kernel_abort_lastframe(); // skip last N stack frames 175 176 176 177 void * array[Frames]; 177 178 size_t size = backtrace( array, Frames ); 178 char ** messages = backtrace_symbols( array, size ); 179 char ** messages = backtrace_symbols( array, size ); // does not demangle names 179 180 180 181 *index( messages[0], '(' ) = '\0'; // find executable name … … 184 185 char * name = 0p, * offset_begin = 0p, * offset_end = 0p; 185 186 186 for ( char * p = messages[i]; *p; ++p ) {// find parantheses and +offset187 for ( char * p = messages[i]; *p; p += 1 ) { // find parantheses and +offset 187 188 //__cfaabi_bits_print_nolock( "X %s\n", p); 188 189 if ( *p == '(' ) { … … 219 220 } 220 221 221 void abort( bool signalAbort, const char fmt[], ... ) { 222 void * kernel_data = kernel_abort(); // must be done here to lock down kernel 223 int len; 224 225 signal( SIGABRT, SIG_DFL ); // prevent final "real" abort from recursing to handler 226 227 len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid) 228 __cfaabi_bits_write( STDERR_FILENO, abort_text, len ); 229 230 if ( fmt ) { 231 va_list args; 232 va_start( args, fmt ); 233 222 static volatile int __abort_stage = 0; 223 224 // Cannot forward va_list. 225 void __abort( bool signalAbort, const char fmt[], va_list args ) { 226 int stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST ); 227 228 // First stage: stop the cforall kernel and print 229 if(stage == 1) { 230 // increment stage 231 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST ); 232 233 // must be done here to lock down kernel 234 void * kernel_data = kernel_abort(); 235 int len; 236 237 signal( SIGABRT, SIG_DFL ); // prevent final "real" abort from recursing to handler 238 239 len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid) 240 __cfaabi_bits_write( STDERR_FILENO, abort_text, len ); 241 242 assert( fmt ); 234 243 len = vsnprintf( abort_text, abort_text_size, fmt, args ); 235 va_end( args );236 244 __cfaabi_bits_write( STDERR_FILENO, abort_text, len ); 237 245 238 if ( fmt[strlen( fmt ) - 1] != '\n' ) { // add optional newline if missing at the end of the format text 239 __cfaabi_dbg_write( "\n", 1 ); 240 } 241 } 242 243 kernel_abort_msg( kernel_data, abort_text, abort_text_size ); 244 __cfaabi_backtrace( signalAbort ? 4 : 3 ); 245 246 __cabi_libc.abort(); // print stack trace in handler 246 // add optional newline if missing at the end of the format text 247 if ( fmt[strlen( fmt ) - 1] != '\n' ) { 248 __cfaabi_bits_write( STDERR_FILENO, "\n", 1 ); 249 } // if 250 kernel_abort_msg( kernel_data, abort_text, abort_text_size ); 251 } 252 253 // Second stage: print the backtrace 254 if(stage == 2) { 255 // increment stage 256 stage = __atomic_add_fetch( &__abort_stage, 1, __ATOMIC_SEQ_CST ); 257 258 // print stack trace in handler 259 __cfaabi_backtrace( signalAbort ? 4 : 2 ); 260 } 261 262 do { 263 // Finally call abort 264 __cabi_libc.abort(); 265 266 // Loop so that we never return 267 } while(true); 247 268 } 248 269 … … 250 271 va_list args; 251 272 va_start( args, fmt ); 252 abort( false, fmt, args ); 273 __abort( false, fmt, args ); 274 // CONTROL NEVER REACHES HERE! 253 275 va_end( args ); 276 } 277 278 void abort( bool signalAbort, const char fmt[], ... ) { 279 va_list args; 280 va_start( args, fmt ); 281 __abort( signalAbort, fmt, args ); 282 // CONTROL NEVER REACHES HERE! 283 va_end( args ); 254 284 } 255 285 -
libcfa/src/iostream.cfa
rbdfc032 reef8dfb 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 13 08:07:59 201913 // Update Count : 82112 // Last Modified On : Mon Aug 24 08:31:35 2020 13 // Update Count : 1130 14 14 // 15 15 16 16 #include "iostream.hfa" 17 17 18 extern "C" {19 18 #include <stdio.h> 20 19 #include <stdbool.h> // true/false 21 //#include <string.h> // strlen, strcmp 20 #include <stdint.h> // UINT64_MAX 21 #include <float.h> // DBL_DIG, LDBL_DIG 22 #include <complex.h> // creal, cimag 23 //#include <string.h> // strlen, strcmp, memcpy 24 extern "C" { 22 25 extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); 23 26 extern int strcmp (const char *__s1, const char *__s2) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2))); 24 27 extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2))); 25 28 extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2))); 26 #include <float.h> // DBL_DIG, LDBL_DIG27 #include <math.h> // isfinite28 #include <complex.h> // creal, cimag29 29 } // extern "C" 30 30 31 32 //*********************************** ostream *********************************** 31 #include "math.hfa" // isfinite, floor, ceiling_div 32 #include "bitmanip.hfa" // high1 33 34 35 // *********************************** ostream *********************************** 33 36 34 37 35 38 forall( dtype ostype | ostream( ostype ) ) { 36 ostype & ?|?( ostype & os, zero_t ) {37 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );38 fmt( os, "%d", 0n );39 return os;40 } // ?|?41 void ?|?( ostype & os, zero_t z ) {42 (ostype &)(os | z); ends( os );43 } // ?|?44 45 ostype & ?|?( ostype & os, one_t ) {46 if ( sepPrt( os ) ) fmt( os, "%s", sepGetCur( os ) );47 fmt( os, "%d", 1n );48 return os;49 } // ?|?50 void ?|?( ostype & os, one_t o ) {51 (ostype &)(os | o); ends( os );52 } // ?|?53 54 39 ostype & ?|?( ostype & os, bool b ) { 55 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );40 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 56 41 fmt( os, "%s", b ? "true" : "false" ); 57 42 return os; … … 63 48 ostype & ?|?( ostype & os, char c ) { 64 49 fmt( os, "%c", c ); 65 if ( c == '\n' ) setNL( os, true );50 if ( c == '\n' ) $setNL( os, true ); 66 51 return sepOff( os ); 67 52 } // ?|? … … 71 56 72 57 ostype & ?|?( ostype & os, signed char sc ) { 73 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );58 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 74 59 fmt( os, "%hhd", sc ); 75 60 return os; … … 80 65 81 66 ostype & ?|?( ostype & os, unsigned char usc ) { 82 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );67 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 83 68 fmt( os, "%hhu", usc ); 84 69 return os; … … 89 74 90 75 ostype & ?|?( ostype & os, short int si ) { 91 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );76 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 92 77 fmt( os, "%hd", si ); 93 78 return os; … … 98 83 99 84 ostype & ?|?( ostype & os, unsigned short int usi ) { 100 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );85 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 101 86 fmt( os, "%hu", usi ); 102 87 return os; … … 107 92 108 93 ostype & ?|?( ostype & os, int i ) { 109 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );94 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 110 95 fmt( os, "%d", i ); 111 96 return os; … … 116 101 117 102 ostype & ?|?( ostype & os, unsigned int ui ) { 118 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );103 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 119 104 fmt( os, "%u", ui ); 120 105 return os; … … 125 110 126 111 ostype & ?|?( ostype & os, long int li ) { 127 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );112 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 128 113 fmt( os, "%ld", li ); 129 114 return os; … … 134 119 135 120 ostype & ?|?( ostype & os, unsigned long int uli ) { 136 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );121 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 137 122 fmt( os, "%lu", uli ); 138 123 return os; … … 143 128 144 129 ostype & ?|?( ostype & os, long long int lli ) { 145 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );130 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 146 131 fmt( os, "%lld", lli ); 147 132 return os; … … 152 137 153 138 ostype & ?|?( ostype & os, unsigned long long int ulli ) { 154 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );139 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 155 140 fmt( os, "%llu", ulli ); 156 141 return os; … … 159 144 (ostype &)(os | ulli); ends( os ); 160 145 } // ?|? 146 147 #if defined( __SIZEOF_INT128__ ) 148 // UINT64_MAX 18_446_744_073_709_551_615_ULL 149 #define P10_UINT64 10_000_000_000_000_000_000_ULL // 19 zeroes 150 151 static inline void base10_128( ostype & os, unsigned int128 val ) { 152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7 153 if ( val > P10_UINT64 ) { 154 #else 155 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug 156 #endif // __GNUC_PREREQ(7,0) 157 base10_128( os, val / P10_UINT64 ); // recursive 158 fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) ); 159 } else { 160 fmt( os, "%lu", (uint64_t)val ); 161 } // if 162 } // base10_128 163 164 static inline void base10_128( ostype & os, int128 val ) { 165 if ( val < 0 ) { 166 fmt( os, "-" ); // leading negative sign 167 val = -val; 168 } // if 169 base10_128( os, (unsigned int128)val ); // print zero/positive value 170 } // base10_128 171 172 ostype & ?|?( ostype & os, int128 llli ) { 173 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 174 base10_128( os, llli ); 175 return os; 176 } // ?|? 177 void & ?|?( ostype & os, int128 llli ) { 178 (ostype &)(os | llli); ends( os ); 179 } // ?|? 180 181 ostype & ?|?( ostype & os, unsigned int128 ullli ) { 182 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 183 base10_128( os, ullli ); 184 return os; 185 } // ?|? 186 void & ?|?( ostype & os, unsigned int128 ullli ) { 187 (ostype &)(os | ullli); ends( os ); 188 } // ?|? 189 #endif // __SIZEOF_INT128__ 161 190 162 191 #define PrintWithDP( os, format, val, ... ) \ … … 175 204 176 205 ostype & ?|?( ostype & os, float f ) { 177 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );206 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 178 207 PrintWithDP( os, "%g", f ); 179 208 return os; … … 184 213 185 214 ostype & ?|?( ostype & os, double d ) { 186 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );215 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 187 216 PrintWithDP( os, "%.*lg", d, DBL_DIG ); 188 217 return os; … … 193 222 194 223 ostype & ?|?( ostype & os, long double ld ) { 195 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );224 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 196 225 PrintWithDP( os, "%.*Lg", ld, LDBL_DIG ); 197 226 return os; … … 202 231 203 232 ostype & ?|?( ostype & os, float _Complex fc ) { 204 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );233 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 205 234 // os | crealf( fc ) | nonl; 206 235 PrintWithDP( os, "%g", crealf( fc ) ); … … 214 243 215 244 ostype & ?|?( ostype & os, double _Complex dc ) { 216 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );245 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 217 246 // os | creal( dc ) | nonl; 218 247 PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG ); … … 226 255 227 256 ostype & ?|?( ostype & os, long double _Complex ldc ) { 228 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );257 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 229 258 // os | creall( ldc ) || nonl; 230 259 PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG ); … … 237 266 } // ?|? 238 267 239 ostype & ?|?( ostype & os, const char * str) {268 ostype & ?|?( ostype & os, const char str[] ) { 240 269 enum { Open = 1, Close, OpenClose }; 241 270 static const unsigned char mask[256] @= { … … 257 286 // first character IS NOT spacing or closing punctuation => add left separator 258 287 unsigned char ch = str[0]; // must make unsigned 259 if ( sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {260 fmt( os, "%s", sepGetCur( os ) );288 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) { 289 fmt( os, "%s", $sepGetCur( os ) ); 261 290 } // if 262 291 263 292 // if string starts line, must reset to determine open state because separator is off 264 sepReset( os );// reset separator293 $sepReset( os ); // reset separator 265 294 266 295 // last character IS spacing or opening punctuation => turn off separator for next item 267 296 size_t len = strlen( str ); 268 297 ch = str[len - 1]; // must make unsigned 269 if ( sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {298 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 270 299 sepOn( os ); 271 300 } else { 272 301 sepOff( os ); 273 302 } // if 274 if ( ch == '\n' ) setNL( os, true ); // check *AFTER*sepPrt call above as it resets NL flag303 if ( ch == '\n' ) $setNL( os, true ); // check *AFTER* $sepPrt call above as it resets NL flag 275 304 return write( os, str, len ); 276 305 } // ?|? 277 void ?|?( ostype & os, const char * str ) { 306 307 void ?|?( ostype & os, const char str[] ) { 278 308 (ostype &)(os | str); ends( os ); 279 309 } // ?|? 280 310 281 311 // ostype & ?|?( ostype & os, const char16_t * str ) { 282 // if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );312 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 283 313 // fmt( os, "%ls", str ); 284 314 // return os; … … 287 317 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 288 318 // ostype & ?|?( ostype & os, const char32_t * str ) { 289 // if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );319 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 290 320 // fmt( os, "%ls", str ); 291 321 // return os; … … 294 324 295 325 // ostype & ?|?( ostype & os, const wchar_t * str ) { 296 // if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );326 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 297 327 // fmt( os, "%ls", str ); 298 328 // return os; … … 300 330 301 331 ostype & ?|?( ostype & os, const void * p ) { 302 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );332 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 303 333 fmt( os, "%p", p ); 304 334 return os; … … 315 345 void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 316 346 (ostype &)(manip( os )); 317 if ( getPrt( os ) ) ends( os );// something printed ?318 setPrt( os, false ); // turn off347 if ( $getPrt( os ) ) ends( os ); // something printed ? 348 $setPrt( os, false ); // turn off 319 349 } // ?|? 320 350 … … 329 359 ostype & nl( ostype & os ) { 330 360 (ostype &)(os | '\n'); 331 setPrt( os, false ); // turn off332 setNL( os, true );361 $setPrt( os, false ); // turn off 362 $setNL( os, true ); 333 363 flush( os ); 334 364 return sepOff( os ); // prepare for next line … … 336 366 337 367 ostype & nonl( ostype & os ) { 338 setPrt( os, false ); // turn off368 $setPrt( os, false ); // turn off 339 369 return os; 340 370 } // nonl … … 375 405 ostype & ?|?( ostype & os, T arg, Params rest ) { 376 406 (ostype &)(os | arg); // print first argument 377 sepSetCur( os, sepGetTuple( os ) );// switch to tuple separator407 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator 378 408 (ostype &)(os | rest); // print remaining arguments 379 sepSetCur( os, sepGet( os ) ); // switch to regular separator409 $sepSetCur( os, sepGet( os ) ); // switch to regular separator 380 410 return os; 381 411 } // ?|? … … 383 413 // (ostype &)(?|?( os, arg, rest )); ends( os ); 384 414 (ostype &)(os | arg); // print first argument 385 sepSetCur( os, sepGetTuple( os ) );// switch to tuple separator415 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator 386 416 (ostype &)(os | rest); // print remaining arguments 387 sepSetCur( os, sepGet( os ) ); // switch to regular separator417 $sepSetCur( os, sepGet( os ) ); // switch to regular separator 388 418 ends( os ); 389 419 } // ?|? … … 403 433 } // distribution 404 434 405 // *********************************** manipulators ***********************************406 407 // *********************************** integral ***********************************435 // *********************************** manipulators *********************************** 436 437 // *********************************** integral *********************************** 408 438 409 439 static const char * shortbin[] = { "0", "1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; … … 411 441 412 442 // Default prefix for non-decimal prints is 0b, 0, 0x. 413 #define IntegralFMTImpl( T, CODE,IFMTNP, IFMTP ) \443 #define IntegralFMTImpl( T, IFMTNP, IFMTP ) \ 414 444 forall( dtype ostype | ostream( ostype ) ) { \ 415 445 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 416 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) ); \446 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 417 447 \ 418 448 if ( f.base == 'b' || f.base == 'B' ) { /* bespoke binary format */ \ 419 int bits; \ 420 if ( f.val == (T){0} ) bits = 1; /* force at least one bit to print */ \ 421 else bits = sizeof(long long int) * 8 - __builtin_clzll( f.val ); /* position of most significant bit */ \ 422 bits = bits > sizeof(f.val) * 8 ? sizeof(f.val) * 8 : bits; \ 423 int spaces = f.wd - bits; /* can be negative */ \ 424 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \ 425 /* printf( "%d %d\n", bits, spaces ); */ \ 449 int bits = high1( f.val ); /* position of most significant bit */ \ 450 if ( bits == 0 ) bits = 1; /* 0 value => force one bit to print */ \ 451 int spaces; \ 426 452 if ( ! f.flags.left ) { /* right justified ? */ \ 427 453 /* Note, base prefix then zero padding or spacing then prefix. */ \ 428 if ( f.flags.pad0 || f.flags.pc ) { \ 454 if ( f.flags.pc ) { \ 455 spaces = f.wd - f.pc; \ 456 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \ 457 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \ 429 458 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \ 430 if ( f.flags.pc )spaces = f.pc - bits; \459 spaces = f.pc - bits; \ 431 460 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \ 432 461 } else { \ 433 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \ 434 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \ 462 spaces = f.wd - bits; \ 463 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \ 464 if ( f.flags.pad0 ) { \ 465 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \ 466 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \ 467 } else { \ 468 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \ 469 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \ 470 } /* if */ \ 435 471 } /* if */ \ 436 } else if ( ! f.flags.nobsdp ) { \ 437 fmt( os, "0%c", f.base ); \ 472 } else { \ 473 if ( ! f.flags.nobsdp ) fmt( os, "0%c", f.base ); \ 474 if ( f.flags.pc ) { \ 475 spaces = f.pc - bits; \ 476 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \ 477 spaces = f.wd - f.pc; \ 478 } else { /* pad0 flag ignored with left flag */ \ 479 spaces = f.wd - bits; \ 480 } /* if */ \ 481 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \ 438 482 } /* if */ \ 439 int shift = (bits - 1) / 4 * 4; /* floor( bits - 1, 4 ) */\483 int shift = floor( bits - 1, 4 ); \ 440 484 typeof( f.val ) temp = f.val; \ 441 485 fmt( os, "%s", shortbin[(temp >> shift) & 0xf] ); \ … … 448 492 if ( f.flags.left && spaces > 0 ) fmt( os, "%*s", spaces, " " ); \ 449 493 return os; \ 450 } /* if 494 } /* if */ \ 451 495 \ 452 496 char fmtstr[sizeof(IFMTP)]; /* sizeof includes '\0' */ \ … … 458 502 if ( ! f.flags.nobsdp ) { fmtstr[star] = '#'; star -= 1; } \ 459 503 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \ 460 if ( f.flags.sign && f.base == CODE) { fmtstr[star] = '+'; star -= 1; } \504 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \ 461 505 if ( f.flags.pad0 && ! f.flags.pc ) { fmtstr[star] = '0'; star -= 1; } \ 462 506 fmtstr[star] = '%'; \ 463 507 \ 464 508 if ( ! f.flags.pc ) { /* no precision */ \ 465 /* printf( "%s\n", &fmtstr[star] ); */ \466 509 fmtstr[sizeof(IFMTNP)-2] = f.base; /* sizeof includes '\0' */ \ 510 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \ 467 511 fmt( os, &fmtstr[star], f.wd, f.val ); \ 468 512 } else { /* precision */ \ 469 513 fmtstr[sizeof(IFMTP)-2] = f.base; /* sizeof includes '\0' */ \ 470 /* printf( "%s \n", &fmtstr[star]); */ \514 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \ 471 515 fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \ 472 516 } /* if */ \ … … 476 520 } // distribution 477 521 478 IntegralFMTImpl( signed char, 'd', "% *hh ", "% *.*hh " ) 479 IntegralFMTImpl( unsigned char, 'u', "% *hh ", "% *.*hh " ) 480 IntegralFMTImpl( signed short int, 'd', "% *h ", "% *.*h " ) 481 IntegralFMTImpl( unsigned short int, 'u', "% *h ", "% *.*h " ) 482 IntegralFMTImpl( signed int, 'd', "% * ", "% *.* " ) 483 IntegralFMTImpl( unsigned int, 'u', "% * ", "% *.* " ) 484 IntegralFMTImpl( signed long int, 'd', "% *l ", "% *.*l " ) 485 IntegralFMTImpl( unsigned long int, 'u', "% *l ", "% *.*l " ) 486 IntegralFMTImpl( signed long long int, 'd', "% *ll ", "% *.*ll " ) 487 IntegralFMTImpl( unsigned long long int, 'u', "% *ll ", "% *.*ll " ) 488 489 //*********************************** floating point *********************************** 522 IntegralFMTImpl( signed char, "% *hh ", "% *.*hh " ) 523 IntegralFMTImpl( unsigned char, "% *hh ", "% *.*hh " ) 524 IntegralFMTImpl( signed short int, "% *h ", "% *.*h " ) 525 IntegralFMTImpl( unsigned short int, "% *h ", "% *.*h " ) 526 IntegralFMTImpl( signed int, "% * ", "% *.* " ) 527 IntegralFMTImpl( unsigned int, "% * ", "% *.* " ) 528 IntegralFMTImpl( signed long int, "% *l ", "% *.*l " ) 529 IntegralFMTImpl( unsigned long int, "% *l ", "% *.*l " ) 530 IntegralFMTImpl( signed long long int, "% *ll ", "% *.*ll " ) 531 IntegralFMTImpl( unsigned long long int, "% *ll ", "% *.*ll " ) 532 533 #if 0 534 #if defined( __SIZEOF_INT128__ ) 535 // Default prefix for non-decimal prints is 0b, 0, 0x. 536 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \ 537 forall( dtype ostype | ostream( ostype ) ) \ 538 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \ 539 if ( f.val > UINT64_MAX ) { \ 540 unsigned long long int lsig = f.val % P10_UINT64; \ 541 f.val /= P10_UINT64; /* msig */ \ 542 base10_128( os, f ); /* recursion */ \ 543 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \ 544 fmt.flags.nobsdp = true; \ 545 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \ 546 sepOff( os ); \ 547 (ostype &)(os | fmt); \ 548 } else { \ 549 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \ 550 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \ 551 (ostype &)(os | fmt); \ 552 } /* if */ \ 553 } /* base10_128 */ \ 554 forall( dtype ostype | ostream( ostype ) ) { \ 555 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 556 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 557 \ 558 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \ 559 unsigned long long int msig = (unsigned long long int)(f.val >> 64); \ 560 unsigned long long int lsig = (unsigned long long int)(f.val); \ 561 _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \ 562 _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \ 563 if ( msig == 0 ) { \ 564 fmt.val = lsig; \ 565 (ostype &)(os | fmt); \ 566 } else { \ 567 fmt2.flags.pad0 = fmt2.flags.nobsdp = true; \ 568 if ( f.base == 'b' | f.base == 'B' ) { \ 569 if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \ 570 if ( fmt.flags.left ) { \ 571 fmt.flags.left = false; \ 572 fmt.wd = 0; \ 573 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 574 fmt2.flags.left = true; \ 575 int msigd = high1( msig ); \ 576 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 577 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \ 578 if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \ 579 fmt2.flags.pc = true; fmt2.pc = 64; \ 580 } else { \ 581 if ( fmt.wd > 64 ) fmt.wd -= 64; \ 582 else fmt.wd = 1; \ 583 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 584 fmt2.wd = 64; \ 585 } /* if */ \ 586 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 587 (ostype &)(os | fmt | "" | fmt2); \ 588 } else if ( f.base == 'o' ) { \ 589 if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \ 590 fmt.val = (unsigned long long int)fmt.val >> 2; \ 591 fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \ 592 if ( fmt.flags.left ) { \ 593 fmt.flags.left = false; \ 594 fmt.wd = 0; \ 595 /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 596 (ostype &)(os | fmt | "" | fmt2); \ 597 sepOff( os ); \ 598 fmt2.flags.left = true; \ 599 int msigd = ceiling_div( high1( fmt.val ), 3 ); \ 600 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 601 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \ 602 if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \ 603 fmt2.flags.pc = true; fmt2.pc = 21; \ 604 } else { \ 605 if ( fmt.wd > 22 ) fmt.wd -= 22; \ 606 else fmt.wd = 1; \ 607 /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 608 (ostype &)(os | fmt | "" | fmt2); \ 609 sepOff( os ); \ 610 fmt2.wd = 21; \ 611 } /* if */ \ 612 fmt2.val = lsig & 0x7fffffffffffffffU; \ 613 /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 614 (ostype &)(os | fmt2); \ 615 } else { /* f.base == 'x' | f.base == 'X' */ \ 616 if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \ 617 if ( fmt.flags.left ) { \ 618 fmt.flags.left = false; \ 619 fmt.wd = 0; \ 620 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 621 fmt2.flags.left = true; \ 622 int msigd = high1( msig ); \ 623 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 624 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \ 625 if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \ 626 fmt2.flags.pc = true; fmt2.pc = 16; \ 627 } else { \ 628 if ( fmt.wd > 16 ) fmt.wd -= 16; \ 629 else fmt.wd = 1; \ 630 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 631 fmt2.wd = 16; \ 632 } /* if */ \ 633 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 634 (ostype &)(os | fmt | "" | fmt2); \ 635 } /* if */ \ 636 } /* if */ \ 637 } else { \ 638 if ( CODE == 'd' ) { \ 639 if ( f.val < 0 ) { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \ 640 } /* if */ \ 641 base10_128( os, f ); \ 642 } /* if */ \ 643 return os; \ 644 } /* ?|? */ \ 645 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 646 } // distribution 647 648 IntegralFMTImpl128( int128, signed, 'd', "% *ll ", "% *.*ll " ) 649 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "% *ll ", "% *.*ll " ) 650 #endif // __SIZEOF_INT128__ 651 #endif // 0 652 653 #if 1 654 #if defined( __SIZEOF_INT128__ ) 655 // Default prefix for non-decimal prints is 0b, 0, 0x. 656 forall( dtype ostype | ostream( ostype ) ) 657 static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) { 658 int wd = 1; // f.wd is never 0 because 0 implies left-pad 659 if ( val > power ) { // subdivide value into printable 64-bit values 660 base_128( os, val / power, power, f, maxdig, bits, cnt + 1 ); // recursive 661 f.val = val % power; 662 if ( cnt == 1 && f.flags.left ) { wd = f.wd; f.wd = maxdig; } // copy f.wd and reset for printing middle chunk 663 // printf( "R val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n", 664 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 ); 665 (ostype &)(os | f); 666 if ( cnt == 1 ) { 667 if ( f.flags.left ) { wd -= maxdig; f.wd = wd < 0 ? 1 : wd; } // update and restore f.wd for printing end chunk 668 sepOff( os ); // no seperator between chunks 669 } // if 670 } else { // print start chunk 671 f.val = val; 672 // f.pc is unsigned => use wd 673 if ( f.flags.pc && f.pc > maxdig * cnt ) { wd = f.pc - maxdig * cnt; f.pc = wd < 0 ? 0 : wd; } 674 else { f.flags.pc = false; f.pc = 0; } 675 676 if ( ! f.flags.left ) { // right justify 677 wd = f.wd - maxdig * cnt; 678 f.wd = wd < 0 ? 1 : wd; 679 wd = maxdig; 680 } else { // left justify 681 if ( cnt != 0 ) { // value >= 2^64 ? 682 unsigned int dig, bs = 0; 683 // compute size of prefix digits and base 684 if ( f.base == 'd' || f.base == 'u' ) { // no base prefix 685 dig = ceil( log10( f.val ) ); // use floating-point 686 if ( f.base == 'd' && (f.flags.neg || f.flags.sign) ) bs = 1; // sign ? 687 } else { 688 dig = ceiling_div( high1( f.val ), bits ); 689 if ( ! f.flags.nobsdp ) { // base prefix ? 690 if ( f.base == 'o' ) { 691 // 0 prefix for octal is not added for precision with leading zero 692 if ( f.pc <= dig ) bs = 1; // 1 character prefix 693 } else bs = 2; // 2 character prefix 694 } // if 695 } // if 696 wd = f.wd - (f.pc > dig ? f.pc : dig) - bs; // precision > leading digits ? 697 if ( wd < 0 ) wd = 1; 698 f.wd = 1; 699 } // if 700 // all manipulators handled implicitly for value < 2^64 701 } // if 702 // prior checks ensure wd not negative 703 704 if ( f.flags.neg ) f.val = -f.val; 705 // printf( "L val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n", 706 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 ); 707 (ostype &)(os | f); 708 709 // remaining middle and end chunks are padded with 0s on the left 710 if ( ! f.flags.left ) { f.flags.pad0 = true; f.flags.pc = false; } // left pad with 0s 711 else { f.pc = maxdig; f.flags.pc = true; } // left pad with precision 712 713 if ( cnt != 0 ) sepOff( os ); // no seperator between chunks 714 f.wd = wd; // reset f.wd for next chunk 715 f.flags.sign = false; // no leading +/- sign 716 f.flags.nobsdp = true; // no leading base prefix 717 } // if 718 } // base_128 719 720 #define IntegralFMTImpl128( T ) \ 721 forall( dtype ostype | ostream( ostype ) ) { \ 722 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 723 _Ostream_Manip(uint64_t) fmt; \ 724 fmt.[wd, pc, base, all] = f.[wd, pc, base, all]; \ 725 if ( f.base == 'b' | f.base == 'B' ) { \ 726 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 64, 1 ); \ 727 } else if ( f.base == 'o' ) { \ 728 base_128( os, f.val, (unsigned int128)1 << 63, fmt, 21, 3 ); \ 729 } else if ( f.base == 'd' || f.base == 'u' ) { \ 730 if ( f.base == 'd' && f.val < 0 ) { f.val = -f.val; fmt.flags.neg = true; } \ 731 base_128( os, f.val, (unsigned int128)10_000_000_000_000_000_000UL, fmt, 19, 0 ); \ 732 } else { \ 733 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 16, 4 ); \ 734 } /* if */ \ 735 return os; \ 736 } /* ?|? */ \ 737 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 738 } // distribution 739 740 IntegralFMTImpl128( int128 ) 741 IntegralFMTImpl128( unsigned int128 ) 742 #endif // __SIZEOF_INT128__ 743 #endif // 0 744 745 // *********************************** floating point *********************************** 490 746 491 747 #define PrintWithDP2( os, format, val, ... ) \ … … 513 769 forall( dtype ostype | ostream( ostype ) ) { \ 514 770 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 515 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) ); \771 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 516 772 char fmtstr[sizeof(DFMTP)]; /* sizeof includes '\0' */ \ 517 773 if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \ … … 536 792 return os; \ 537 793 } /* ?|? */ \ 794 \ 538 795 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 539 796 } // distribution … … 542 799 FloatingPointFMTImpl( long double, "% *L ", "% *.*L " ) 543 800 544 // *********************************** character ***********************************801 // *********************************** character *********************************** 545 802 546 803 forall( dtype ostype | ostream( ostype ) ) { … … 555 812 } // if 556 813 557 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );814 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 558 815 559 816 #define CFMTNP "% * " … … 571 828 return os; 572 829 } // ?|? 830 573 831 void ?|?( ostype & os, _Ostream_Manip(char) f ) { (ostype &)(os | f); ends( os ); } 574 832 } // distribution 575 833 576 // *********************************** C string ***********************************834 // *********************************** C string *********************************** 577 835 578 836 forall( dtype ostype | ostream( ostype ) ) { … … 592 850 } // if 593 851 594 if ( sepPrt( os ) ) fmt( os, "%s",sepGetCur( os ) );852 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); 595 853 596 854 #define SFMTNP "% * " … … 616 874 return os; 617 875 } // ?|? 876 618 877 void ?|?( ostype & os, _Ostream_Manip(const char *) f ) { (ostype &)(os | f); ends( os ); } 619 878 } // distribution 620 879 621 880 622 // *********************************** istream ***********************************881 // *********************************** istream *********************************** 623 882 624 883 … … 697 956 } // ?|? 698 957 958 #if defined( __SIZEOF_INT128__ ) 959 istype & ?|?( istype & is, int128 & i128 ) { 960 return (istype &)(is | (unsigned int128 &)i128); 961 } // ?|? 962 963 istype & ?|?( istype & is, unsigned int128 & ui128 ) { 964 char s[40]; 965 bool sign = false; 966 967 if ( fmt( is, " %[-]", s ) == 1 ) sign = true; // skip whitespace, negative sign ? 968 // If the input is too large, the value returned is undefined. If there is no input, no value is returned 969 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) { // take first 39 characters, ignore remaining 970 ui128 = 0; 971 for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) { 972 ui128 = ui128 * 10 + s[i] - '0'; 973 } // for 974 if ( sign ) ui128 = -ui128; 975 } else if ( sign ) ungetc( is, '-' ); // return minus when no digits 976 return is; 977 } // ?|? 978 #endif // __SIZEOF_INT128__ 699 979 700 980 istype & ?|?( istype & is, float & f ) { … … 735 1015 } // ?|? 736 1016 737 // istype & ?|?( istype & is, const char * fmt) {1017 // istype & ?|?( istype & is, const char fmt[] ) { 738 1018 // fmt( is, fmt, "" ); 739 1019 // return is; … … 766 1046 } // distribution 767 1047 768 // *********************************** manipulators ***********************************1048 // *********************************** manipulators *********************************** 769 1049 770 1050 forall( dtype istype | istream( istype ) ) -
libcfa/src/iostream.hfa
rbdfc032 reef8dfb 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 12 12:08:38 201913 // Update Count : 3 3412 // Last Modified On : Tue Aug 11 22:16:14 2020 13 // Update Count : 350 14 14 // 15 15 … … 19 19 20 20 21 // *********************************** ostream ***********************************21 // *********************************** ostream *********************************** 22 22 23 23 24 24 trait ostream( dtype ostype ) { 25 25 // private 26 bool sepPrt( ostype & ); // get separator state (on/off)27 void sepReset( ostype & ); // set separator state to default state28 void sepReset( ostype &, bool ); // set separator and default state29 const char * sepGetCur( ostype & );// get current separator string30 void sepSetCur( ostype &, const char *); // set current separator string31 bool getNL( ostype & );// check newline32 void setNL( ostype &, bool ); // saw newline33 bool getANL( ostype & ); // get auto newline (on/off)34 bool getPrt( ostype & ); // get fmt called in output cascade35 void setPrt( ostype &, bool ); // set fmt called in output cascade26 bool $sepPrt( ostype & ); // get separator state (on/off) 27 void $sepReset( ostype & ); // set separator state to default state 28 void $sepReset( ostype &, bool ); // set separator and default state 29 const char * $sepGetCur( ostype & ); // get current separator string 30 void $sepSetCur( ostype &, const char [] ); // set current separator string 31 bool $getNL( ostype & ); // check newline 32 void $setNL( ostype &, bool ); // saw newline 33 bool $getANL( ostype & ); // get auto newline (on/off) 34 bool $getPrt( ostype & ); // get fmt called in output cascade 35 void $setPrt( ostype &, bool ); // set fmt called in output cascade 36 36 // public 37 37 void sepOn( ostype & ); // turn separator state on … … 43 43 44 44 const char * sepGet( ostype & ); // get separator string 45 void sepSet( ostype &, const char *); // set separator to string (15 character maximum)45 void sepSet( ostype &, const char [] ); // set separator to string (15 character maximum) 46 46 const char * sepGetTuple( ostype & ); // get tuple separator string 47 void sepSetTuple( ostype &, const char * );// set tuple separator to string (15 character maximum)47 void sepSetTuple( ostype &, const char [] ); // set tuple separator to string (15 character maximum) 48 48 49 49 void ends( ostype & os ); // end of output statement 50 50 int fail( ostype & ); 51 51 int flush( ostype & ); 52 void open( ostype & os, const char * name, const char * mode);52 void open( ostype & os, const char name[], const char mode[] ); 53 53 void close( ostype & os ); 54 ostype & write( ostype &, const char *, size_t );54 ostype & write( ostype &, const char [], size_t ); 55 55 int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 56 56 }; // ostream … … 67 67 68 68 forall( dtype ostype | ostream( ostype ) ) { 69 ostype & ?|?( ostype &, zero_t );70 void ?|?( ostype &, zero_t );71 ostype & ?|?( ostype &, one_t );72 void ?|?( ostype &, one_t );73 74 69 ostype & ?|?( ostype &, bool ); 75 70 void ?|?( ostype &, bool ); … … 98 93 ostype & ?|?( ostype &, unsigned long long int ); 99 94 void ?|?( ostype &, unsigned long long int ); 95 #if defined( __SIZEOF_INT128__ ) 96 ostype & ?|?( ostype &, int128 ); 97 void ?|?( ostype &, int128 ); 98 ostype & ?|?( ostype &, unsigned int128 ); 99 void ?|?( ostype &, unsigned int128 ); 100 #endif // __SIZEOF_INT128__ 100 101 101 102 ostype & ?|?( ostype &, float ); … … 113 114 void ?|?( ostype &, long double _Complex ); 114 115 115 ostype & ?|?( ostype &, const char *);116 void ?|?( ostype &, const char *);116 ostype & ?|?( ostype &, const char [] ); 117 void ?|?( ostype &, const char [] ); 117 118 // ostype & ?|?( ostype &, const char16_t * ); 118 119 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous … … 150 151 } // distribution 151 152 152 // *********************************** manipulators ***********************************153 // *********************************** manipulators *********************************** 153 154 154 155 forall( otype T ) … … 160 161 unsigned char all; 161 162 struct { 163 unsigned char neg:1; // val is negative 162 164 unsigned char pc:1; // precision specified 163 165 unsigned char left:1; // left justify … … 169 171 }; // _Ostream_Manip 170 172 171 // *********************************** integral ***********************************173 // *********************************** integral *********************************** 172 174 173 175 // See 6.7.9. 19) The initialization shall occur in initializer list order, each initializer provided for a particular … … 206 208 IntegralFMTDecl( signed long long int, 'd' ) 207 209 IntegralFMTDecl( unsigned long long int, 'u' ) 208 209 //*********************************** floating point *********************************** 210 #if defined( __SIZEOF_INT128__ ) 211 IntegralFMTDecl( int128, 'd' ) 212 IntegralFMTDecl( unsigned int128, 'u' ) 213 #endif // __SIZEOF_INT128__ 214 215 // *********************************** floating point *********************************** 210 216 211 217 // Default suffix for values with no fraction is "." … … 236 242 FloatingPointFMTDecl( long double ) 237 243 238 // *********************************** character ***********************************244 // *********************************** character *********************************** 239 245 240 246 static inline { … … 253 259 } // ?|? 254 260 255 // *********************************** C string ***********************************261 // *********************************** C string *********************************** 256 262 257 263 static inline { 258 _Ostream_Manip(const char *) bin( const char * s) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; }259 _Ostream_Manip(const char *) oct( const char * s) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; }260 _Ostream_Manip(const char *) hex( const char * s) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }261 _Ostream_Manip(const char *) wd( unsigned int w, const char * s) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }262 _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char * s) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }264 _Ostream_Manip(const char *) bin( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'b', { .all : 0 } }; } 265 _Ostream_Manip(const char *) oct( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'o', { .all : 0 } }; } 266 _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; } 267 _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; } 268 _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; } 263 269 _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; } 264 270 _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } … … 272 278 273 279 274 // *********************************** istream ***********************************280 // *********************************** istream *********************************** 275 281 276 282 … … 281 287 int fail( istype & ); 282 288 int eof( istype & ); 283 void open( istype & is, const char * name);289 void open( istype & is, const char name[] ); 284 290 void close( istype & is ); 285 291 istype & read( istype &, char *, size_t ); … … 304 310 istype & ?|?( istype &, unsigned int & ); 305 311 istype & ?|?( istype &, long int & ); 312 istype & ?|?( istype &, unsigned long int & ); 306 313 istype & ?|?( istype &, long long int & ); 307 istype & ?|?( istype &, unsigned long int & );308 314 istype & ?|?( istype &, unsigned long long int & ); 315 #if defined( __SIZEOF_INT128__ ) 316 istype & ?|?( istype &, int128 & ); 317 istype & ?|?( istype &, unsigned int128 & ); 318 #endif // __SIZEOF_INT128__ 309 319 310 320 istype & ?|?( istype &, float & ); … … 316 326 istype & ?|?( istype &, long double _Complex & ); 317 327 318 // istype & ?|?( istype &, const char *);328 // istype & ?|?( istype &, const char [] ); 319 329 istype & ?|?( istype &, char * ); 320 330 … … 326 336 } // distribution 327 337 328 // *********************************** manipulators ***********************************338 // *********************************** manipulators *********************************** 329 339 330 340 struct _Istream_Cstr { … … 343 353 static inline { 344 354 _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; } 345 _Istream_Cstr skip( const char * scanset) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }346 _Istream_Cstr incl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }347 _Istream_Cstr & incl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }348 _Istream_Cstr excl( const char * scanset, char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; }349 _Istream_Cstr & excl( const char * scanset, _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }350 _Istream_Cstr ignore( c onst char * s) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; }355 _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; } 356 _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; } 357 _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } 358 _Istream_Cstr excl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : true } }; } 359 _Istream_Cstr & excl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; } 360 _Istream_Cstr ignore( char s[] ) { return (_Istream_Cstr)@{ s, 0p, -1, { .flags.ignore : true } }; } 351 361 _Istream_Cstr & ignore( _Istream_Cstr & fmt ) { fmt.flags.ignore = true; return fmt; } 352 _Istream_Cstr wdi( unsigned int w, char * s) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; }362 _Istream_Cstr wdi( unsigned int w, char s[] ) { return (_Istream_Cstr)@{ s, 0p, w, { .all : 0 } }; } 353 363 _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; } 354 364 } // distribution … … 360 370 361 371 static inline { 362 _Istream_Char ignore( const char c) { return (_Istream_Char)@{ true }; }372 _Istream_Char ignore( const char ) { return (_Istream_Char)@{ true }; } 363 373 _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; } 364 374 } // distribution 365 375 forall( dtype istype | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f ); 366 376 367 forall( otype T)377 forall( dtype T | sized( T ) ) 368 378 struct _Istream_Manip { 369 379 T & val; // polymorphic base-type … … 403 413 404 414 405 // *********************************** time ***********************************415 // *********************************** time *********************************** 406 416 407 417 -
libcfa/src/math.hfa
rbdfc032 reef8dfb 10 10 // Created On : Mon Apr 18 23:37:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 13 11:02:15 201813 // Update Count : 1 1612 // Last Modified On : Mon Aug 24 08:56:20 2020 13 // Update Count : 126 14 14 // 15 15 … … 19 19 #include <complex.h> 20 20 21 //--------------------------------------- 22 23 #include "common.hfa" 24 21 25 //---------------------- General ---------------------- 22 26 23 static inline float ?%?( float x, float y ) { return fmodf( x, y ); } 24 static inline float fmod( float x, float y ) { return fmodf( x, y ); } 25 static inline double ?%?( double x, double y ) { return fmod( x, y ); } 26 // extern "C" { double fmod( double, double ); } 27 static inline long double ?%?( long double x, long double y ) { return fmodl( x, y ); } 28 static inline long double fmod( long double x, long double y ) { return fmodl( x, y ); } 29 30 static inline float remainder( float x, float y ) { return remainderf( x, y ); } 31 // extern "C" { double remainder( double, double ); } 32 static inline long double remainder( long double x, long double y ) { return remainderl( x, y ); } 33 34 static inline float remquo( float x, float y, int * quo ) { return remquof( x, y, quo ); } 35 // extern "C" { double remquo( double x, double y, int * quo ); } 36 static inline long double remquo( long double x, long double y, int * quo ) { return remquol( x, y, quo ); } 37 static inline [ int, float ] remquo( float x, float y ) { int quo; x = remquof( x, y, &quo ); return [ quo, x ]; } 38 static inline [ int, double ] remquo( double x, double y ) { int quo; x = remquo( x, y, &quo ); return [ quo, x ]; } 39 static inline [ int, long double ] remquo( long double x, long double y ) { int quo; x = remquol( x, y, &quo ); return [ quo, x ]; } 40 41 static inline [ float, float ] div( float x, float y ) { y = modff( x / y, &x ); return [ x, y ]; } 42 static inline [ double, double ] div( double x, double y ) { y = modf( x / y, &x ); return [ x, y ]; } 43 static inline [ long double, long double ] div( long double x, long double y ) { y = modfl( x / y, &x ); return [ x, y ]; } 44 45 static inline float fma( float x, float y, float z ) { return fmaf( x, y, z ); } 46 // extern "C" { double fma( double, double, double ); } 47 static inline long double fma( long double x, long double y, long double z ) { return fmal( x, y, z ); } 48 49 static inline float fdim( float x, float y ) { return fdimf( x, y ); } 50 // extern "C" { double fdim( double, double ); } 51 static inline long double fdim( long double x, long double y ) { return fdiml( x, y ); } 52 53 static inline float nan( const char * tag ) { return nanf( tag ); } 54 // extern "C" { double nan( const char * ); } 55 static inline long double nan( const char * tag ) { return nanl( tag ); } 27 static inline { 28 float ?%?( float x, float y ) { return fmodf( x, y ); } 29 float fmod( float x, float y ) { return fmodf( x, y ); } 30 double ?%?( double x, double y ) { return fmod( x, y ); } 31 // extern "C" { double fmod( double, double ); } 32 long double ?%?( long double x, long double y ) { return fmodl( x, y ); } 33 long double fmod( long double x, long double y ) { return fmodl( x, y ); } 34 35 float remainder( float x, float y ) { return remainderf( x, y ); } 36 // extern "C" { double remainder( double, double ); } 37 long double remainder( long double x, long double y ) { return remainderl( x, y ); } 38 39 float remquo( float x, float y, int * quo ) { return remquof( x, y, quo ); } 40 // extern "C" { double remquo( double x, double y, int * quo ); } 41 long double remquo( long double x, long double y, int * quo ) { return remquol( x, y, quo ); } 42 [ int, float ] remquo( float x, float y ) { int quo; x = remquof( x, y, &quo ); return [ quo, x ]; } 43 [ int, double ] remquo( double x, double y ) { int quo; x = remquo( x, y, &quo ); return [ quo, x ]; } 44 [ int, long double ] remquo( long double x, long double y ) { int quo; x = remquol( x, y, &quo ); return [ quo, x ]; } 45 46 [ float, float ] div( float x, float y ) { y = modff( x / y, &x ); return [ x, y ]; } 47 [ double, double ] div( double x, double y ) { y = modf( x / y, &x ); return [ x, y ]; } 48 [ long double, long double ] div( long double x, long double y ) { y = modfl( x / y, &x ); return [ x, y ]; } 49 50 float fma( float x, float y, float z ) { return fmaf( x, y, z ); } 51 // extern "C" { double fma( double, double, double ); } 52 long double fma( long double x, long double y, long double z ) { return fmal( x, y, z ); } 53 54 float fdim( float x, float y ) { return fdimf( x, y ); } 55 // extern "C" { double fdim( double, double ); } 56 long double fdim( long double x, long double y ) { return fdiml( x, y ); } 57 58 float nan( const char tag[] ) { return nanf( tag ); } 59 // extern "C" { double nan( const char [] ); } 60 long double nan( const char tag[] ) { return nanl( tag ); } 61 } // distribution 56 62 57 63 //---------------------- Exponential ---------------------- 58 64 59 static inline float exp( float x ) { return expf( x ); } 60 // extern "C" { double exp( double ); } 61 static inline long double exp( long double x ) { return expl( x ); } 62 static inline float _Complex exp( float _Complex x ) { return cexpf( x ); } 63 static inline double _Complex exp( double _Complex x ) { return cexp( x ); } 64 static inline long double _Complex exp( long double _Complex x ) { return cexpl( x ); } 65 66 static inline float exp2( float x ) { return exp2f( x ); } 67 // extern "C" { double exp2( double ); } 68 static inline long double exp2( long double x ) { return exp2l( x ); } 69 //static inline float _Complex exp2( float _Complex x ) { return cexp2f( x ); } 70 //static inline double _Complex exp2( double _Complex x ) { return cexp2( x ); } 71 //static inline long double _Complex exp2( long double _Complex x ) { return cexp2l( x ); } 72 73 static inline float expm1( float x ) { return expm1f( x ); } 74 // extern "C" { double expm1( double ); } 75 static inline long double expm1( long double x ) { return expm1l( x ); } 76 77 static inline float pow( float x, float y ) { return powf( x, y ); } 78 // extern "C" { double pow( double, double ); } 79 static inline long double pow( long double x, long double y ) { return powl( x, y ); } 80 static inline float _Complex pow( float _Complex x, float _Complex y ) { return cpowf( x, y ); } 81 static inline double _Complex pow( double _Complex x, double _Complex y ) { return cpow( x, y ); } 82 static inline long double _Complex pow( long double _Complex x, long double _Complex y ) { return cpowl( x, y ); } 65 static inline { 66 float exp( float x ) { return expf( x ); } 67 // extern "C" { double exp( double ); } 68 long double exp( long double x ) { return expl( x ); } 69 float _Complex exp( float _Complex x ) { return cexpf( x ); } 70 double _Complex exp( double _Complex x ) { return cexp( x ); } 71 long double _Complex exp( long double _Complex x ) { return cexpl( x ); } 72 73 float exp2( float x ) { return exp2f( x ); } 74 // extern "C" { double exp2( double ); } 75 long double exp2( long double x ) { return exp2l( x ); } 76 //float _Complex exp2( float _Complex x ) { return cexp2f( x ); } 77 //double _Complex exp2( double _Complex x ) { return cexp2( x ); } 78 //long double _Complex exp2( long double _Complex x ) { return cexp2l( x ); } 79 80 float expm1( float x ) { return expm1f( x ); } 81 // extern "C" { double expm1( double ); } 82 long double expm1( long double x ) { return expm1l( x ); } 83 84 float pow( float x, float y ) { return powf( x, y ); } 85 // extern "C" { double pow( double, double ); } 86 long double pow( long double x, long double y ) { return powl( x, y ); } 87 float _Complex pow( float _Complex x, float _Complex y ) { return cpowf( x, y ); } 88 double _Complex pow( double _Complex x, double _Complex y ) { return cpow( x, y ); } 89 long double _Complex pow( long double _Complex x, long double _Complex y ) { return cpowl( x, y ); } 90 } // distribution 83 91 84 92 //---------------------- Logarithm ---------------------- 85 93 86 static inline float log( float x ) { return logf( x ); } 87 // extern "C" { double log( double ); } 88 static inline long double log( long double x ) { return logl( x ); } 89 static inline float _Complex log( float _Complex x ) { return clogf( x ); } 90 static inline double _Complex log( double _Complex x ) { return clog( x ); } 91 static inline long double _Complex log( long double _Complex x ) { return clogl( x ); } 92 93 static inline float log2( float x ) { return log2f( x ); } 94 // extern "C" { double log2( double ); } 95 static inline long double log2( long double x ) { return log2l( x ); } 96 // static inline float _Complex log2( float _Complex x ) { return clog2f( x ); } 97 // static inline double _Complex log2( double _Complex x ) { return clog2( x ); } 98 // static inline long double _Complex log2( long double _Complex x ) { return clog2l( x ); } 99 100 static inline float log10( float x ) { return log10f( x ); } 101 // extern "C" { double log10( double ); } 102 static inline long double log10( long double x ) { return log10l( x ); } 103 // static inline float _Complex log10( float _Complex x ) { return clog10f( x ); } 104 // static inline double _Complex log10( double _Complex x ) { return clog10( x ); } 105 // static inline long double _Complex log10( long double _Complex x ) { return clog10l( x ); } 106 107 static inline float log1p( float x ) { return log1pf( x ); } 108 // extern "C" { double log1p( double ); } 109 static inline long double log1p( long double x ) { return log1pl( x ); } 110 111 static inline int ilogb( float x ) { return ilogbf( x ); } 112 // extern "C" { int ilogb( double ); } 113 static inline int ilogb( long double x ) { return ilogbl( x ); } 114 115 static inline float logb( float x ) { return logbf( x ); } 116 // extern "C" { double logb( double ); } 117 static inline long double logb( long double x ) { return logbl( x ); } 118 119 static inline float sqrt( float x ) { return sqrtf( x ); } 120 // extern "C" { double sqrt( double ); } 121 static inline long double sqrt( long double x ) { return sqrtl( x ); } 122 static inline float _Complex sqrt( float _Complex x ) { return csqrtf( x ); } 123 static inline double _Complex sqrt( double _Complex x ) { return csqrt( x ); } 124 static inline long double _Complex sqrt( long double _Complex x ) { return csqrtl( x ); } 125 126 static inline float cbrt( float x ) { return cbrtf( x ); } 127 // extern "C" { double cbrt( double ); } 128 static inline long double cbrt( long double x ) { return cbrtl( x ); } 129 130 static inline float hypot( float x, float y ) { return hypotf( x, y ); } 131 // extern "C" { double hypot( double, double ); } 132 static inline long double hypot( long double x, long double y ) { return hypotl( x, y ); } 94 static inline { 95 float log( float x ) { return logf( x ); } 96 // extern "C" { double log( double ); } 97 long double log( long double x ) { return logl( x ); } 98 float _Complex log( float _Complex x ) { return clogf( x ); } 99 double _Complex log( double _Complex x ) { return clog( x ); } 100 long double _Complex log( long double _Complex x ) { return clogl( x ); } 101 102 float log2( float x ) { return log2f( x ); } 103 // extern "C" { double log2( double ); } 104 long double log2( long double x ) { return log2l( x ); } 105 // float _Complex log2( float _Complex x ) { return clog2f( x ); } 106 // double _Complex log2( double _Complex x ) { return clog2( x ); } 107 // long double _Complex log2( long double _Complex x ) { return clog2l( x ); } 108 109 float log10( float x ) { return log10f( x ); } 110 // extern "C" { double log10( double ); } 111 long double log10( long double x ) { return log10l( x ); } 112 // float _Complex log10( float _Complex x ) { return clog10f( x ); } 113 // double _Complex log10( double _Complex x ) { return clog10( x ); } 114 // long double _Complex log10( long double _Complex x ) { return clog10l( x ); } 115 116 float log1p( float x ) { return log1pf( x ); } 117 // extern "C" { double log1p( double ); } 118 long double log1p( long double x ) { return log1pl( x ); } 119 120 int ilogb( float x ) { return ilogbf( x ); } 121 // extern "C" { int ilogb( double ); } 122 int ilogb( long double x ) { return ilogbl( x ); } 123 124 float logb( float x ) { return logbf( x ); } 125 // extern "C" { double logb( double ); } 126 long double logb( long double x ) { return logbl( x ); } 127 128 float sqrt( float x ) { return sqrtf( x ); } 129 // extern "C" { double sqrt( double ); } 130 long double sqrt( long double x ) { return sqrtl( x ); } 131 float _Complex sqrt( float _Complex x ) { return csqrtf( x ); } 132 double _Complex sqrt( double _Complex x ) { return csqrt( x ); } 133 long double _Complex sqrt( long double _Complex x ) { return csqrtl( x ); } 134 135 float cbrt( float x ) { return cbrtf( x ); } 136 // extern "C" { double cbrt( double ); } 137 long double cbrt( long double x ) { return cbrtl( x ); } 138 139 float hypot( float x, float y ) { return hypotf( x, y ); } 140 // extern "C" { double hypot( double, double ); } 141 long double hypot( long double x, long double y ) { return hypotl( x, y ); } 142 } // distribution 133 143 134 144 //---------------------- Trigonometric ---------------------- 135 145 136 static inline float sin( float x ) { return sinf( x ); } 137 // extern "C" { double sin( double ); } 138 static inline long double sin( long double x ) { return sinl( x ); } 139 static inline float _Complex sin( float _Complex x ) { return csinf( x ); } 140 static inline double _Complex sin( double _Complex x ) { return csin( x ); } 141 static inline long double _Complex sin( long double _Complex x ) { return csinl( x ); } 142 143 static inline float cos( float x ) { return cosf( x ); } 144 // extern "C" { double cos( double ); } 145 static inline long double cos( long double x ) { return cosl( x ); } 146 static inline float _Complex cos( float _Complex x ) { return ccosf( x ); } 147 static inline double _Complex cos( double _Complex x ) { return ccos( x ); } 148 static inline long double _Complex cos( long double _Complex x ) { return ccosl( x ); } 149 150 static inline float tan( float x ) { return tanf( x ); } 151 // extern "C" { double tan( double ); } 152 static inline long double tan( long double x ) { return tanl( x ); } 153 static inline float _Complex tan( float _Complex x ) { return ctanf( x ); } 154 static inline double _Complex tan( double _Complex x ) { return ctan( x ); } 155 static inline long double _Complex tan( long double _Complex x ) { return ctanl( x ); } 156 157 static inline float asin( float x ) { return asinf( x ); } 158 // extern "C" { double asin( double ); } 159 static inline long double asin( long double x ) { return asinl( x ); } 160 static inline float _Complex asin( float _Complex x ) { return casinf( x ); } 161 static inline double _Complex asin( double _Complex x ) { return casin( x ); } 162 static inline long double _Complex asin( long double _Complex x ) { return casinl( x ); } 163 164 static inline float acos( float x ) { return acosf( x ); } 165 // extern "C" { double acos( double ); } 166 static inline long double acos( long double x ) { return acosl( x ); } 167 static inline float _Complex acos( float _Complex x ) { return cacosf( x ); } 168 static inline double _Complex acos( double _Complex x ) { return cacos( x ); } 169 static inline long double _Complex acos( long double _Complex x ) { return cacosl( x ); } 170 171 static inline float atan( float x ) { return atanf( x ); } 172 // extern "C" { double atan( double ); } 173 static inline long double atan( long double x ) { return atanl( x ); } 174 static inline float _Complex atan( float _Complex x ) { return catanf( x ); } 175 static inline double _Complex atan( double _Complex x ) { return catan( x ); } 176 static inline long double _Complex atan( long double _Complex x ) { return catanl( x ); } 177 178 static inline float atan2( float x, float y ) { return atan2f( x, y ); } 179 // extern "C" { double atan2( double, double ); } 180 static inline long double atan2( long double x, long double y ) { return atan2l( x, y ); } 181 182 // alternative name for atan2 183 static inline float atan( float x, float y ) { return atan2f( x, y ); } 184 static inline double atan( double x, double y ) { return atan2( x, y ); } 185 static inline long double atan( long double x, long double y ) { return atan2l( x, y ); } 146 static inline { 147 float sin( float x ) { return sinf( x ); } 148 // extern "C" { double sin( double ); } 149 long double sin( long double x ) { return sinl( x ); } 150 float _Complex sin( float _Complex x ) { return csinf( x ); } 151 double _Complex sin( double _Complex x ) { return csin( x ); } 152 long double _Complex sin( long double _Complex x ) { return csinl( x ); } 153 154 float cos( float x ) { return cosf( x ); } 155 // extern "C" { double cos( double ); } 156 long double cos( long double x ) { return cosl( x ); } 157 float _Complex cos( float _Complex x ) { return ccosf( x ); } 158 double _Complex cos( double _Complex x ) { return ccos( x ); } 159 long double _Complex cos( long double _Complex x ) { return ccosl( x ); } 160 161 float tan( float x ) { return tanf( x ); } 162 // extern "C" { double tan( double ); } 163 long double tan( long double x ) { return tanl( x ); } 164 float _Complex tan( float _Complex x ) { return ctanf( x ); } 165 double _Complex tan( double _Complex x ) { return ctan( x ); } 166 long double _Complex tan( long double _Complex x ) { return ctanl( x ); } 167 168 float asin( float x ) { return asinf( x ); } 169 // extern "C" { double asin( double ); } 170 long double asin( long double x ) { return asinl( x ); } 171 float _Complex asin( float _Complex x ) { return casinf( x ); } 172 double _Complex asin( double _Complex x ) { return casin( x ); } 173 long double _Complex asin( long double _Complex x ) { return casinl( x ); } 174 175 float acos( float x ) { return acosf( x ); } 176 // extern "C" { double acos( double ); } 177 long double acos( long double x ) { return acosl( x ); } 178 float _Complex acos( float _Complex x ) { return cacosf( x ); } 179 double _Complex acos( double _Complex x ) { return cacos( x ); } 180 long double _Complex acos( long double _Complex x ) { return cacosl( x ); } 181 182 float atan( float x ) { return atanf( x ); } 183 // extern "C" { double atan( double ); } 184 long double atan( long double x ) { return atanl( x ); } 185 float _Complex atan( float _Complex x ) { return catanf( x ); } 186 double _Complex atan( double _Complex x ) { return catan( x ); } 187 long double _Complex atan( long double _Complex x ) { return catanl( x ); } 188 189 float atan2( float x, float y ) { return atan2f( x, y ); } 190 // extern "C" { double atan2( double, double ); } 191 long double atan2( long double x, long double y ) { return atan2l( x, y ); } 192 193 // alternative name for atan2 194 float atan( float x, float y ) { return atan2f( x, y ); } 195 double atan( double x, double y ) { return atan2( x, y ); } 196 long double atan( long double x, long double y ) { return atan2l( x, y ); } 197 } // distribution 186 198 187 199 //---------------------- Hyperbolic ---------------------- 188 200 189 static inline float sinh( float x ) { return sinhf( x ); } 190 // extern "C" { double sinh( double ); } 191 static inline long double sinh( long double x ) { return sinhl( x ); } 192 static inline float _Complex sinh( float _Complex x ) { return csinhf( x ); } 193 static inline double _Complex sinh( double _Complex x ) { return csinh( x ); } 194 static inline long double _Complex sinh( long double _Complex x ) { return csinhl( x ); } 195 196 static inline float cosh( float x ) { return coshf( x ); } 197 // extern "C" { double cosh( double ); } 198 static inline long double cosh( long double x ) { return coshl( x ); } 199 static inline float _Complex cosh( float _Complex x ) { return ccoshf( x ); } 200 static inline double _Complex cosh( double _Complex x ) { return ccosh( x ); } 201 static inline long double _Complex cosh( long double _Complex x ) { return ccoshl( x ); } 202 203 static inline float tanh( float x ) { return tanhf( x ); } 204 // extern "C" { double tanh( double ); } 205 static inline long double tanh( long double x ) { return tanhl( x ); } 206 static inline float _Complex tanh( float _Complex x ) { return ctanhf( x ); } 207 static inline double _Complex tanh( double _Complex x ) { return ctanh( x ); } 208 static inline long double _Complex tanh( long double _Complex x ) { return ctanhl( x ); } 209 210 static inline float asinh( float x ) { return asinhf( x ); } 211 // extern "C" { double asinh( double ); } 212 static inline long double asinh( long double x ) { return asinhl( x ); } 213 static inline float _Complex asinh( float _Complex x ) { return casinhf( x ); } 214 static inline double _Complex asinh( double _Complex x ) { return casinh( x ); } 215 static inline long double _Complex asinh( long double _Complex x ) { return casinhl( x ); } 216 217 static inline float acosh( float x ) { return acoshf( x ); } 218 // extern "C" { double acosh( double ); } 219 static inline long double acosh( long double x ) { return acoshl( x ); } 220 static inline float _Complex acosh( float _Complex x ) { return cacoshf( x ); } 221 static inline double _Complex acosh( double _Complex x ) { return cacosh( x ); } 222 static inline long double _Complex acosh( long double _Complex x ) { return cacoshl( x ); } 223 224 static inline float atanh( float x ) { return atanhf( x ); } 225 // extern "C" { double atanh( double ); } 226 static inline long double atanh( long double x ) { return atanhl( x ); } 227 static inline float _Complex atanh( float _Complex x ) { return catanhf( x ); } 228 static inline double _Complex atanh( double _Complex x ) { return catanh( x ); } 229 static inline long double _Complex atanh( long double _Complex x ) { return catanhl( x ); } 201 static inline { 202 float sinh( float x ) { return sinhf( x ); } 203 // extern "C" { double sinh( double ); } 204 long double sinh( long double x ) { return sinhl( x ); } 205 float _Complex sinh( float _Complex x ) { return csinhf( x ); } 206 double _Complex sinh( double _Complex x ) { return csinh( x ); } 207 long double _Complex sinh( long double _Complex x ) { return csinhl( x ); } 208 209 float cosh( float x ) { return coshf( x ); } 210 // extern "C" { double cosh( double ); } 211 long double cosh( long double x ) { return coshl( x ); } 212 float _Complex cosh( float _Complex x ) { return ccoshf( x ); } 213 double _Complex cosh( double _Complex x ) { return ccosh( x ); } 214 long double _Complex cosh( long double _Complex x ) { return ccoshl( x ); } 215 216 float tanh( float x ) { return tanhf( x ); } 217 // extern "C" { double tanh( double ); } 218 long double tanh( long double x ) { return tanhl( x ); } 219 float _Complex tanh( float _Complex x ) { return ctanhf( x ); } 220 double _Complex tanh( double _Complex x ) { return ctanh( x ); } 221 long double _Complex tanh( long double _Complex x ) { return ctanhl( x ); } 222 223 float asinh( float x ) { return asinhf( x ); } 224 // extern "C" { double asinh( double ); } 225 long double asinh( long double x ) { return asinhl( x ); } 226 float _Complex asinh( float _Complex x ) { return casinhf( x ); } 227 double _Complex asinh( double _Complex x ) { return casinh( x ); } 228 long double _Complex asinh( long double _Complex x ) { return casinhl( x ); } 229 230 float acosh( float x ) { return acoshf( x ); } 231 // extern "C" { double acosh( double ); } 232 long double acosh( long double x ) { return acoshl( x ); } 233 float _Complex acosh( float _Complex x ) { return cacoshf( x ); } 234 double _Complex acosh( double _Complex x ) { return cacosh( x ); } 235 long double _Complex acosh( long double _Complex x ) { return cacoshl( x ); } 236 237 float atanh( float x ) { return atanhf( x ); } 238 // extern "C" { double atanh( double ); } 239 long double atanh( long double x ) { return atanhl( x ); } 240 float _Complex atanh( float _Complex x ) { return catanhf( x ); } 241 double _Complex atanh( double _Complex x ) { return catanh( x ); } 242 long double _Complex atanh( long double _Complex x ) { return catanhl( x ); } 243 } // distribution 230 244 231 245 //---------------------- Error / Gamma ---------------------- 232 246 233 static inline float erf( float x ) { return erff( x ); } 234 // extern "C" { double erf( double ); } 235 static inline long double erf( long double x ) { return erfl( x ); } 236 // float _Complex erf( float _Complex ); 237 // double _Complex erf( double _Complex ); 238 // long double _Complex erf( long double _Complex ); 239 240 static inline float erfc( float x ) { return erfcf( x ); } 241 // extern "C" { double erfc( double ); } 242 static inline long double erfc( long double x ) { return erfcl( x ); } 243 // float _Complex erfc( float _Complex ); 244 // double _Complex erfc( double _Complex ); 245 // long double _Complex erfc( long double _Complex ); 246 247 static inline float lgamma( float x ) { return lgammaf( x ); } 248 // extern "C" { double lgamma( double ); } 249 static inline long double lgamma( long double x ) { return lgammal( x ); } 250 static inline float lgamma( float x, int * sign ) { return lgammaf_r( x, sign ); } 251 static inline double lgamma( double x, int * sign ) { return lgamma_r( x, sign ); } 252 static inline long double lgamma( long double x, int * sign ) { return lgammal_r( x, sign ); } 253 254 static inline float tgamma( float x ) { return tgammaf( x ); } 255 // extern "C" { double tgamma( double ); } 256 static inline long double tgamma( long double x ) { return tgammal( x ); } 247 static inline { 248 float erf( float x ) { return erff( x ); } 249 // extern "C" { double erf( double ); } 250 long double erf( long double x ) { return erfl( x ); } 251 // float _Complex erf( float _Complex ); 252 // double _Complex erf( double _Complex ); 253 // long double _Complex erf( long double _Complex ); 254 255 float erfc( float x ) { return erfcf( x ); } 256 // extern "C" { double erfc( double ); } 257 long double erfc( long double x ) { return erfcl( x ); } 258 // float _Complex erfc( float _Complex ); 259 // double _Complex erfc( double _Complex ); 260 // long double _Complex erfc( long double _Complex ); 261 262 float lgamma( float x ) { return lgammaf( x ); } 263 // extern "C" { double lgamma( double ); } 264 long double lgamma( long double x ) { return lgammal( x ); } 265 float lgamma( float x, int * sign ) { return lgammaf_r( x, sign ); } 266 double lgamma( double x, int * sign ) { return lgamma_r( x, sign ); } 267 long double lgamma( long double x, int * sign ) { return lgammal_r( x, sign ); } 268 269 float tgamma( float x ) { return tgammaf( x ); } 270 // extern "C" { double tgamma( double ); } 271 long double tgamma( long double x ) { return tgammal( x ); } 272 } // distribution 257 273 258 274 //---------------------- Nearest Integer ---------------------- 259 275 260 static inline float floor( float x ) { return floorf( x ); } 261 // extern "C" { double floor( double ); } 262 static inline long double floor( long double x ) { return floorl( x ); } 263 264 static inline float ceil( float x ) { return ceilf( x ); } 265 // extern "C" { double ceil( double ); } 266 static inline long double ceil( long double x ) { return ceill( x ); } 267 268 static inline float trunc( float x ) { return truncf( x ); } 269 // extern "C" { double trunc( double ); } 270 static inline long double trunc( long double x ) { return truncl( x ); } 271 272 static inline float rint( float x ) { return rintf( x ); } 273 // extern "C" { double rint( double x ); } 274 static inline long double rint( long double x ) { return rintl( x ); } 275 static inline long int rint( float x ) { return lrintf( x ); } 276 static inline long int rint( double x ) { return lrint( x ); } 277 static inline long int rint( long double x ) { return lrintl( x ); } 278 static inline long long int rint( float x ) { return llrintf( x ); } 279 static inline long long int rint( double x ) { return llrint( x ); } 280 static inline long long int rint( long double x ) { return llrintl( x ); } 281 282 static inline long int lrint( float x ) { return lrintf( x ); } 283 // extern "C" { long int lrint( double ); } 284 static inline long int lrint( long double x ) { return lrintl( x ); } 285 static inline long long int llrint( float x ) { return llrintf( x ); } 286 // extern "C" { long long int llrint( double ); } 287 static inline long long int llrint( long double x ) { return llrintl( x ); } 288 289 static inline float nearbyint( float x ) { return nearbyintf( x ); } 290 // extern "C" { double nearbyint( double ); } 291 static inline long double nearbyint( long double x ) { return nearbyintl( x ); } 292 293 static inline float round( float x ) { return roundf( x ); } 294 // extern "C" { double round( double x ); } 295 static inline long double round( long double x ) { return roundl( x ); } 296 static inline long int round( float x ) { return lroundf( x ); } 297 static inline long int round( double x ) { return lround( x ); } 298 static inline long int round( long double x ) { return lroundl( x ); } 299 static inline long long int round( float x ) { return llroundf( x ); } 300 static inline long long int round( double x ) { return llround( x ); } 301 static inline long long int round( long double x ) { return llroundl( x ); } 302 303 static inline long int lround( float x ) { return lroundf( x ); } 304 // extern "C" { long int lround( double ); } 305 static inline long int lround( long double x ) { return lroundl( x ); } 306 static inline long long int llround( float x ) { return llroundf( x ); } 307 // extern "C" { long long int llround( double ); } 308 static inline long long int llround( long double x ) { return llroundl( x ); } 276 static inline { 277 signed char floor( signed char n, signed char align ) { return n / align * align; } 278 unsigned char floor( unsigned char n, unsigned char align ) { return n / align * align; } 279 short int floor( short int n, short int align ) { return n / align * align; } 280 unsigned short int floor( unsigned short int n, unsigned short int align ) { return n / align * align; } 281 int floor( int n, int align ) { return n / align * align; } 282 unsigned int floor( unsigned int n, unsigned int align ) { return n / align * align; } 283 long int floor( long int n, long int align ) { return n / align * align; } 284 unsigned long int floor( unsigned long int n, unsigned long int align ) { return n / align * align; } 285 long long int floor( long long int n, long long int align ) { return n / align * align; } 286 unsigned long long int floor( unsigned long long int n, unsigned long long int align ) { return n / align * align; } 287 288 // forall( otype T | { T ?/?( T, T ); T ?*?( T, T ); } ) 289 // T floor( T n, T align ) { return n / align * align; } 290 291 signed char ceiling_div( signed char n, char align ) { return (n + (align - 1)) / align; } 292 unsigned char ceiling_div( unsigned char n, unsigned char align ) { return (n + (align - 1)) / align; } 293 short int ceiling_div( short int n, short int align ) { return (n + (align - 1)) / align; } 294 unsigned short int ceiling_div( unsigned short int n, unsigned short int align ) { return (n + (align - 1)) / align; } 295 int ceiling_div( int n, int align ) { return (n + (align - 1)) / align; } 296 unsigned int ceiling_div( unsigned int n, unsigned int align ) { return (n + (align - 1)) / align; } 297 long int ceiling_div( long int n, long int align ) { return (n + (align - 1)) / align; } 298 unsigned long int ceiling_div( unsigned long int n, unsigned long int align ) { return (n + (align - 1)) / align; } 299 long long int ceiling_div( long long int n, long long int align ) { return (n + (align - 1)) / align; } 300 unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align ) { return (n + (align - 1)) / align; } 301 302 // forall( otype T | { T ?+?( T, T ); T ?-?( T, T ); T ?%?( T, T ); } ) 303 // T ceiling_div( T n, T align ) { verify( is_pow2( align ) );return (n + (align - 1)) / align; } 304 305 // gcc notices the div/mod pair and saves both so only one div. 306 signed char ceiling( signed char n, signed char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 307 unsigned char ceiling( unsigned char n, unsigned char align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 308 short int ceiling( short int n, short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 309 unsigned short int ceiling( unsigned short int n, unsigned short int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 310 int ceiling( int n, int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 311 unsigned int ceiling( unsigned int n, unsigned int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 312 long int ceiling( long int n, long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 313 unsigned long int ceiling( unsigned long int n, unsigned long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0) , align); } 314 long long int ceiling( long long int n, long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 315 unsigned long long int ceiling( unsigned long long int n, unsigned long long int align ) { return floor( n + (n % align != 0 ? align - 1 : 0), align ); } 316 317 // forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T ); T ?/?( T, T ); } ) 318 // T ceiling( T n, T align ) { return return floor( n + (n % align != 0 ? align - 1 : 0), align ); *} 319 320 float floor( float x ) { return floorf( x ); } 321 // extern "C" { double floor( double ); } 322 long double floor( long double x ) { return floorl( x ); } 323 324 float ceil( float x ) { return ceilf( x ); } 325 // extern "C" { double ceil( double ); } 326 long double ceil( long double x ) { return ceill( x ); } 327 328 float trunc( float x ) { return truncf( x ); } 329 // extern "C" { double trunc( double ); } 330 long double trunc( long double x ) { return truncl( x ); } 331 332 float rint( float x ) { return rintf( x ); } 333 // extern "C" { double rint( double x ); } 334 long double rint( long double x ) { return rintl( x ); } 335 long int rint( float x ) { return lrintf( x ); } 336 long int rint( double x ) { return lrint( x ); } 337 long int rint( long double x ) { return lrintl( x ); } 338 long long int rint( float x ) { return llrintf( x ); } 339 long long int rint( double x ) { return llrint( x ); } 340 long long int rint( long double x ) { return llrintl( x ); } 341 342 long int lrint( float x ) { return lrintf( x ); } 343 // extern "C" { long int lrint( double ); } 344 long int lrint( long double x ) { return lrintl( x ); } 345 long long int llrint( float x ) { return llrintf( x ); } 346 // extern "C" { long long int llrint( double ); } 347 long long int llrint( long double x ) { return llrintl( x ); } 348 349 float nearbyint( float x ) { return nearbyintf( x ); } 350 // extern "C" { double nearbyint( double ); } 351 long double nearbyint( long double x ) { return nearbyintl( x ); } 352 353 float round( float x ) { return roundf( x ); } 354 // extern "C" { double round( double x ); } 355 long double round( long double x ) { return roundl( x ); } 356 long int round( float x ) { return lroundf( x ); } 357 long int round( double x ) { return lround( x ); } 358 long int round( long double x ) { return lroundl( x ); } 359 long long int round( float x ) { return llroundf( x ); } 360 long long int round( double x ) { return llround( x ); } 361 long long int round( long double x ) { return llroundl( x ); } 362 363 long int lround( float x ) { return lroundf( x ); } 364 // extern "C" { long int lround( double ); } 365 long int lround( long double x ) { return lroundl( x ); } 366 long long int llround( float x ) { return llroundf( x ); } 367 // extern "C" { long long int llround( double ); } 368 long long int llround( long double x ) { return llroundl( x ); } 369 } // distribution 309 370 310 371 //---------------------- Manipulation ---------------------- 311 372 312 static inline float copysign( float x, float y ) { return copysignf( x, y ); } 313 // extern "C" { double copysign( double, double ); } 314 static inline long double copysign( long double x, long double y ) { return copysignl( x, y ); } 315 316 static inline float frexp( float x, int * ip ) { return frexpf( x, ip ); } 317 // extern "C" { double frexp( double, int * ); } 318 static inline long double frexp( long double x, int * ip ) { return frexpl( x, ip ); } 319 320 static inline float ldexp( float x, int exp2 ) { return ldexpf( x, exp2 ); } 321 // extern "C" { double ldexp( double, int ); } 322 static inline long double ldexp( long double x, int exp2 ) { return ldexpl( x, exp2 ); } 323 324 static inline [ float, float ] modf( float x ) { float i; x = modff( x, &i ); return [ i, x ]; } 325 static inline float modf( float x, float * i ) { return modff( x, i ); } 326 static inline [ double, double ] modf( double x ) { double i; x = modf( x, &i ); return [ i, x ]; } 327 // extern "C" { double modf( double, double * ); } 328 static inline [ long double, long double ] modf( long double x ) { long double i; x = modfl( x, &i ); return [ i, x ]; } 329 static inline long double modf( long double x, long double * i ) { return modfl( x, i ); } 330 331 static inline float nextafter( float x, float y ) { return nextafterf( x, y ); } 332 // extern "C" { double nextafter( double, double ); } 333 static inline long double nextafter( long double x, long double y ) { return nextafterl( x, y ); } 334 335 static inline float nexttoward( float x, long double y ) { return nexttowardf( x, y ); } 336 // extern "C" { double nexttoward( double, long double ); } 337 static inline long double nexttoward( long double x, long double y ) { return nexttowardl( x, y ); } 338 339 static inline float scalbn( float x, int exp ) { return scalbnf( x, exp ); } 340 // extern "C" { double scalbn( double, int ); } 341 static inline long double scalbn( long double x, int exp ) { return scalbnl( x, exp ); } 342 static inline float scalbn( float x, long int exp ) { return scalblnf( x, exp ); } 343 static inline double scalbn( double x, long int exp ) { return scalbln( x, exp ); } 344 static inline long double scalbn( long double x, long int exp ) { return scalblnl( x, exp ); } 345 346 static inline float scalbln( float x, long int exp ) { return scalblnf( x, exp ); } 347 // extern "C" { double scalbln( double, long int ); } 348 static inline long double scalbln( long double x, long int exp ) { return scalblnl( x, exp ); } 373 static inline { 374 float copysign( float x, float y ) { return copysignf( x, y ); } 375 // extern "C" { double copysign( double, double ); } 376 long double copysign( long double x, long double y ) { return copysignl( x, y ); } 377 378 float frexp( float x, int * ip ) { return frexpf( x, ip ); } 379 // extern "C" { double frexp( double, int * ); } 380 long double frexp( long double x, int * ip ) { return frexpl( x, ip ); } 381 382 float ldexp( float x, int exp2 ) { return ldexpf( x, exp2 ); } 383 // extern "C" { double ldexp( double, int ); } 384 long double ldexp( long double x, int exp2 ) { return ldexpl( x, exp2 ); } 385 386 [ float, float ] modf( float x ) { float i; x = modff( x, &i ); return [ i, x ]; } 387 float modf( float x, float * i ) { return modff( x, i ); } 388 [ double, double ] modf( double x ) { double i; x = modf( x, &i ); return [ i, x ]; } 389 // extern "C" { double modf( double, double * ); } 390 [ long double, long double ] modf( long double x ) { long double i; x = modfl( x, &i ); return [ i, x ]; } 391 long double modf( long double x, long double * i ) { return modfl( x, i ); } 392 393 float nextafter( float x, float y ) { return nextafterf( x, y ); } 394 // extern "C" { double nextafter( double, double ); } 395 long double nextafter( long double x, long double y ) { return nextafterl( x, y ); } 396 397 float nexttoward( float x, long double y ) { return nexttowardf( x, y ); } 398 // extern "C" { double nexttoward( double, long double ); } 399 long double nexttoward( long double x, long double y ) { return nexttowardl( x, y ); } 400 401 float scalbn( float x, int exp ) { return scalbnf( x, exp ); } 402 // extern "C" { double scalbn( double, int ); } 403 long double scalbn( long double x, int exp ) { return scalbnl( x, exp ); } 404 float scalbn( float x, long int exp ) { return scalblnf( x, exp ); } 405 double scalbn( double x, long int exp ) { return scalbln( x, exp ); } 406 long double scalbn( long double x, long int exp ) { return scalblnl( x, exp ); } 407 408 float scalbln( float x, long int exp ) { return scalblnf( x, exp ); } 409 // extern "C" { double scalbln( double, long int ); } 410 long double scalbln( long double x, long int exp ) { return scalblnl( x, exp ); } 411 } // distribution 349 412 350 413 //--------------------------------------- 351 414 352 #include "common.hfa" 353 354 //--------------------------------------- 355 356 forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } ) 357 T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; } 358 359 forall( otype T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } ) 360 T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; } 361 362 forall( otype T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } ) 363 T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); } 415 static inline { 416 forall( otype T | { void ?{}( T &, one_t ); T ?+?( T, T ); T ?-?( T, T );T ?*?( T, T ); } ) 417 T lerp( T x, T y, T a ) { return x * ((T){1} - a) + y * a; } 418 419 forall( otype T | { void ?{}( T &, zero_t ); void ?{}( T &, one_t ); int ?<?( T, T ); } ) 420 T step( T edge, T x ) { return x < edge ? (T){0} : (T){1}; } 421 422 forall( otype T | { void ?{}( T &, int ); T clamp( T, T, T ); T ?-?( T, T ); T ?*?( T, T ); T ?/?( T, T ); } ) 423 T smoothstep( T edge0, T edge1, T x ) { T t = clamp( (x - edge0) / (edge1 - edge0), (T){0}, (T){1} ); return t * t * ((T){3} - (T){2} * t); } 424 } // distribution 364 425 365 426 // Local Variables: // -
libcfa/src/rational.cfa
rbdfc032 reef8dfb 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 12 18:12:08 201913 // Update Count : 18 412 // Last Modified On : Sat Feb 8 17:56:36 2020 13 // Update Count : 187 14 14 // 15 15 … … 56 56 } // rational 57 57 58 void ?{}( Rational(RationalImpl) & r, zero_t ) { 59 r{ (RationalImpl){0}, (RationalImpl){1} }; 60 } // rational 61 62 void ?{}( Rational(RationalImpl) & r, one_t ) { 63 r{ (RationalImpl){1}, (RationalImpl){1} }; 64 } // rational 58 65 59 66 // getter for numerator/denominator -
libcfa/src/startup.cfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Jul 24 16:21:57 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 13:16:45 201913 // Update Count : 2912 // Last Modified On : Tue Feb 4 13:03:18 2020 13 // Update Count : 30 14 14 // 15 15 16 #include <time.h> // tzset 16 #include <time.h> // tzset 17 #include <locale.h> // setlocale 17 18 #include "startup.hfa" 18 19 … … 21 22 void __cfaabi_appready_startup( void ) { 22 23 tzset(); // initialize time global variables 24 setlocale(LC_NUMERIC, ""); 23 25 #ifdef __CFA_DEBUG__ 24 26 extern void heapAppStart(); … … 41 43 struct __spinlock_t; 42 44 extern "C" { 43 void __cfaabi_dbg_record (struct __spinlock_t & this, const char * prev_name) __attribute__(( weak )) {}45 void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {} 44 46 } 45 47 -
libcfa/src/stdhdr/assert.h
rbdfc032 reef8dfb 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jul 31 23:09:32 201713 // Update Count : 1 312 // Last Modified On : Tue Feb 4 12:58:49 2020 13 // Update Count : 15 14 14 // 15 15 … … 27 27 #define assertf( expr, fmt, ... ) ((expr) ? ((void)0) : __assert_fail_f(__VSTRINGIFY__(expr), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ## __VA_ARGS__ )) 28 28 29 void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) __attribute__((noreturn, format( printf, 5, 6) ));29 void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) __attribute__((noreturn, format( printf, 5, 6) )); 30 30 #endif 31 31 … … 33 33 #define verify(x) assert(x) 34 34 #define verifyf(x, ...) assertf(x, __VA_ARGS__) 35 #define verifyfail(...) 35 36 #define __CFA_WITH_VERIFY__ 36 37 #else 37 38 #define verify(x) 38 39 #define verifyf(x, ...) 40 #define verifyfail(...) 39 41 #endif 40 42 -
libcfa/src/stdhdr/bfdlink.h
rbdfc032 reef8dfb 10 10 // Created On : Tue Jul 18 07:26:04 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 1 07:15:29202013 // Update Count : 512 // Last Modified On : Fri Feb 7 19:05:08 2020 13 // Update Count : 6 14 14 // 15 15 16 16 // include file uses the CFA keyword "with". 17 17 #if ! defined( with ) // nesting ? 18 #define with ``with ``// make keyword an identifier18 #define with ``with // make keyword an identifier 19 19 #define __CFA_BFDLINK_H__ 20 20 #endif -
libcfa/src/stdhdr/hwloc.h
rbdfc032 reef8dfb 10 10 // Created On : Tue Jul 18 07:45:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 1 07:15:39202013 // Update Count : 512 // Last Modified On : Fri Feb 7 19:05:18 2020 13 // Update Count : 6 14 14 // 15 15 16 16 // include file uses the CFA keyword "thread". 17 17 #if ! defined( thread ) // nesting ? 18 #define thread ``thread ``// make keyword an identifier18 #define thread ``thread // make keyword an identifier 19 19 #define __CFA_HWLOC_H__ 20 20 #endif -
libcfa/src/stdhdr/krb5.h
rbdfc032 reef8dfb 10 10 // Created On : Tue Jul 18 07:55:44 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 1 07:15:47202013 // Update Count : 512 // Last Modified On : Fri Feb 7 19:05:35 2020 13 // Update Count : 6 14 14 // 15 15 16 16 // include file uses the CFA keyword "enable". 17 17 #if ! defined( enable ) // nesting ? 18 #define enable ``enable ``// make keyword an identifier18 #define enable ``enable // make keyword an identifier 19 19 #define __CFA_KRB5_H__ 20 20 #endif -
libcfa/src/stdhdr/malloc.h
rbdfc032 reef8dfb 10 10 // Created On : Thu Jul 20 15:58:16 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 11 09:06:31 201813 // Update Count : 1 012 // Last Modified On : Wed May 27 14:13:14 2020 13 // Update Count : 18 14 14 // 15 16 17 size_t default_mmap_start(); // CFA extras18 size_t default_heap_expansion();19 20 bool traceHeap();21 bool traceHeapOn();22 bool traceHeapOff();23 24 bool traceHeapTerm();25 bool traceHeapTermOn();26 bool traceHeapTermOff();27 28 bool checkFree();29 bool checkFreeOn();30 bool checkFreeOff();31 32 extern "C" {33 size_t malloc_alignment( void * );34 bool malloc_zero_fill( void * );35 int malloc_stats_fd( int fd );36 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );37 } // extern "C"38 15 39 16 extern "C" { 40 17 #include_next <malloc.h> // has internal check for multiple expansion 41 18 } // extern "C" 19 20 #include <heap.hfa> 42 21 43 22 // Local Variables: // -
libcfa/src/stdhdr/math.h
rbdfc032 reef8dfb 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 1 07:15:58202013 // Update Count : 1 412 // Last Modified On : Fri Feb 7 19:05:27 2020 13 // Update Count : 15 14 14 // 15 15 16 16 extern "C" { 17 17 #if ! defined( exception ) // nesting ? 18 #define exception ``exception ``// make keyword an identifier18 #define exception ``exception // make keyword an identifier 19 19 #define __CFA_MATH_H__ 20 20 #endif -
libcfa/src/stdlib.cfa
rbdfc032 reef8dfb 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 20 17:22:47 201913 // Update Count : 48512 // Last Modified On : Thu Nov 12 07:46:09 2020 13 // Update Count : 503 14 14 // 15 15 … … 20 20 #define _XOPEN_SOURCE 600 // posix_memalign, *rand48 21 21 #include <string.h> // memcpy, memset 22 #include <malloc.h> // malloc_usable_size23 22 //#include <math.h> // fabsf, fabs, fabsl 24 23 #include <complex.h> // _Complex_I … … 27 26 //--------------------------------------- 28 27 29 forall( dtype T | sized(T) ) { 30 T * alloc_set( T ptr[], size_t dim, char fill ) { // realloc array with fill 31 size_t olen = malloc_usable_size( ptr ); // current allocation 32 void * nptr = (void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 33 size_t nlen = malloc_usable_size( nptr ); // new allocation 34 if ( nlen > olen ) { // larger ? 35 memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage 36 } // if 37 return (T *)nptr; 38 } // alloc_set 39 40 T * alloc_align_set( T ptr[], size_t align, char fill ) { // aligned realloc with fill 41 size_t olen = malloc_usable_size( ptr ); // current allocation 42 void * nptr = (void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 43 // char * nptr = alloc_align( ptr, align ); 44 size_t nlen = malloc_usable_size( nptr ); // new allocation 45 if ( nlen > olen ) { // larger ? 46 memset( (char *)nptr + olen, (int)fill, nlen - olen ); // initialize added storage 47 } // if 48 return (T *)nptr; 49 } // alloc_align_set 50 } // distribution 51 52 // allocation/deallocation and constructor/destructor, non-array types 53 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) 54 T * new( Params p ) { 55 return &(*malloc()){ p }; // run constructor 56 } // new 57 58 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) 59 void delete( T * ptr ) { 60 if ( ptr ) { // ignore null 61 ^(*ptr){}; // run destructor 62 free( ptr ); 63 } // if 64 } // delete 65 66 forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } ) 67 void delete( T * ptr, Params rest ) { 68 if ( ptr ) { // ignore null 69 ^(*ptr){}; // run destructor 70 free( ptr ); 71 } // if 72 delete( rest ); 73 } // delete 74 75 76 // allocation/deallocation and constructor/destructor, array types 77 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) 78 T * anew( size_t dim, Params p ) { 28 // Cforall allocation/deallocation and constructor/destructor, array types 29 30 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) 31 T * anew( size_t dim, TT p ) { 79 32 T * arr = alloc( dim ); 80 33 for ( unsigned int i = 0; i < dim; i += 1 ) { … … 85 38 86 39 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) 87 void adelete( size_t dim,T arr[] ) {40 void adelete( T arr[] ) { 88 41 if ( arr ) { // ignore null 42 size_t dim = malloc_size( arr ) / sizeof( T ); 89 43 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 90 44 ^(arr[i]){}; // run destructor … … 94 48 } // adelete 95 49 96 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params); } )97 void adelete( size_t dim, T arr[], Paramsrest ) {50 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } ) 51 void adelete( T arr[], TT rest ) { 98 52 if ( arr ) { // ignore null 53 size_t dim = malloc_size( arr ) / sizeof( T ); 99 54 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 100 55 ^(arr[i]){}; // run destructor … … 107 62 //--------------------------------------- 108 63 109 float _Complex strto( const char * sptr, char ** eptr ) {64 float _Complex strto( const char sptr[], char ** eptr ) { 110 65 float re, im; 111 66 char * eeptr; … … 118 73 } // strto 119 74 120 double _Complex strto( const char * sptr, char ** eptr ) {75 double _Complex strto( const char sptr[], char ** eptr ) { 121 76 double re, im; 122 77 char * eeptr; … … 129 84 } // strto 130 85 131 long double _Complex strto( const char * sptr, char ** eptr ) {86 long double _Complex strto( const char sptr[], char ** eptr ) { 132 87 long double re, im; 133 88 char * eeptr; … … 255 210 extern "C" { // override C version 256 211 void srandom( unsigned int seed ) { srand48( (long int)seed ); } 257 long int random( void ) { return mrand48(); } 212 long int random( void ) { return mrand48(); } // GENERATES POSITIVE AND NEGATIVE VALUES 258 213 } // extern "C" 259 214 -
libcfa/src/stdlib.hfa
rbdfc032 reef8dfb 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 29 23:08:02 201913 // Update Count : 40012 // Last Modified On : Sat Dec 12 13:52:34 2020 13 // Update Count : 536 14 14 // 15 15 16 16 #pragma once 17 17 18 #include "bits/defs.hfa" 19 #include "bits/align.hfa" 18 #include "bits/defs.hfa" // OPTIONAL_THREAD 19 #include "bits/align.hfa" // libAlign 20 20 21 21 #include <stdlib.h> // *alloc, strto*, ato* 22 22 #include <heap.hfa> 23 24 // Reduce includes by explicitly defining these routines. 23 25 extern "C" { 24 void * memalign( size_t align, size_t size ); // malloc.h 26 void * memalign( size_t alignment, size_t size ); // malloc.h 27 void * pvalloc( size_t size ); // malloc.h 25 28 void * memset( void * dest, int fill, size_t size ); // string.h 26 29 void * memcpy( void * dest, const void * src, size_t size ); // string.h 27 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ); // CFA heap28 30 } // extern "C" 29 30 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap31 31 32 32 //--------------------------------------- … … 39 39 //--------------------------------------- 40 40 41 #include "common.hfa" 42 43 //--------------------------------------- 44 45 // Macro because of returns 46 #define $ARRAY_ALLOC( allocation, alignment, dim ) \ 47 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \ 48 else return (T *)alignment( _Alignof(T), dim, sizeof(T) ) 49 41 50 static inline forall( dtype T | sized(T) ) { 42 // C dynamic allocation51 // CFA safe equivalents, i.e., implicit size specification 43 52 44 53 T * malloc( void ) { 45 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc54 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( (size_t)sizeof(T) ); // C allocation 46 55 else return (T *)memalign( _Alignof(T), sizeof(T) ); 47 56 } // malloc 48 57 58 T * aalloc( size_t dim ) { 59 $ARRAY_ALLOC( aalloc, amemalign, dim ); 60 } // aalloc 61 49 62 T * calloc( size_t dim ) { 50 if ( _Alignof(T) <= libAlign() )return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc 51 else return (T *)cmemalign( _Alignof(T), dim, sizeof(T) ); 63 $ARRAY_ALLOC( calloc, cmemalign, dim ); 52 64 } // calloc 53 65 66 T * resize( T * ptr, size_t size ) { // CFA resize, eliminate return-type cast 67 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)resize( (void *)ptr, size ); // CFA resize 68 else return (T *)(void *)resize( (void *)ptr, _Alignof(T), size ); // CFA resize 69 } // resize 70 54 71 T * realloc( T * ptr, size_t size ) { // CFA realloc, eliminate return-type cast 55 return (T *)(void *)realloc( (void *)ptr, size ); // C realloc 72 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)realloc( (void *)ptr, size ); // C realloc 73 else return (T *)(void *)realloc( (void *)ptr, _Alignof(T), size ); // CFA realloc 56 74 } // realloc 57 75 … … 60 78 } // memalign 61 79 80 T * amemalign( size_t align, size_t dim ) { 81 return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign 82 } // amemalign 83 62 84 T * cmemalign( size_t align, size_t dim ) { 63 85 return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign … … 72 94 } // posix_memalign 73 95 74 // Cforall dynamic allocation 75 76 T * alloc( void ) { 77 return malloc(); 78 } // alloc 79 80 T * alloc( size_t dim ) { 81 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)malloc( dim * (size_t)sizeof(T) ); 82 else return (T *)memalign( _Alignof(T), dim * sizeof(T) ); 83 } // alloc 84 85 T * alloc( T ptr[], size_t dim ) { // realloc 86 return (T *)(void *)realloc( (void *)ptr, dim * sizeof(T) ); // C realloc 87 } // alloc 88 89 T * alloc_set( char fill ) { 90 return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value 91 } // alloc 92 93 T * alloc_set( T fill ) { 94 return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value 95 } // alloc 96 97 T * alloc_set( size_t dim, char fill ) { 98 return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value 99 } // alloc 100 101 T * alloc_set( size_t dim, T fill ) { 102 T * r = (T *)alloc( dim ); 103 for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value 104 return r; 105 } // alloc 106 107 T * alloc_set( size_t dim, const T fill[] ) { 108 return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value 109 } // alloc 110 } // distribution 111 112 forall( dtype T | sized(T) ) { 113 T * alloc_set( T ptr[], size_t dim, char fill ); // realloc array with fill 114 } // distribution 96 T * valloc( void ) { 97 return (T *)valloc( sizeof(T) ); // C valloc 98 } // valloc 99 100 T * pvalloc( void ) { 101 return (T *)pvalloc( sizeof(T) ); // C pvalloc 102 } // pvalloc 103 } // distribution 104 105 /* 106 FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal. 107 Or, just follow the instructions below for that. 108 109 1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following: 110 forall( dtype T | sized(T) ) { 111 union U_fill { char c; T * a; T t; }; 112 struct S_fill { char tag; U_fill(T) fill; }; 113 struct S_realloc { inline T *; }; 114 } 115 116 2. Replace all current postfix-fill functions with following for updated S_fill: 117 S_fill(T) ?`fill( char a ) { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; } 118 S_fill(T) ?`fill( T a ) { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; } 119 S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; } 120 121 3. Replace the $alloc_internal function which is outside ttype forall-block with following function: 122 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) { 123 T * ptr = NULL; 124 size_t size = sizeof(T); 125 size_t copy_end = 0; 126 127 if(Resize) { 128 ptr = (T*) (void *) resize( (int *)Resize, Align, Dim * size ); 129 } else if (Realloc) { 130 if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size); 131 ptr = (T*) (void *) realloc( (int *)Realloc, Align, Dim * size ); 132 } else { 133 ptr = (T*) (void *) memalign( Align, Dim * size ); 134 } 135 136 if(Fill.tag == 'c') { 137 memset( (char *)ptr + copy_end, (int)Fill.fill.c, Dim * size - copy_end ); 138 } else if(Fill.tag == 't') { 139 for ( int i = copy_end; i <= Dim * size - size ; i += size ) { 140 memcpy( (char *)ptr + i, &Fill.fill.t, size ); 141 } 142 } else if(Fill.tag == 'a') { 143 memcpy( (char *)ptr + copy_end, Fill.fill.a, min(Dim * size - copy_end, size * Fill.nmemb) ); 144 } 145 146 return ptr; 147 } // $alloc_internal 148 */ 149 150 typedef struct S_align { inline size_t; } T_align; 151 typedef struct S_resize { inline void *; } T_resize; 152 153 forall( dtype T ) { 154 struct S_fill { char tag; char c; size_t size; T * at; char t[50]; }; 155 struct S_realloc { inline T *; }; 156 } 157 158 static inline T_align ?`align ( size_t a ) { return (T_align){a}; } 159 static inline T_resize ?`resize ( void * a ) { return (T_resize){a}; } 115 160 116 161 static inline forall( dtype T | sized(T) ) { 117 T * alloc_align( size_t align ) { 118 return (T *)memalign( align, sizeof(T) ); 119 } // alloc_align 120 121 T * alloc_align( size_t align, size_t dim ) { 122 return (T *)memalign( align, dim * sizeof(T) ); 123 } // alloc_align 124 125 T * alloc_align( T ptr[], size_t align ) { // aligned realloc array 126 return (T *)(void *)realloc( (void *)ptr, align, sizeof(T) ); // CFA realloc 127 } // alloc_align 128 129 T * alloc_align( T ptr[], size_t align, size_t dim ) { // aligned realloc array 130 return (T *)(void *)realloc( (void *)ptr, align, dim * sizeof(T) ); // CFA realloc 131 } // alloc_align 132 133 T * alloc_align_set( size_t align, char fill ) { 134 return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value 135 } // alloc_align 136 137 T * alloc_align_set( size_t align, T fill ) { 138 return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value 139 } // alloc_align 140 141 T * alloc_align_set( size_t align, size_t dim, char fill ) { 142 return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value 143 } // alloc_align 144 145 T * alloc_align_set( size_t align, size_t dim, T fill ) { 146 T * r = (T *)alloc_align( align, dim ); 147 for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value 148 return r; 149 } // alloc_align 150 151 T * alloc_align_set( size_t align, size_t dim, const T fill[] ) { 152 return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) ); 153 } // alloc_align 154 } // distribution 155 156 forall( dtype T | sized(T) ) { 157 T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); // aligned realloc array with fill 158 } // distribution 162 S_fill(T) ?`fill ( T t ) { 163 S_fill(T) ret = { 't' }; 164 size_t size = sizeof(T); 165 if(size > sizeof(ret.t)) { printf("ERROR: const object of size greater than 50 bytes given for dynamic memory fill\n"); exit(1); } 166 memcpy( &ret.t, &t, size ); 167 return ret; 168 } 169 S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c }; } 170 S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } 171 S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; } 172 173 S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; } 174 175 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) { 176 T * ptr = NULL; 177 size_t size = sizeof(T); 178 size_t copy_end = 0; 179 180 if ( Resize ) { 181 ptr = (T*) (void *) resize( (void *)Resize, Align, Dim * size ); 182 } else if ( Realloc ) { 183 if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size); 184 ptr = (T*) (void *) realloc( (void *)Realloc, Align, Dim * size ); 185 } else { 186 ptr = (T*) (void *) memalign( Align, Dim * size ); 187 } 188 189 if(Fill.tag == 'c') { 190 memset( (char *)ptr + copy_end, (int)Fill.c, Dim * size - copy_end ); 191 } else if(Fill.tag == 't') { 192 for ( int i = copy_end; i < Dim * size; i += size ) { 193 memcpy( (char *)ptr + i, &Fill.t, size ); 194 } 195 } else if(Fill.tag == 'a') { 196 memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) ); 197 } else if(Fill.tag == 'T') { 198 for ( int i = copy_end; i < Dim * size; i += size ) { 199 memcpy( (char *)ptr + i, Fill.at, size ); 200 } 201 } 202 203 return ptr; 204 } // $alloc_internal 205 206 forall( ttype TT | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) { 207 208 T * $alloc_internal( void * , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) { 209 return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest); 210 } 211 212 T * $alloc_internal( void * Resize, T * , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) { 213 return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest); 214 } 215 216 T * $alloc_internal( void * Resize, T * Realloc, size_t , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) { 217 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest); 218 } 219 220 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) , S_fill(T) Fill, TT rest) { 221 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest); 222 } 223 224 T * alloc( TT all ) { 225 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all); 226 } 227 228 T * alloc( size_t dim, TT all ) { 229 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all); 230 } 231 232 } // distribution TT 233 } // distribution T 159 234 160 235 static inline forall( dtype T | sized(T) ) { 161 // data, non-array types236 // CFA safe initialization/copy, i.e., implicit size specification, non-array types 162 237 T * memset( T * dest, char fill ) { 163 238 return (T *)memset( dest, fill, sizeof(T) ); … … 167 242 return (T *)memcpy( dest, src, sizeof(T) ); 168 243 } // memcpy 169 } // distribution 170 171 static inline forall( dtype T | sized(T) ) { 172 // data, array types 244 245 // CFA safe initialization/copy, i.e., implicit size specification, array types 173 246 T * amemset( T dest[], char fill, size_t dim ) { 174 247 return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset … … 180 253 } // distribution 181 254 182 // allocation/deallocation and constructor/destructor, non-array types 183 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p ); 184 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr ); 185 forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } ) void delete( T * ptr, Params rest ); 186 187 // allocation/deallocation and constructor/destructor, array types 188 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p ); 189 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] ); 190 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } ) void adelete( size_t dim, T arr[], Params rest ); 255 // CFA deallocation for multiple objects 256 static inline forall( dtype T ) // FIX ME, problems with 0p in list 257 void free( T * ptr ) { 258 free( (void *)ptr ); // C free 259 } // free 260 static inline forall( dtype T, ttype TT | { void free( TT ); } ) 261 void free( T * ptr, TT rest ) { 262 free( ptr ); 263 free( rest ); 264 } // free 265 266 // CFA allocation/deallocation and constructor/destructor, non-array types 267 static inline forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) 268 T * new( TT p ) { 269 return &(*(T *)malloc()){ p }; // run constructor 270 } // new 271 272 static inline forall( dtype T | { void ^?{}( T & ); } ) 273 void delete( T * ptr ) { 274 // special case for 0-sized object => always call destructor 275 if ( ptr || sizeof(ptr) == 0 ) { // ignore null but not 0-sized objects 276 ^(*ptr){}; // run destructor 277 } // if 278 free( ptr ); // always call free 279 } // delete 280 static inline forall( dtype T, ttype TT | { void ^?{}( T & ); void delete( TT ); } ) 281 void delete( T * ptr, TT rest ) { 282 delete( ptr ); 283 delete( rest ); 284 } // delete 285 286 // CFA allocation/deallocation and constructor/destructor, array types 287 forall( dtype T | sized(T), ttype TT | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p ); 288 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] ); 289 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype TT | { void adelete( TT ); } ) void adelete( T arr[], TT rest ); 191 290 192 291 //--------------------------------------- 193 292 194 293 static inline { 195 int strto( const char * sptr, char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); }196 unsigned int strto( const char * sptr, char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); }197 long int strto( const char * sptr, char ** eptr, int base ) { return strtol( sptr, eptr, base ); }198 unsigned long int strto( const char * sptr, char ** eptr, int base ) { return strtoul( sptr, eptr, base ); }199 long long int strto( const char * sptr, char ** eptr, int base ) { return strtoll( sptr, eptr, base ); }200 unsigned long long int strto( const char * sptr, char ** eptr, int base ) { return strtoull( sptr, eptr, base ); }201 202 float strto( const char * sptr, char ** eptr ) { return strtof( sptr, eptr ); }203 double strto( const char * sptr, char ** eptr ) { return strtod( sptr, eptr ); }204 long double strto( const char * sptr, char ** eptr ) { return strtold( sptr, eptr ); }205 } // distribution 206 207 float _Complex strto( const char * sptr, char ** eptr );208 double _Complex strto( const char * sptr, char ** eptr );209 long double _Complex strto( const char * sptr, char ** eptr );294 int strto( const char sptr[], char ** eptr, int base ) { return (int)strtol( sptr, eptr, base ); } 295 unsigned int strto( const char sptr[], char ** eptr, int base ) { return (unsigned int)strtoul( sptr, eptr, base ); } 296 long int strto( const char sptr[], char ** eptr, int base ) { return strtol( sptr, eptr, base ); } 297 unsigned long int strto( const char sptr[], char ** eptr, int base ) { return strtoul( sptr, eptr, base ); } 298 long long int strto( const char sptr[], char ** eptr, int base ) { return strtoll( sptr, eptr, base ); } 299 unsigned long long int strto( const char sptr[], char ** eptr, int base ) { return strtoull( sptr, eptr, base ); } 300 301 float strto( const char sptr[], char ** eptr ) { return strtof( sptr, eptr ); } 302 double strto( const char sptr[], char ** eptr ) { return strtod( sptr, eptr ); } 303 long double strto( const char sptr[], char ** eptr ) { return strtold( sptr, eptr ); } 304 } // distribution 305 306 float _Complex strto( const char sptr[], char ** eptr ); 307 double _Complex strto( const char sptr[], char ** eptr ); 308 long double _Complex strto( const char sptr[], char ** eptr ); 210 309 211 310 static inline { 212 int ato( const char * sptr) { return (int)strtol( sptr, 0p, 10 ); }213 unsigned int ato( const char * sptr) { return (unsigned int)strtoul( sptr, 0p, 10 ); }214 long int ato( const char * sptr) { return strtol( sptr, 0p, 10 ); }215 unsigned long int ato( const char * sptr) { return strtoul( sptr, 0p, 10 ); }216 long long int ato( const char * sptr) { return strtoll( sptr, 0p, 10 ); }217 unsigned long long int ato( const char * sptr) { return strtoull( sptr, 0p, 10 ); }218 219 float ato( const char * sptr) { return strtof( sptr, 0p ); }220 double ato( const char * sptr) { return strtod( sptr, 0p ); }221 long double ato( const char * sptr) { return strtold( sptr, 0p ); }222 223 float _Complex ato( const char * sptr) { return strto( sptr, 0p ); }224 double _Complex ato( const char * sptr) { return strto( sptr, 0p ); }225 long double _Complex ato( const char * sptr) { return strto( sptr, 0p ); }311 int ato( const char sptr[] ) { return (int)strtol( sptr, 0p, 10 ); } 312 unsigned int ato( const char sptr[] ) { return (unsigned int)strtoul( sptr, 0p, 10 ); } 313 long int ato( const char sptr[] ) { return strtol( sptr, 0p, 10 ); } 314 unsigned long int ato( const char sptr[] ) { return strtoul( sptr, 0p, 10 ); } 315 long long int ato( const char sptr[] ) { return strtoll( sptr, 0p, 10 ); } 316 unsigned long long int ato( const char sptr[] ) { return strtoull( sptr, 0p, 10 ); } 317 318 float ato( const char sptr[] ) { return strtof( sptr, 0p ); } 319 double ato( const char sptr[] ) { return strtod( sptr, 0p ); } 320 long double ato( const char sptr[] ) { return strtold( sptr, 0p ); } 321 322 float _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } 323 double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } 324 long double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } 226 325 } // distribution 227 326 … … 254 353 extern "C" { // override C version 255 354 void srandom( unsigned int seed ); 256 long int random( void ); 355 long int random( void ); // GENERATES POSITIVE AND NEGATIVE VALUES 356 // For positive values, use unsigned int, e.g., unsigned int r = random() % 100U; 257 357 } // extern "C" 258 358 … … 261 361 long int random( long int u ) { if ( u < 0 ) return random( u, 0 ); else return random( 0, u ); } // [0,u) 262 362 unsigned long int random( void ) { return lrand48(); } 363 unsigned long int random( unsigned long int u ) { return lrand48() % u; } // [0,u) 263 364 unsigned long int random( unsigned long int l, unsigned long int u ) { if ( u < l ) [u, l] = [l, u]; return lrand48() % (u - l) + l; } // [l,u) 264 unsigned long int random( unsigned long int u ) { return lrand48() % u; } // [0,u)265 365 266 366 char random( void ) { return (unsigned long int)random(); } … … 283 383 //--------------------------------------- 284 384 285 #include "common.hfa" 286 287 //--------------------------------------- 288 289 extern bool threading_enabled(void) OPTIONAL_THREAD; 385 extern bool threading_enabled( void ) OPTIONAL_THREAD; 290 386 291 387 // Local Variables: // -
libcfa/src/time.cfa
rbdfc032 reef8dfb 10 10 // Created On : Tue Mar 27 13:33:14 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 5 17:27:40202013 // Update Count : 6912 // Last Modified On : Tue Feb 4 08:24:18 2020 13 // Update Count : 70 14 14 // 15 15 … … 129 129 } // dd_mm_yy 130 130 131 size_t strftime( char * buf, size_t size, const char * fmt, Time time ) with( time ) {131 size_t strftime( char buf[], size_t size, const char fmt[], Time time ) with( time ) { 132 132 time_t s = tn / TIMEGRAN; 133 133 tm tm; -
libcfa/src/time.hfa
rbdfc032 reef8dfb 10 10 // Created On : Wed Mar 14 23:18:57 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 6 12:50:16202013 // Update Count : 6 5312 // Last Modified On : Wed Jun 17 16:13:00 2020 13 // Update Count : 663 14 14 // 15 15 … … 20 20 21 21 #include <time.h> // timespec 22 extern "C" {23 22 #include <sys/time.h> // timeval 24 }25 23 #include <time_t.hfa> // Duration/Time types 26 24 … … 91 89 int64_t ?`w( Duration dur ) { return dur.tn / (7LL * 24LL * 60LL * 60LL * TIMEGRAN); } 92 90 91 double ?`dns( Duration dur ) { return dur.tn; } 92 double ?`dus( Duration dur ) { return dur.tn / ((double)TIMEGRAN / 1_000_000.); } 93 double ?`dms( Duration dur ) { return dur.tn / ((double)TIMEGRAN / 1_000.); } 94 double ?`ds( Duration dur ) { return dur.tn / (double)TIMEGRAN; } 95 double ?`dm( Duration dur ) { return dur.tn / (60. * TIMEGRAN); } 96 double ?`dh( Duration dur ) { return dur.tn / (60. * 60. * (double)TIMEGRAN); } 97 double ?`dd( Duration dur ) { return dur.tn / (24. * 60. * 60. * (double)TIMEGRAN); } 98 double ?`dw( Duration dur ) { return dur.tn / (7. * 24. * 60. * 60. * (double)TIMEGRAN); } 99 93 100 Duration max( Duration lhs, Duration rhs ) { return (lhs.tn < rhs.tn) ? rhs : lhs;} 94 101 Duration min( Duration lhs, Duration rhs ) { return !(rhs.tn < lhs.tn) ? lhs : rhs;} … … 191 198 } // dmy 192 199 193 size_t strftime( char * buf, size_t size, const char * fmt, Time time );200 size_t strftime( char buf[], size_t size, const char fmt[], Time time ); 194 201 195 202 //------------------------- timeval (cont) ------------------------- -
libcfa/src/vec/vec.hfa
rbdfc032 reef8dfb 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // io/types.hfa -- 8 // 9 // Author : Dimitry Kobets 10 // Created On : 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 15 1 16 #pragma once 2 17 -
libcfa/src/vec/vec2.hfa
rbdfc032 reef8dfb 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // io/types.hfa -- 8 // 9 // Author : Dimitry Kobets 10 // Created On : 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 15 1 16 #pragma once 2 17 -
libcfa/src/vec/vec3.hfa
rbdfc032 reef8dfb 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // io/types.hfa -- 8 // 9 // Author : Dimitry Kobets 10 // Created On : 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 15 1 16 #pragma once 2 17 -
libcfa/src/vec/vec4.hfa
rbdfc032 reef8dfb 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // io/types.hfa -- 8 // 9 // Author : Dimitry Kobets 10 // Created On : 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 15 1 16 #pragma once 2 17
Note:
See TracChangeset
for help on using the changeset viewer.