source: libcfa/src/bits/locks.hfa @ 96ac72c

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 96ac72c was 2026bb6, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

More robust fix for optionally linking threads

  • Property mode set to 100644
File size: 3.8 KB
Line 
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//
7// bits/locks.hfa -- Fast internal locks.
8//
9// Author           : Thierry Delisle
10// Created On       : Tue Oct 31 15:14:38 2017
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sat Aug 11 15:42:24 2018
13// Update Count     : 10
14//
15
16#pragma once
17
18#include "bits/debug.hfa"
19#include "bits/defs.hfa"
20#include <assert.h>
21
22#ifdef __cforall
23        extern "C" {
24                #include <pthread.h>
25        }
26#endif
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" : : : )
33#elif defined( __ARM_ARCH )
34        #define Pause() __asm__ __volatile__ ( "nop" : : : )
35#else
36        #error unsupported architecture
37#endif
38
39struct __spinlock_t {
40        // Wrap in struct to prevent false sharing with debug info
41        volatile bool lock;
42        #ifdef __CFA_DEBUG__
43                // previous function to acquire the lock
44                const char * prev_name;
45                // previous thread to acquire the lock
46                void* prev_thrd;
47        #endif
48};
49
50#ifdef __cforall
51        extern "C" {
52                extern void disable_interrupts() OPTIONAL_THREAD;
53                extern void enable_interrupts_noPoll() OPTIONAL_THREAD;
54
55                #ifdef __CFA_DEBUG__
56                        void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name);
57                #else
58                        #define __cfaabi_dbg_record(x, y)
59                #endif
60        }
61
62        extern void yield( unsigned int );
63
64        static inline void ?{}( __spinlock_t & this ) {
65                this.lock = 0;
66        }
67
68        // Lock the spinlock, return false if already acquired
69        static inline bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
70                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
71                if( result ) {
72                        disable_interrupts();
73                        __cfaabi_dbg_record( this, caller );
74                }
75                return result;
76        }
77
78        // Lock the spinlock, spin if already acquired
79        static inline void lock( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
80                #ifndef NOEXPBACK
81                        enum { SPIN_START = 4, SPIN_END = 64 * 1024, };
82                        unsigned int spin = SPIN_START;
83                #endif
84
85                for ( unsigned int i = 1;; i += 1 ) {
86                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
87                        #ifndef NOEXPBACK
88                                // exponential spin
89                                for ( volatile unsigned int s = 0; s < spin; s += 1 ) Pause();
90
91                                // slowly increase by powers of 2
92                                if ( i % 64 == 0 ) spin += spin;
93
94                                // prevent overflow
95                                if ( spin > SPIN_END ) spin = SPIN_START;
96                        #else
97                                Pause();
98                        #endif
99                }
100                disable_interrupts();
101                __cfaabi_dbg_record( this, caller );
102        }
103
104        static inline void unlock( __spinlock_t & this ) {
105                enable_interrupts_noPoll();
106                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
107        }
108
109
110        #ifdef __CFA_WITH_VERIFY__
111                extern bool __cfaabi_dbg_in_kernel();
112        #endif
113
114        struct __bin_sem_t {
115                bool                    signaled;
116                pthread_mutex_t         lock;
117                pthread_cond_t          cond;
118        };
119
120        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        }
125
126        static inline void ^?{}(__bin_sem_t & this) with( this ) {
127                pthread_mutex_destroy(&lock);
128                pthread_cond_destroy (&cond);
129        }
130
131        static inline void wait(__bin_sem_t & this) with( this ) {
132                verify(__cfaabi_dbg_in_kernel());
133                pthread_mutex_lock(&lock);
134                        if(!signaled) {   // this must be a loop, not if!
135                                pthread_cond_wait(&cond, &lock);
136                        }
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);
151        }
152#endif
Note: See TracBrowser for help on using the repository browser.