HPCToolkit
spinlock.h
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // Spin lock
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 // Author:
59 // [...]
60 //
61 //***************************************************************************
62 
63 #ifndef prof_lean_spinlock_h
64 #define prof_lean_spinlock_h
65 
66 #include <stdbool.h>
67 #include <stdint.h>
68 #include <stddef.h>
69 
70 #include "stdatomic.h"
71 
72 //
73 // Simple spin lock.
74 //
75 
76 typedef struct spinlock_s {
77  atomic_long thelock;
78 } spinlock_t;
79 
80 #define SPINLOCK_UNLOCKED_VALUE (-1L)
81 #define SPINLOCK_LOCKED_VALUE (1L)
82 #define INITIALIZE_SPINLOCK(x) { .thelock = ATOMIC_VAR_INIT(x) }
83 
84 #define SPINLOCK_UNLOCKED INITIALIZE_SPINLOCK(SPINLOCK_UNLOCKED_VALUE)
85 #define SPINLOCK_LOCKED INITIALIZE_SPINLOCK(SPINLOCK_LOCKED_VALUE)
86 
87 
88 static inline void
90 {
92 }
93 
94 static inline
95 void
97 {
99 }
100 
101 
102 static inline
103 bool
105 {
107 }
108 
109 static inline
110 void
112 {
113  /* test-and-set lock */
114  long old_lockval = SPINLOCK_UNLOCKED_VALUE;
117  old_lockval = SPINLOCK_UNLOCKED_VALUE;
118  }
119 }
120 
121 
122 // deadlock avoiding lock primitives:
123 //
124 // test-and-test-and-set lock acquisition, but make a bounded
125 // number of attempts to get lock.
126 // to be signature compatible, this locking function takes a "locked" value, but does
127 // not use it.
128 // returns false if lock not acquired
129 //
130 // NOTE: this lock is still released with spinlock_unlock operation
131 //
132 static inline
133 bool
134 limit_spinlock_lock(spinlock_t* l, size_t limit, long locked_val)
135 {
136  if (limit == 0) {
137  spinlock_lock(l);
138  return true;
139  }
140 
141  long old_lockval = SPINLOCK_UNLOCKED_VALUE;
142  while (limit-- > 0 &&
145  old_lockval = SPINLOCK_UNLOCKED_VALUE;
146  }
147  return (limit + 1 > 0);
148 }
149 
150 //
151 // hwt_cas_spinlock_lock uses the CAS primitive, but prevents deadlock
152 // by checking the locked value to see if this (hardware) thread has already
153 // acquired the lock
154 //
155 // returns false if lock acquisition is abandoned
156 //
157 // NOTE: this lock is still released with spinlock_unlock operation
158 //
159 static inline
160 bool
161 hwt_cas_spinlock_lock(spinlock_t* l, size_t limit, long locked_val)
162 {
163  long old_lockval = SPINLOCK_UNLOCKED_VALUE;
164  while (!atomic_compare_exchange_weak_explicit(&l->thelock, &old_lockval, locked_val,
166  // if we are already locked by the same id, prevent deadlock by
167  // abandoning lock acquisition
168  if (old_lockval == locked_val)
169  return false;
170  old_lockval = SPINLOCK_UNLOCKED_VALUE;
171  }
172  return true;
173 }
174 
175 //
176 // hwt_limit_spinlock_lock uses the CAS primitive, but prevents deadlock
177 // by checking the locked value to see if this (hardware) thread has already
178 // acquired the lock. This spinlock *also* uses the iteration limit
179 // from the limit spinlock.
180 
181 // The hwt technique covers priority inversion deadlock
182 // in a way that is most friendly to high priority threads.
183 //
184 // The iteration limit technique covers other kinds of deadlock
185 // and starvation situations.
186 //
187 // NOTE: this lock is still released with spinlock_unlock operation
188 //
189 static inline
190 bool
191 hwt_limit_spinlock_lock(spinlock_t* l, size_t limit, long locked_val)
192 {
193  if (limit == 0)
194  return hwt_cas_spinlock_lock(l, limit, locked_val);
195 
196  long old_lockval = SPINLOCK_UNLOCKED_VALUE;
197  while (limit-- > 0 &&
198  !atomic_compare_exchange_weak_explicit(&l->thelock, &old_lockval, locked_val,
200  // if we are already locked by the same id, prevent deadlock by
201  // abandoning lock acquisition
202  if (old_lockval == locked_val)
203  return false;
204  old_lockval = SPINLOCK_UNLOCKED_VALUE;
205  }
206  return (limit + 1 > 0);
207 }
208 #endif // prof_lean_spinlock_h
atomic_long thelock
Definition: spinlock.h:77
static void spinlock_init(spinlock_t *l)
Definition: spinlock.h:89
static bool hwt_limit_spinlock_lock(spinlock_t *l, size_t limit, long locked_val)
Definition: spinlock.h:191
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure)
Definition: stdatomic.h:343
static void spinlock_unlock(spinlock_t *l)
Definition: spinlock.h:96
static bool limit_spinlock_lock(spinlock_t *l, size_t limit, long locked_val)
Definition: spinlock.h:134
#define atomic_load_explicit(object, order)
Definition: stdatomic.h:378
#define atomic_store_explicit(object, desired, order)
Definition: stdatomic.h:380
#define SPINLOCK_LOCKED_VALUE
Definition: spinlock.h:81
#define atomic_init(obj, value)
Definition: stdatomic.h:133
static void spinlock_lock(spinlock_t *l)
Definition: spinlock.h:111
static bool hwt_cas_spinlock_lock(spinlock_t *l, size_t limit, long locked_val)
Definition: spinlock.h:161
struct spinlock_s spinlock_t
#define SPINLOCK_UNLOCKED_VALUE
Definition: spinlock.h:80
static bool spinlock_is_locked(spinlock_t *l)
Definition: spinlock.h:104