source: libcfa/src/bits/locks.hfa @ f835806

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since f835806 was 418d31ac, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Added spin count to spin locks as a debugging tool

  • Property mode set to 100644
File size: 2.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 -- Basic spinlocks that are reused in the system.
8// Used for locks that aren't specific to cforall threads and can be used anywhere
9//
10//  *** Must not contain code specific to libcfathread ***
11//
12// Author           : Thierry Delisle
13// Created On       : Tue Oct 31 15:14:38 2017
14// Last Modified By : Peter A. Buhr
15// Last Modified On : Wed Aug 12 14:18:07 2020
16// Update Count     : 13
17//
18
19#pragma once
20
21#include "bits/debug.hfa"
22#include "bits/defs.hfa"
23#include <assert.h>
24
25struct __spinlock_t {
26        // Wrap in struct to prevent false sharing with debug info
27        volatile bool lock;
28        #ifdef __CFA_DEBUG__
29                // previous function to acquire the lock
30                const char * prev_name;
31                // previous thread to acquire the lock
32                void* prev_thrd;
33                // keep track of number of times we had to spin, just in case the number is unexpectedly huge
34                size_t spin_count;
35        #endif
36};
37
38#ifdef __cforall
39        extern "C" {
40                extern void disable_interrupts() OPTIONAL_THREAD;
41                extern void enable_interrupts( bool poll = true ) OPTIONAL_THREAD;
42
43                #ifdef __CFA_DEBUG__
44                        void __cfaabi_dbg_record_lock(__spinlock_t & this, const char prev_name[]);
45                #else
46                        #define __cfaabi_dbg_record_lock(x, y)
47                #endif
48        }
49
50        static inline void ?{}( __spinlock_t & this ) {
51                this.lock = 0;
52                #ifdef __CFA_DEBUG__
53                        this.spin_count = 0;
54                #endif
55        }
56
57        // Lock the spinlock, return false if already acquired
58        static inline bool try_lock  ( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
59                disable_interrupts();
60                bool result = (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0);
61                if( result ) {
62                        __cfaabi_dbg_record_lock( this, caller );
63                } else {
64                        enable_interrupts( false );
65                }
66                return result;
67        }
68
69        // Lock the spinlock, spin if already acquired
70        static inline void lock( __spinlock_t & this __cfaabi_dbg_ctx_param2 ) {
71                #ifndef NOEXPBACK
72                        enum { SPIN_START = 4, SPIN_END = 64 * 1024, };
73                        unsigned int spin = SPIN_START;
74                #endif
75
76                disable_interrupts();
77                for ( unsigned int i = 1;; i += 1 ) {
78                        if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
79                        #ifdef __CFA_DEBUG__
80                                this.spin_count++;
81                        #endif
82                        #ifndef NOEXPBACK
83                                // exponential spin
84                                for ( volatile unsigned int s = 0; s < spin; s += 1 ) Pause();
85
86                                // slowly increase by powers of 2
87                                if ( i % 64 == 0 ) spin += spin;
88
89                                // prevent overflow
90                                if ( spin > SPIN_END ) spin = SPIN_START;
91                        #else
92                                Pause();
93                        #endif
94                }
95                __cfaabi_dbg_record_lock( this, caller );
96        }
97
98        static inline void unlock( __spinlock_t & this ) {
99                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
100                enable_interrupts( false );
101        }
102#endif
Note: See TracBrowser for help on using the repository browser.