Changeset 58fe85a for libcfa/src/bits


Ignore:
Timestamp:
Jan 7, 2021, 3:27:00 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
2b4daf2, 64aeca0
Parents:
3c64c668 (diff), eef8dfb (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.
Message:

Merge branch 'master' into park_unpark

Location:
libcfa/src/bits
Files:
5 added
6 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/bits/containers.hfa

    r3c64c668 r58fe85a  
    1717#include "bits/align.hfa"
    1818#include "bits/defs.hfa"
    19 
     19#include <stdio.h>
    2020//-----------------------------------------------------------------------------
    2121// Array
     
    3636        #define __small_array_t(T) __small_array(T)
    3737#else
    38         #define __small_array_t(T) struct __small_array
     38        #define __small_array_t(T) __small_array
    3939#endif
    4040
     
    146146        static inline forall( dtype T | is_node(T) ) {
    147147                void ?{}( __queue(T) & this ) with( this ) {
    148                         head{ 1p };
    149                         tail{ &head };
    150                         verify(*tail == 1p);
     148                        (this.head){ 1p };
     149                        (this.tail){ &this.head };
     150                        verify(*this.tail == 1p);
    151151                }
    152152
    153153                void append( __queue(T) & this, T * val ) with( this ) {
    154                         verify(tail != 0p);
    155                         verify(*tail == 1p);
    156                         *tail = val;
    157                         tail = &get_next( *val );
    158                         *tail = 1p;
     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;
    159170                }
    160171
    161172                T * pop_head( __queue(T) & this ) {
    162173                        verify(*this.tail == 1p);
    163                         T * head = this.head;
    164                         if( head != 1p ) {
    165                                 this.head = get_next( *head );
    166                                 if( get_next( *head ) == 1p ) {
     174                        T * _head = this.head;
     175                        if( _head != 1p ) {
     176                                this.head = get_next( *_head );
     177                                if( get_next( *_head ) == 1p ) {
    167178                                        this.tail = &this.head;
    168179                                }
    169                                 get_next( *head ) = 0p;
     180                                get_next( *_head ) = 0p;
    170181                                verify(*this.tail == 1p);
    171                                 return head;
     182                                verify( get_next(*_head) == 0p );
     183                                return _head;
    172184                        }
    173185                        verify(*this.tail == 1p);
     
    181193                        (*it) = get_next( *val );
    182194
    183                         if( tail == &get_next( *val ) ) {
    184                                 tail = it;
     195                        if( this.tail == &get_next( *val ) ) {
     196                                this.tail = it;
    185197                        }
    186198
    187199                        get_next( *val ) = 0p;
    188200
    189                         verify( (head == 1p) == (&head == tail) );
    190                         verify( *tail == 1p );
     201                        verify( (this.head == 1p) == (&this.head == this.tail) );
     202                        verify( *this.tail == 1p );
    191203                        return val;
    192204                }
    193205
    194206                int ?!=?( const __queue(T) & this, __attribute__((unused)) zero_t zero ) {
    195                         return this.head != 0;
     207                        return this.head != 1p;
    196208                }
    197209        }
     
    227239        forall(dtype T )
    228240        static inline [void] ?{}( __dllist(T) & this, * [T * & next, T * & prev] ( T & ) __get ) {
    229                 this.head{ 0p };
     241                (this.head){ 0p };
    230242                this.__get = __get;
    231243        }
     
    236248                void push_front( __dllist(T) & this, T & node ) with( this ) {
    237249                        verify(__get);
    238                         if ( head ) {
    239                                 __get( node ).next = head;
    240                                 __get( node ).prev = __get( *head ).prev;
     250                        if ( this.head ) {
     251                                __get( node ).next = this.head;
     252                                __get( node ).prev = __get( *this.head ).prev;
    241253                                // inserted node must be consistent before it is seen
    242254                                // prevent code movement across barrier
    243255                                asm( "" : : : "memory" );
    244                                 __get( *head ).prev = &node;
     256                                __get( *this.head ).prev = &node;
    245257                                T & _prev = *__get( node ).prev;
    246258                                __get( _prev ).next = &node;
     
    252264                        // prevent code movement across barrier
    253265                        asm( "" : : : "memory" );
    254                         head = &node;
     266                        this.head = &node;
    255267                }
    256268
    257269                void remove( __dllist(T) & this, T & node ) with( this ) {
    258270                        verify(__get);
    259                         if ( &node == head ) {
    260                                 if ( __get( *head ).next == head ) {
    261                                         head = 0p;
     271                        if ( &node == this.head ) {
     272                                if ( __get( *this.head ).next == this.head ) {
     273                                        this.head = 0p;
    262274                                } else {
    263                                         head = __get( *head ).next;
     275                                        this.head = __get( *this.head ).next;
    264276                                }
    265277                        }
     
    273285                        return this.head != 0;
    274286                }
     287
     288                void move_to_front( __dllist(T) & src, __dllist(T) & dst, T & node ) {
     289                        remove    (src, node);
     290                        push_front(dst, node);
     291                }
    275292        }
    276293        #undef next
  • libcfa/src/bits/debug.cfa

    r3c64c668 r58fe85a  
    1010// Created On       : Thu Mar 30 12:30:01 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:16 2020
    13 // Update Count     : 11
     12// Last Modified On : Wed Jun 17 11:07:13 2020
     13// Update Count     : 12
    1414//
    1515
    16 extern "C" {
    1716#include <stdio.h>
    1817#include <stdlib.h>
     
    2120#include <stdarg.h>
    2221#include <unistd.h>
    23 }
    2422
    2523enum { buffer_size = 4096 };
  • libcfa/src/bits/debug.hfa

    r3c64c668 r58fe85a  
    99// Author           : Thierry Delisle
    1010// Created On       : Mon Nov 28 12:27:26 2016
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:21 2020
    13 // Update Count     : 9
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr 27 10:15:00 2020
     13// Update Count     : 10
    1414//
    1515
    1616#pragma once
     17
     18#include <assert.h>
    1719
    1820#ifdef __CFA_DEBUG__
     
    2325        #define __cfaabi_dbg_ctx_param const char caller[]
    2426        #define __cfaabi_dbg_ctx_param2 , const char caller[]
     27        #define __cfaabi_dbg_ctx_fwd caller
     28        #define __cfaabi_dbg_ctx_fwd2 , caller
    2529#else
    2630        #define __cfaabi_dbg_debug_do(...)
     
    3034        #define __cfaabi_dbg_ctx_param
    3135        #define __cfaabi_dbg_ctx_param2
     36        #define __cfaabi_dbg_ctx_fwd
     37        #define __cfaabi_dbg_ctx_fwd2
    3238#endif
    3339
     
    3642#endif
    3743        #include <stdarg.h>
    38         #include <stdio.h>
    3944
    4045        extern void __cfaabi_bits_write( int fd, const char buffer[], int len );
     
    4550        extern void __cfaabi_bits_print_vararg( int fd, const char fmt[], va_list arg );
    4651        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
    4761#ifdef __cforall
    4862}
    4963#endif
    5064
     65// Deprecated: Use the versions with the new module names.
    5166#ifdef __CFA_DEBUG_PRINT__
    5267        #define __cfaabi_dbg_write( buffer, len )         __cfaabi_bits_write( STDERR_FILENO, buffer, len )
    5368        #define __cfaabi_dbg_acquire()                    __cfaabi_bits_acquire()
    5469        #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 );
    6075#else
    6176        #define __cfaabi_dbg_write(...)               ((void)0)
     
    6984#endif
    7085
     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
    71144// Local Variables: //
    72145// mode: c //
  • libcfa/src/bits/defs.hfa

    r3c64c668 r58fe85a  
    1010// Created On       : Thu Nov  9 13:24:10 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jan 28 22:38:27 2020
    13 // Update Count     : 9
     12// Last Modified On : Sat Oct 24 10:53:15 2020
     13// Update Count     : 21
    1414//
    1515
    1616#pragma once
    1717
    18 #include <stdbool.h>
    19 #include <stddef.h>
    2018#include <stdint.h>
     19#include <assert.h>
    2120
    2221#define likely(x)   __builtin_expect(!!(x), 1)
     
    3029#define __cfa_anonymous_object(x) inline struct x
    3130#else
    32 #define __cfa_anonymous_object(x) x __cfa_anonymous_object
     31#define __cfa_anonymous_object(x) struct x __cfa_anonymous_object
    3332#endif
    3433
     
    4948#endif
    5049
    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 );
     50static 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
    5563}
  • libcfa/src/bits/locks.hfa

    r3c64c668 r58fe85a  
    1010// Created On       : Tue Oct 31 15:14:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 13:03:19 2020
    13 // Update Count     : 11
     12// Last Modified On : Wed Aug 12 14:18:07 2020
     13// Update Count     : 13
    1414//
    1515
     
    2727
    2828// 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 )
    3230        #define Pause() __asm__ __volatile__ ( "pause" : : : )
    3331#elif defined( __ARM_ARCH )
    34         #define Pause() __asm__ __volatile__ ( "nop" : : : )
     32        #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    3533#else
    3634        #error unsupported architecture
     
    5452
    5553                #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[]);
    5755                #else
    58                         #define __cfaabi_dbg_record(x, y)
     56                        #define __cfaabi_dbg_record_lock(x, y)
    5957                #endif
    6058        }
     
    6967                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
    7068                if( result ) {
    71                         __cfaabi_dbg_record( this, caller );
     69                        __cfaabi_dbg_record_lock( this, caller );
    7270                } else {
    7371                        enable_interrupts_noPoll();
     
    9997                        #endif
    10098                }
    101                 __cfaabi_dbg_record( this, caller );
     99                __cfaabi_dbg_record_lock( this, caller );
    102100        }
    103101
     
    112110        #endif
    113111
     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
    114117        struct __bin_sem_t {
    115                 bool                    signaled;
    116118                pthread_mutex_t         lock;
    117119                pthread_cond_t          cond;
     120                int                     val;
    118121        };
    119122
    120123        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;
    124132        }
    125133
    126134        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) );
    129137        }
    130138
    131139        static inline void wait(__bin_sem_t & this) with( this ) {
    132140                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) {
    135143                                pthread_cond_wait(&cond, &lock);
    136144                        }
    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                }
    151422        }
    152423#endif
  • libcfa/src/bits/signal.hfa

    r3c64c668 r58fe85a  
    1919#include "bits/defs.hfa"
    2020
    21 extern "C" {
    2221#include <errno.h>
    2322#define __USE_GNU
     
    2625#include <stdlib.h>
    2726#include <string.h>
    28 }
    2927
    3028// Short hands for signal context information
     
    5452                        sig, handler, flags, errno, strerror( errno )
    5553                );
    56                 _exit( EXIT_FAILURE );
     54                _Exit( EXIT_FAILURE );
    5755        } // if
    5856}
Note: See TracChangeset for help on using the changeset viewer.