source: libcfa/src/bits/locks.hfa @ 8465b4d

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 8465b4d was 95789be, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 5.6 KB
RevLine 
[ea7d2b0]1//
2// Cforall Version 1.0.0 Copyright (C) 2016 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//
[73abe95]7// bits/locks.hfa -- Fast internal locks.
[ea7d2b0]8//
9// Author           : Thierry Delisle
10// Created On       : Tue Oct 31 15:14:38 2017
[b158d8f]11// Last Modified By : Peter A. Buhr
[e3fea42]12// Last Modified On : Tue Feb  4 13:03:19 2020
13// Update Count     : 11
[ea7d2b0]14//
15
16#pragma once
17
[73abe95]18#include "bits/debug.hfa"
19#include "bits/defs.hfa"
[ea8b2f7]20#include <assert.h>
21
22#ifdef __cforall
23        extern "C" {
24                #include <pthread.h>
25        }
26#endif
[ea7d2b0]27
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 )
32        #define Pause() __asm__ __volatile__ ( "pause" : : : )
[b158d8f]33#elif defined( __ARM_ARCH )
34        #define Pause() __asm__ __volatile__ ( "nop" : : : )
[ea7d2b0]35#else
36        #error unsupported architecture
37#endif
38
39struct __spinlock_t {
[13073be]40        // Wrap in struct to prevent false sharing with debug info
[3aeee3c]41        volatile bool lock;
[ea7d2b0]42        #ifdef __CFA_DEBUG__
[13073be]43                // previous function to acquire the lock
[ea7d2b0]44                const char * prev_name;
[13073be]45                // previous thread to acquire the lock
[ea7d2b0]46                void* prev_thrd;
47        #endif
[3aeee3c]48};
[ea7d2b0]49
[0cf5b79]50#ifdef __cforall
[dbe9b08]51        extern "C" {
[2026bb6]52                extern void disable_interrupts() OPTIONAL_THREAD;
53                extern void enable_interrupts_noPoll() OPTIONAL_THREAD;
[1997b4e]54
55                #ifdef __CFA_DEBUG__
[ae66348]56                        void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]);
[1997b4e]57                #else
[ae66348]58                        #define __cfaabi_dbg_record_lock(x, y)
[1997b4e]59                #endif
[dbe9b08]60        }
61
[ea7d2b0]62        static inline void ?{}( __spinlock_t & this ) {
63                this.lock = 0;
64        }
65
66        // Lock the spinlock, return false if already acquired
[93c2e0a]67        static inline bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
[3381ed7]68                disable_interrupts();
[93c2e0a]69                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
[dbe9b08]70                if( result ) {
[ae66348]71                        __cfaabi_dbg_record_lock( this, caller );
[3381ed7]72                } else {
73                        enable_interrupts_noPoll();
[dbe9b08]74                }
[ea7d2b0]75                return result;
76        }
77
78        // Lock the spinlock, spin if already acquired
[36982fc]79        static inline void lock( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
[ea7d2b0]80                #ifndef NOEXPBACK
81                        enum { SPIN_START = 4, SPIN_END = 64 * 1024, };
82                        unsigned int spin = SPIN_START;
83                #endif
84
[3381ed7]85                disable_interrupts();
[ea7d2b0]86                for ( unsigned int i = 1;; i += 1 ) {
[13073be]87                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
[ea7d2b0]88                        #ifndef NOEXPBACK
89                                // exponential spin
90                                for ( volatile unsigned int s = 0; s < spin; s += 1 ) Pause();
91
92                                // slowly increase by powers of 2
93                                if ( i % 64 == 0 ) spin += spin;
94
95                                // prevent overflow
96                                if ( spin > SPIN_END ) spin = SPIN_START;
97                        #else
98                                Pause();
99                        #endif
100                }
[ae66348]101                __cfaabi_dbg_record_lock( this, caller );
[ea7d2b0]102        }
103
104        static inline void unlock( __spinlock_t & this ) {
[13073be]105                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
[3381ed7]106                enable_interrupts_noPoll();
[ea7d2b0]107        }
[ea8b2f7]108
109
110        #ifdef __CFA_WITH_VERIFY__
111                extern bool __cfaabi_dbg_in_kernel();
112        #endif
113
[c66f6cb]114        extern "C" {
115                char * strerror(int);
116        }
[6ec07e5]117        #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
[c66f6cb]118
[ea8b2f7]119        struct __bin_sem_t {
[85b1deb]120                pthread_mutex_t         lock;
121                pthread_cond_t          cond;
[4069faad]122                int                     val;
[ea8b2f7]123        };
124
125        static inline void ?{}(__bin_sem_t & this) with( this ) {
[c66f6cb]126                // Create the mutex with error checking
127                pthread_mutexattr_t mattr;
128                pthread_mutexattr_init( &mattr );
129                pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
130                pthread_mutex_init(&lock, &mattr);
131
[b81fd95]132                pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
[4069faad]133                val = 0;
[ea8b2f7]134        }
135
136        static inline void ^?{}(__bin_sem_t & this) with( this ) {
[c66f6cb]137                CHECKED( pthread_mutex_destroy(&lock) );
138                CHECKED( pthread_cond_destroy (&cond) );
[ea8b2f7]139        }
140
141        static inline void wait(__bin_sem_t & this) with( this ) {
142                verify(__cfaabi_dbg_in_kernel());
[c66f6cb]143                CHECKED( pthread_mutex_lock(&lock) );
[4069faad]144                        while(val < 1) {
[85b1deb]145                                pthread_cond_wait(&cond, &lock);
146                        }
[4069faad]147                        val -= 1;
[c66f6cb]148                CHECKED( pthread_mutex_unlock(&lock) );
[ea8b2f7]149        }
150
[92e7631]151        static inline bool post(__bin_sem_t & this) with( this ) {
[4069faad]152                bool needs_signal = false;
153
[c66f6cb]154                CHECKED( pthread_mutex_lock(&lock) );
[4069faad]155                        if(val < 1) {
156                                val += 1;
157                                pthread_cond_signal(&cond);
158                                needs_signal = true;
159                        }
[c66f6cb]160                CHECKED( pthread_mutex_unlock(&lock) );
[85b1deb]161
[92e7631]162                return needs_signal;
[85b1deb]163        }
[c66f6cb]164
165        #undef CHECKED
[e0f93e0]166
167        struct $thread;
168        extern void park( __cfaabi_dbg_ctx_param );
169        extern void unpark( struct $thread * this __cfaabi_dbg_ctx_param2 );
170        static inline struct $thread * active_thread ();
171
172        // Semaphore which only supports a single thread
173        struct single_sem {
174                struct $thread * volatile ptr;
175        };
176
177        static inline {
178                void  ?{}(single_sem & this) {
179                        this.ptr = 0p;
180                }
181
182                void ^?{}(single_sem & this) {}
183
184                bool wait(single_sem & this) {
185                        for() {
186                                struct $thread * expected = this.ptr;
187                                if(expected == 1p) {
188                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
189                                                return false;
190                                        }
191                                }
192                                else {
193                                        /* paranoid */ verify( expected == 0p );
194                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
195                                                park( __cfaabi_dbg_ctx );
196                                                return true;
197                                        }
198                                }
199
200                        }
201                }
202
203                bool post(single_sem & this) {
204                        for() {
205                                struct $thread * expected = this.ptr;
206                                if(expected == 1p) return false;
207                                if(expected == 0p) {
208                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, 1p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
209                                                return false;
210                                        }
211                                }
212                                else {
213                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
214                                                unpark( expected __cfaabi_dbg_ctx2 );
215                                                return true;
216                                        }
217                                }
218                        }
219                }
220        }
[b158d8f]221#endif
Note: See TracBrowser for help on using the repository browser.