blob: c5ce83823c0072277088c8b45283ee0c94515cf1 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
2 * kmp_lock.h -- lock header file
Jim Cownie181b4bb2013-12-23 17:28:57 +00003 * $Revision: 42810 $
4 * $Date: 2013-11-07 12:06:33 -0600 (Thu, 07 Nov 2013) $
Jim Cownie5e8470a2013-09-27 10:38:44 +00005 */
6
7
8//===----------------------------------------------------------------------===//
9//
10// The LLVM Compiler Infrastructure
11//
12// This file is dual licensed under the MIT and the University of Illinois Open
13// Source Licenses. See LICENSE.txt for details.
14//
15//===----------------------------------------------------------------------===//
16
17
18#ifndef KMP_LOCK_H
19#define KMP_LOCK_H
20
21#include <limits.h> // CHAR_BIT
22#include <stddef.h> // offsetof
23
24#include "kmp_os.h"
25#include "kmp_debug.h"
26
27#ifdef __cplusplus
28extern "C" {
29#endif // __cplusplus
30
31// ----------------------------------------------------------------------------
32// Have to copy these definitions from kmp.h because kmp.h cannot be included
33// due to circular dependencies. Will undef these at end of file.
34
35#define KMP_PAD(type, sz) (sizeof(type) + (sz - ((sizeof(type) - 1) % (sz)) - 1))
36#define KMP_GTID_DNE (-2)
37
38// Forward declaration of ident and ident_t
39
40struct ident;
41typedef struct ident ident_t;
42
43// End of copied code.
44// ----------------------------------------------------------------------------
45
46//
47// We need to know the size of the area we can assume that the compiler(s)
48// allocated for obects of type omp_lock_t and omp_nest_lock_t. The Intel
49// compiler always allocates a pointer-sized area, as does visual studio.
50//
51// gcc however, only allocates 4 bytes for regular locks, even on 64-bit
52// intel archs. It allocates at least 8 bytes for nested lock (more on
53// recent versions), but we are bounded by the pointer-sized chunks that
54// the Intel compiler allocates.
55//
56
57#if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT)
58# define OMP_LOCK_T_SIZE sizeof(int)
59# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
60#else
61# define OMP_LOCK_T_SIZE sizeof(void *)
62# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
63#endif
64
65//
66// The Intel compiler allocates a 32-byte chunk for a critical section.
67// Both gcc and visual studio only allocate enough space for a pointer.
68// Sometimes we know that the space was allocated by the Intel compiler.
69//
70#define OMP_CRITICAL_SIZE sizeof(void *)
71#define INTEL_CRITICAL_SIZE 32
72
73//
74// lock flags
75//
76typedef kmp_uint32 kmp_lock_flags_t;
77
78#define kmp_lf_critical_section 1
79
80//
81// When a lock table is used, the indices are of kmp_lock_index_t
82//
83typedef kmp_uint32 kmp_lock_index_t;
84
85//
86// When memory allocated for locks are on the lock pool (free list),
87// it is treated as structs of this type.
88//
89struct kmp_lock_pool {
90 union kmp_user_lock *next;
91 kmp_lock_index_t index;
92};
93
94typedef struct kmp_lock_pool kmp_lock_pool_t;
95
96
97extern void __kmp_validate_locks( void );
98
99
100// ----------------------------------------------------------------------------
101//
102// There are 5 lock implementations:
103//
104// 1. Test and set locks.
105// 2. futex locks (Linux* OS on x86 and Intel(R) Many Integrated Core architecture)
106// 3. Ticket (Lamport bakery) locks.
107// 4. Queuing locks (with separate spin fields).
108// 5. DRPA (Dynamically Reconfigurable Distributed Polling Area) locks
109//
110// and 3 lock purposes:
111//
112// 1. Bootstrap locks -- Used for a few locks available at library startup-shutdown time.
113// These do not require non-negative global thread ID's.
114// 2. Internal RTL locks -- Used everywhere else in the RTL
115// 3. User locks (includes critical sections)
116//
117// ----------------------------------------------------------------------------
118
119
120// ============================================================================
121// Lock implementations.
122// ============================================================================
123
124
125// ----------------------------------------------------------------------------
126// Test and set locks.
127//
128// Non-nested test and set locks differ from the other lock kinds (except
129// futex) in that we use the memory allocated by the compiler for the lock,
130// rather than a pointer to it.
131//
132// On lin32, lin_32e, and win_32, the space allocated may be as small as 4
133// bytes, so we have to use a lock table for nested locks, and avoid accessing
134// the depth_locked field for non-nested locks.
135//
136// Information normally available to the tools, such as lock location,
137// lock usage (normal lock vs. critical section), etc. is not available with
138// test and set locks.
139// ----------------------------------------------------------------------------
140
141struct kmp_base_tas_lock {
142 volatile kmp_int32 poll; // 0 => unlocked
143 // locked: (gtid+1) of owning thread
144 kmp_int32 depth_locked; // depth locked, for nested locks only
145};
146
147typedef struct kmp_base_tas_lock kmp_base_tas_lock_t;
148
149union kmp_tas_lock {
150 kmp_base_tas_lock_t lk;
151 kmp_lock_pool_t pool; // make certain struct is large enough
152 double lk_align; // use worst case alignment
153 // no cache line padding
154};
155
156typedef union kmp_tas_lock kmp_tas_lock_t;
157
158//
159// Static initializer for test and set lock variables. Usage:
160// kmp_tas_lock_t xlock = KMP_TAS_LOCK_INITIALIZER( xlock );
161//
162#define KMP_TAS_LOCK_INITIALIZER( lock ) { { 0, 0 } }
163
164extern void __kmp_acquire_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
165extern int __kmp_test_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
166extern void __kmp_release_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
167extern void __kmp_init_tas_lock( kmp_tas_lock_t *lck );
168extern void __kmp_destroy_tas_lock( kmp_tas_lock_t *lck );
169
170extern void __kmp_acquire_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
171extern int __kmp_test_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
172extern void __kmp_release_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
173extern void __kmp_init_nested_tas_lock( kmp_tas_lock_t *lck );
174extern void __kmp_destroy_nested_tas_lock( kmp_tas_lock_t *lck );
175
176
Jim Cownie181b4bb2013-12-23 17:28:57 +0000177#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000178
179// ----------------------------------------------------------------------------
180// futex locks. futex locks are only available on Linux* OS.
181//
182// Like non-nested test and set lock, non-nested futex locks use the memory
183// allocated by the compiler for the lock, rather than a pointer to it.
184//
185// Information normally available to the tools, such as lock location,
186// lock usage (normal lock vs. critical section), etc. is not available with
187// test and set locks. With non-nested futex locks, the lock owner is not
188// even available.
189// ----------------------------------------------------------------------------
190
191struct kmp_base_futex_lock {
192 volatile kmp_int32 poll; // 0 => unlocked
193 // 2*(gtid+1) of owning thread, 0 if unlocked
194 // locked: (gtid+1) of owning thread
195 kmp_int32 depth_locked; // depth locked, for nested locks only
196};
197
198typedef struct kmp_base_futex_lock kmp_base_futex_lock_t;
199
200union kmp_futex_lock {
201 kmp_base_futex_lock_t lk;
202 kmp_lock_pool_t pool; // make certain struct is large enough
203 double lk_align; // use worst case alignment
204 // no cache line padding
205};
206
207typedef union kmp_futex_lock kmp_futex_lock_t;
208
209//
210// Static initializer for futex lock variables. Usage:
211// kmp_futex_lock_t xlock = KMP_FUTEX_LOCK_INITIALIZER( xlock );
212//
213#define KMP_FUTEX_LOCK_INITIALIZER( lock ) { { 0, 0 } }
214
215extern void __kmp_acquire_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
216extern int __kmp_test_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
217extern void __kmp_release_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
218extern void __kmp_init_futex_lock( kmp_futex_lock_t *lck );
219extern void __kmp_destroy_futex_lock( kmp_futex_lock_t *lck );
220
221extern void __kmp_acquire_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
222extern int __kmp_test_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
223extern void __kmp_release_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
224extern void __kmp_init_nested_futex_lock( kmp_futex_lock_t *lck );
225extern void __kmp_destroy_nested_futex_lock( kmp_futex_lock_t *lck );
226
Jim Cownie181b4bb2013-12-23 17:28:57 +0000227#endif // KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000228
229
230// ----------------------------------------------------------------------------
231// Ticket locks.
232// ----------------------------------------------------------------------------
233
234struct kmp_base_ticket_lock {
235 // `initialized' must be the first entry in the lock data structure!
236 volatile union kmp_ticket_lock * initialized; // points to the lock union if in initialized state
237 ident_t const * location; // Source code location of omp_init_lock().
238 volatile kmp_uint32 next_ticket; // ticket number to give to next thread which acquires
239 volatile kmp_uint32 now_serving; // ticket number for thread which holds the lock
240 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
241 kmp_int32 depth_locked; // depth locked, for nested locks only
242 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
243};
244
245typedef struct kmp_base_ticket_lock kmp_base_ticket_lock_t;
246
247union KMP_ALIGN_CACHE kmp_ticket_lock {
248 kmp_base_ticket_lock_t lk; // This field must be first to allow static initializing.
249 kmp_lock_pool_t pool;
250 double lk_align; // use worst case alignment
251 char lk_pad[ KMP_PAD( kmp_base_ticket_lock_t, CACHE_LINE ) ];
252};
253
254typedef union kmp_ticket_lock kmp_ticket_lock_t;
255
256//
257// Static initializer for simple ticket lock variables. Usage:
258// kmp_ticket_lock_t xlock = KMP_TICKET_LOCK_INITIALIZER( xlock );
259// Note the macro argument. It is important to make var properly initialized.
260//
261#define KMP_TICKET_LOCK_INITIALIZER( lock ) { { (kmp_ticket_lock_t *) & (lock), NULL, 0, 0, 0, -1 } }
262
263extern void __kmp_acquire_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
264extern int __kmp_test_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
265extern int __kmp_test_ticket_lock_with_cheks( kmp_ticket_lock_t *lck, kmp_int32 gtid );
266extern void __kmp_release_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
267extern void __kmp_init_ticket_lock( kmp_ticket_lock_t *lck );
268extern void __kmp_destroy_ticket_lock( kmp_ticket_lock_t *lck );
269
270extern void __kmp_acquire_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
271extern int __kmp_test_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
272extern void __kmp_release_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
273extern void __kmp_init_nested_ticket_lock( kmp_ticket_lock_t *lck );
274extern void __kmp_destroy_nested_ticket_lock( kmp_ticket_lock_t *lck );
275
276
277// ----------------------------------------------------------------------------
278// Queuing locks.
279// ----------------------------------------------------------------------------
280
281#if KMP_USE_ADAPTIVE_LOCKS
282
283struct kmp_adaptive_lock;
284
285typedef struct kmp_adaptive_lock kmp_adaptive_lock_t;
286
287#if KMP_DEBUG_ADAPTIVE_LOCKS
288
289struct kmp_adaptive_lock_statistics {
290 /* So we can get stats from locks that haven't been destroyed. */
291 kmp_adaptive_lock_t * next;
292 kmp_adaptive_lock_t * prev;
293
294 /* Other statistics */
295 kmp_uint32 successfulSpeculations;
296 kmp_uint32 hardFailedSpeculations;
297 kmp_uint32 softFailedSpeculations;
298 kmp_uint32 nonSpeculativeAcquires;
299 kmp_uint32 nonSpeculativeAcquireAttempts;
300 kmp_uint32 lemmingYields;
301};
302
303typedef struct kmp_adaptive_lock_statistics kmp_adaptive_lock_statistics_t;
304
305extern void __kmp_print_speculative_stats();
306extern void __kmp_init_speculative_stats();
307
308#endif // KMP_DEBUG_ADAPTIVE_LOCKS
309
310struct kmp_adaptive_lock
311{
312 /* Values used for adaptivity.
313 * Although these are accessed from multiple threads we don't access them atomically,
314 * because if we miss updates it probably doesn't matter much. (It just affects our
315 * decision about whether to try speculation on the lock).
316 */
317 kmp_uint32 volatile badness;
318 kmp_uint32 volatile acquire_attempts;
319 /* Parameters of the lock. */
320 kmp_uint32 max_badness;
321 kmp_uint32 max_soft_retries;
322
323#if KMP_DEBUG_ADAPTIVE_LOCKS
324 kmp_adaptive_lock_statistics_t volatile stats;
325#endif
326};
327
328#endif // KMP_USE_ADAPTIVE_LOCKS
329
330
331struct kmp_base_queuing_lock {
332
333 // `initialized' must be the first entry in the lock data structure!
334 volatile union kmp_queuing_lock *initialized; // Points to the lock union if in initialized state.
335
336 ident_t const * location; // Source code location of omp_init_lock().
337
338 KMP_ALIGN( 8 ) // tail_id must be 8-byte aligned!
339
340 volatile kmp_int32 tail_id; // (gtid+1) of thread at tail of wait queue, 0 if empty
341 // Must be no padding here since head/tail used in 8-byte CAS
342 volatile kmp_int32 head_id; // (gtid+1) of thread at head of wait queue, 0 if empty
343 // Decl order assumes little endian
344 // bakery-style lock
345 volatile kmp_uint32 next_ticket; // ticket number to give to next thread which acquires
346 volatile kmp_uint32 now_serving; // ticket number for thread which holds the lock
347 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
348 kmp_int32 depth_locked; // depth locked, for nested locks only
349
350 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
351#if KMP_USE_ADAPTIVE_LOCKS
352 KMP_ALIGN(CACHE_LINE)
353 kmp_adaptive_lock_t adaptive; // Information for the speculative adaptive lock
354#endif
355};
356
357typedef struct kmp_base_queuing_lock kmp_base_queuing_lock_t;
358
359KMP_BUILD_ASSERT( offsetof( kmp_base_queuing_lock_t, tail_id ) % 8 == 0 );
360
361union KMP_ALIGN_CACHE kmp_queuing_lock {
362 kmp_base_queuing_lock_t lk; // This field must be first to allow static initializing.
363 kmp_lock_pool_t pool;
364 double lk_align; // use worst case alignment
365 char lk_pad[ KMP_PAD( kmp_base_queuing_lock_t, CACHE_LINE ) ];
366};
367
368typedef union kmp_queuing_lock kmp_queuing_lock_t;
369
370extern void __kmp_acquire_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
371extern int __kmp_test_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
372extern void __kmp_release_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
373extern void __kmp_init_queuing_lock( kmp_queuing_lock_t *lck );
374extern void __kmp_destroy_queuing_lock( kmp_queuing_lock_t *lck );
375
376extern void __kmp_acquire_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
377extern int __kmp_test_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
378extern void __kmp_release_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
379extern void __kmp_init_nested_queuing_lock( kmp_queuing_lock_t *lck );
380extern void __kmp_destroy_nested_queuing_lock( kmp_queuing_lock_t *lck );
381
382
383// ----------------------------------------------------------------------------
384// DRDPA ticket locks.
385// ----------------------------------------------------------------------------
386
387struct kmp_base_drdpa_lock {
388 //
389 // All of the fields on the first cache line are only written when
390 // initializing or reconfiguring the lock. These are relatively rare
391 // operations, so data from the first cache line will usually stay
392 // resident in the cache of each thread trying to acquire the lock.
393 //
394 // initialized must be the first entry in the lock data structure!
395 //
396 KMP_ALIGN_CACHE
397
398 volatile union kmp_drdpa_lock * initialized; // points to the lock union if in initialized state
399 ident_t const * location; // Source code location of omp_init_lock().
400 volatile struct kmp_lock_poll {
401 kmp_uint64 poll;
402 } * volatile polls;
403 volatile kmp_uint64 mask; // is 2**num_polls-1 for mod op
404 kmp_uint64 cleanup_ticket; // thread with cleanup ticket
405 volatile struct kmp_lock_poll * old_polls; // will deallocate old_polls
406 kmp_uint32 num_polls; // must be power of 2
407
408 //
409 // next_ticket it needs to exist in a separate cache line, as it is
410 // invalidated every time a thread takes a new ticket.
411 //
412 KMP_ALIGN_CACHE
413
414 volatile kmp_uint64 next_ticket;
415
416 //
417 // now_serving is used to store our ticket value while we hold the lock.
Alp Toker8f2d3f02014-02-24 10:40:15 +0000418 // It has a slightly different meaning in the DRDPA ticket locks (where
Jim Cownie5e8470a2013-09-27 10:38:44 +0000419 // it is written by the acquiring thread) than it does in the simple
420 // ticket locks (where it is written by the releasing thread).
421 //
422 // Since now_serving is only read an written in the critical section,
423 // it is non-volatile, but it needs to exist on a separate cache line,
424 // as it is invalidated at every lock acquire.
425 //
426 // Likewise, the vars used for nested locks (owner_id and depth_locked)
427 // are only written by the thread owning the lock, so they are put in
428 // this cache line. owner_id is read by other threads, so it must be
429 // declared volatile.
430 //
431 KMP_ALIGN_CACHE
432
433 kmp_uint64 now_serving; // doesn't have to be volatile
434 volatile kmp_uint32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
435 kmp_int32 depth_locked; // depth locked
436 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
437};
438
439typedef struct kmp_base_drdpa_lock kmp_base_drdpa_lock_t;
440
441union KMP_ALIGN_CACHE kmp_drdpa_lock {
442 kmp_base_drdpa_lock_t lk; // This field must be first to allow static initializing. */
443 kmp_lock_pool_t pool;
444 double lk_align; // use worst case alignment
445 char lk_pad[ KMP_PAD( kmp_base_drdpa_lock_t, CACHE_LINE ) ];
446};
447
448typedef union kmp_drdpa_lock kmp_drdpa_lock_t;
449
450extern void __kmp_acquire_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
451extern int __kmp_test_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
452extern void __kmp_release_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
453extern void __kmp_init_drdpa_lock( kmp_drdpa_lock_t *lck );
454extern void __kmp_destroy_drdpa_lock( kmp_drdpa_lock_t *lck );
455
456extern void __kmp_acquire_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
457extern int __kmp_test_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
458extern void __kmp_release_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
459extern void __kmp_init_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
460extern void __kmp_destroy_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
461
462
463// ============================================================================
464// Lock purposes.
465// ============================================================================
466
467
468// ----------------------------------------------------------------------------
469// Bootstrap locks.
470// ----------------------------------------------------------------------------
471
472// Bootstrap locks -- very few locks used at library initialization time.
473// Bootstrap locks are currently implemented as ticket locks.
474// They could also be implemented as test and set lock, but cannot be
475// implemented with other lock kinds as they require gtids which are not
476// available at initialization time.
477
478typedef kmp_ticket_lock_t kmp_bootstrap_lock_t;
479
480#define KMP_BOOTSTRAP_LOCK_INITIALIZER( lock ) KMP_TICKET_LOCK_INITIALIZER( (lock) )
481
Jim Cownie181b4bb2013-12-23 17:28:57 +0000482static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000483__kmp_acquire_bootstrap_lock( kmp_bootstrap_lock_t *lck )
484{
485 __kmp_acquire_ticket_lock( lck, KMP_GTID_DNE );
486}
487
Jim Cownie181b4bb2013-12-23 17:28:57 +0000488static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000489__kmp_test_bootstrap_lock( kmp_bootstrap_lock_t *lck )
490{
491 return __kmp_test_ticket_lock( lck, KMP_GTID_DNE );
492}
493
Jim Cownie181b4bb2013-12-23 17:28:57 +0000494static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000495__kmp_release_bootstrap_lock( kmp_bootstrap_lock_t *lck )
496{
497 __kmp_release_ticket_lock( lck, KMP_GTID_DNE );
498}
499
Jim Cownie181b4bb2013-12-23 17:28:57 +0000500static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000501__kmp_init_bootstrap_lock( kmp_bootstrap_lock_t *lck )
502{
503 __kmp_init_ticket_lock( lck );
504}
505
Jim Cownie181b4bb2013-12-23 17:28:57 +0000506static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000507__kmp_destroy_bootstrap_lock( kmp_bootstrap_lock_t *lck )
508{
509 __kmp_destroy_ticket_lock( lck );
510}
511
512
513// ----------------------------------------------------------------------------
514// Internal RTL locks.
515// ----------------------------------------------------------------------------
516
517//
518// Internal RTL locks are also implemented as ticket locks, for now.
519//
520// FIXME - We should go through and figure out which lock kind works best for
Jim Cownie3051f972014-08-07 10:12:54 +0000521// each internal lock, and use the type declaration and function calls for
Jim Cownie5e8470a2013-09-27 10:38:44 +0000522// that explicit lock kind (and get rid of this section).
523//
524
525typedef kmp_ticket_lock_t kmp_lock_t;
526
Jim Cownie181b4bb2013-12-23 17:28:57 +0000527static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000528__kmp_acquire_lock( kmp_lock_t *lck, kmp_int32 gtid )
529{
530 __kmp_acquire_ticket_lock( lck, gtid );
531}
532
Jim Cownie181b4bb2013-12-23 17:28:57 +0000533static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000534__kmp_test_lock( kmp_lock_t *lck, kmp_int32 gtid )
535{
536 return __kmp_test_ticket_lock( lck, gtid );
537}
538
Jim Cownie181b4bb2013-12-23 17:28:57 +0000539static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000540__kmp_release_lock( kmp_lock_t *lck, kmp_int32 gtid )
541{
542 __kmp_release_ticket_lock( lck, gtid );
543}
544
Jim Cownie181b4bb2013-12-23 17:28:57 +0000545static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000546__kmp_init_lock( kmp_lock_t *lck )
547{
548 __kmp_init_ticket_lock( lck );
549}
550
Jim Cownie181b4bb2013-12-23 17:28:57 +0000551static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000552__kmp_destroy_lock( kmp_lock_t *lck )
553{
554 __kmp_destroy_ticket_lock( lck );
555}
556
557
558// ----------------------------------------------------------------------------
559// User locks.
560// ----------------------------------------------------------------------------
561
562//
563// Do not allocate objects of type union kmp_user_lock!!!
564// This will waste space unless __kmp_user_lock_kind == lk_drdpa.
565// Instead, check the value of __kmp_user_lock_kind and allocate objects of
566// the type of the appropriate union member, and cast their addresses to
567// kmp_user_lock_p.
568//
569
570enum kmp_lock_kind {
571 lk_default = 0,
572 lk_tas,
Jim Cownie181b4bb2013-12-23 17:28:57 +0000573#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000574 lk_futex,
575#endif
576 lk_ticket,
577 lk_queuing,
578 lk_drdpa,
579#if KMP_USE_ADAPTIVE_LOCKS
580 lk_adaptive
581#endif // KMP_USE_ADAPTIVE_LOCKS
582};
583
584typedef enum kmp_lock_kind kmp_lock_kind_t;
585
586extern kmp_lock_kind_t __kmp_user_lock_kind;
587
588union kmp_user_lock {
589 kmp_tas_lock_t tas;
Jim Cownie181b4bb2013-12-23 17:28:57 +0000590#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000591 kmp_futex_lock_t futex;
592#endif
593 kmp_ticket_lock_t ticket;
594 kmp_queuing_lock_t queuing;
595 kmp_drdpa_lock_t drdpa;
596#if KMP_USE_ADAPTIVE_LOCKS
597 kmp_adaptive_lock_t adaptive;
598#endif // KMP_USE_ADAPTIVE_LOCKS
599 kmp_lock_pool_t pool;
600};
601
602typedef union kmp_user_lock *kmp_user_lock_p;
603
604extern size_t __kmp_base_user_lock_size;
605extern size_t __kmp_user_lock_size;
606
607extern kmp_int32 ( *__kmp_get_user_lock_owner_ )( kmp_user_lock_p lck );
608
Jim Cownie181b4bb2013-12-23 17:28:57 +0000609static inline kmp_int32
Jim Cownie5e8470a2013-09-27 10:38:44 +0000610__kmp_get_user_lock_owner( kmp_user_lock_p lck )
611{
612 KMP_DEBUG_ASSERT( __kmp_get_user_lock_owner_ != NULL );
613 return ( *__kmp_get_user_lock_owner_ )( lck );
614}
615
616extern void ( *__kmp_acquire_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
617
Jim Cownie181b4bb2013-12-23 17:28:57 +0000618#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000619
620#define __kmp_acquire_user_lock_with_checks(lck,gtid) \
621 if (__kmp_user_lock_kind == lk_tas) { \
622 if ( __kmp_env_consistency_check ) { \
623 char const * const func = "omp_set_lock"; \
624 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE ) \
625 && lck->tas.lk.depth_locked != -1 ) { \
626 KMP_FATAL( LockNestableUsedAsSimple, func ); \
627 } \
628 if ( ( gtid >= 0 ) && ( lck->tas.lk.poll - 1 == gtid ) ) { \
629 KMP_FATAL( LockIsAlreadyOwned, func ); \
630 } \
631 } \
632 if ( ( lck->tas.lk.poll != 0 ) || \
633 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
634 kmp_uint32 spins; \
635 KMP_FSYNC_PREPARE( lck ); \
636 KMP_INIT_YIELD( spins ); \
637 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
638 KMP_YIELD( TRUE ); \
639 } else { \
640 KMP_YIELD_SPIN( spins ); \
641 } \
642 while ( ( lck->tas.lk.poll != 0 ) || \
643 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
644 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
645 KMP_YIELD( TRUE ); \
646 } else { \
647 KMP_YIELD_SPIN( spins ); \
648 } \
649 } \
650 } \
651 KMP_FSYNC_ACQUIRED( lck ); \
652 } else { \
653 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL ); \
654 ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid ); \
655 }
656
657#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000658static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000659__kmp_acquire_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
660{
661 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL );
662 ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid );
663}
664#endif
665
666extern int ( *__kmp_test_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
667
Jim Cownie181b4bb2013-12-23 17:28:57 +0000668#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000669
670#include "kmp_i18n.h" /* AC: KMP_FATAL definition */
671extern int __kmp_env_consistency_check; /* AC: copy from kmp.h here */
Jim Cownie181b4bb2013-12-23 17:28:57 +0000672static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000673__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
674{
675 if ( __kmp_user_lock_kind == lk_tas ) {
676 if ( __kmp_env_consistency_check ) {
677 char const * const func = "omp_test_lock";
678 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE )
679 && lck->tas.lk.depth_locked != -1 ) {
680 KMP_FATAL( LockNestableUsedAsSimple, func );
681 }
682 }
683 return ( ( lck->tas.lk.poll == 0 ) &&
684 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
685 } else {
686 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
687 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
688 }
689}
690#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000691static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000692__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
693{
694 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
695 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
696}
697#endif
698
699extern void ( *__kmp_release_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
700
Jim Cownie181b4bb2013-12-23 17:28:57 +0000701static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000702__kmp_release_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
703{
704 KMP_DEBUG_ASSERT( __kmp_release_user_lock_with_checks_ != NULL );
705 ( *__kmp_release_user_lock_with_checks_ ) ( lck, gtid );
706}
707
708extern void ( *__kmp_init_user_lock_with_checks_ )( kmp_user_lock_p lck );
709
Jim Cownie181b4bb2013-12-23 17:28:57 +0000710static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000711__kmp_init_user_lock_with_checks( kmp_user_lock_p lck )
712{
713 KMP_DEBUG_ASSERT( __kmp_init_user_lock_with_checks_ != NULL );
714 ( *__kmp_init_user_lock_with_checks_ )( lck );
715}
716
717//
718// We need a non-checking version of destroy lock for when the RTL is
719// doing the cleanup as it can't always tell if the lock is nested or not.
720//
721extern void ( *__kmp_destroy_user_lock_ )( kmp_user_lock_p lck );
722
Jim Cownie181b4bb2013-12-23 17:28:57 +0000723static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000724__kmp_destroy_user_lock( kmp_user_lock_p lck )
725{
726 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_ != NULL );
727 ( *__kmp_destroy_user_lock_ )( lck );
728}
729
730extern void ( *__kmp_destroy_user_lock_with_checks_ )( kmp_user_lock_p lck );
731
Jim Cownie181b4bb2013-12-23 17:28:57 +0000732static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000733__kmp_destroy_user_lock_with_checks( kmp_user_lock_p lck )
734{
735 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_with_checks_ != NULL );
736 ( *__kmp_destroy_user_lock_with_checks_ )( lck );
737}
738
739extern void ( *__kmp_acquire_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
740
741#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
742
743#define __kmp_acquire_nested_user_lock_with_checks(lck,gtid) \
744 if (__kmp_user_lock_kind == lk_tas) { \
745 if ( __kmp_env_consistency_check ) { \
746 char const * const func = "omp_set_nest_lock"; \
747 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE ) \
748 && lck->tas.lk.depth_locked == -1 ) { \
749 KMP_FATAL( LockSimpleUsedAsNestable, func ); \
750 } \
751 } \
752 if ( lck->tas.lk.poll - 1 == gtid ) { \
753 lck->tas.lk.depth_locked += 1; \
754 } else { \
755 if ( ( lck->tas.lk.poll != 0 ) || \
756 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
757 kmp_uint32 spins; \
758 KMP_FSYNC_PREPARE( lck ); \
759 KMP_INIT_YIELD( spins ); \
760 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
761 KMP_YIELD( TRUE ); \
762 } else { \
763 KMP_YIELD_SPIN( spins ); \
764 } \
765 while ( ( lck->tas.lk.poll != 0 ) || \
766 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
767 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
768 KMP_YIELD( TRUE ); \
769 } else { \
770 KMP_YIELD_SPIN( spins ); \
771 } \
772 } \
773 } \
774 lck->tas.lk.depth_locked = 1; \
775 } \
776 KMP_FSYNC_ACQUIRED( lck ); \
777 } else { \
778 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL ); \
779 ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid ); \
780 }
781
782#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000783static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000784__kmp_acquire_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
785{
786 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL );
787 ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid );
788}
789#endif
790
791extern int ( *__kmp_test_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
792
793#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
Jim Cownie181b4bb2013-12-23 17:28:57 +0000794static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000795__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
796{
797 if ( __kmp_user_lock_kind == lk_tas ) {
798 int retval;
799 if ( __kmp_env_consistency_check ) {
800 char const * const func = "omp_test_nest_lock";
801 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE )
802 && lck->tas.lk.depth_locked == -1 ) {
803 KMP_FATAL( LockSimpleUsedAsNestable, func );
804 }
805 }
806 KMP_DEBUG_ASSERT( gtid >= 0 );
807 if ( lck->tas.lk.poll - 1 == gtid ) { /* __kmp_get_tas_lock_owner( lck ) == gtid */
808 return ++lck->tas.lk.depth_locked; /* same owner, depth increased */
809 }
810 retval = ( ( lck->tas.lk.poll == 0 ) &&
811 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
812 if ( retval ) {
813 KMP_MB();
814 lck->tas.lk.depth_locked = 1;
815 }
816 return retval;
817 } else {
818 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
819 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
820 }
821}
822#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000823static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000824__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
825{
826 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
827 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
828}
829#endif
830
831extern void ( *__kmp_release_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
832
Jim Cownie181b4bb2013-12-23 17:28:57 +0000833static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000834__kmp_release_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
835{
836 KMP_DEBUG_ASSERT( __kmp_release_nested_user_lock_with_checks_ != NULL );
837 ( *__kmp_release_nested_user_lock_with_checks_ )( lck, gtid );
838}
839
840extern void ( *__kmp_init_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
841
Jim Cownie181b4bb2013-12-23 17:28:57 +0000842static inline void __kmp_init_nested_user_lock_with_checks( kmp_user_lock_p lck )
Jim Cownie5e8470a2013-09-27 10:38:44 +0000843{
844 KMP_DEBUG_ASSERT( __kmp_init_nested_user_lock_with_checks_ != NULL );
845 ( *__kmp_init_nested_user_lock_with_checks_ )( lck );
846}
847
848extern void ( *__kmp_destroy_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
849
Jim Cownie181b4bb2013-12-23 17:28:57 +0000850static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000851__kmp_destroy_nested_user_lock_with_checks( kmp_user_lock_p lck )
852{
853 KMP_DEBUG_ASSERT( __kmp_destroy_nested_user_lock_with_checks_ != NULL );
854 ( *__kmp_destroy_nested_user_lock_with_checks_ )( lck );
855}
856
857//
858// user lock functions which do not necessarily exist for all lock kinds.
859//
860// The "set" functions usually have wrapper routines that check for a NULL set
861// function pointer and call it if non-NULL.
862//
863// In some cases, it makes sense to have a "get" wrapper function check for a
864// NULL get function pointer and return NULL / invalid value / error code if
865// the function pointer is NULL.
866//
867// In other cases, the calling code really should differentiate between an
868// unimplemented function and one that is implemented but returning NULL /
869// invalied value. If this is the case, no get function wrapper exists.
870//
871
872extern int ( *__kmp_is_user_lock_initialized_ )( kmp_user_lock_p lck );
873
874// no set function; fields set durining local allocation
875
876extern const ident_t * ( *__kmp_get_user_lock_location_ )( kmp_user_lock_p lck );
877
Jim Cownie181b4bb2013-12-23 17:28:57 +0000878static inline const ident_t *
Jim Cownie5e8470a2013-09-27 10:38:44 +0000879__kmp_get_user_lock_location( kmp_user_lock_p lck )
880{
881 if ( __kmp_get_user_lock_location_ != NULL ) {
882 return ( *__kmp_get_user_lock_location_ )( lck );
883 }
884 else {
885 return NULL;
886 }
887}
888
889extern void ( *__kmp_set_user_lock_location_ )( kmp_user_lock_p lck, const ident_t *loc );
890
Jim Cownie181b4bb2013-12-23 17:28:57 +0000891static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000892__kmp_set_user_lock_location( kmp_user_lock_p lck, const ident_t *loc )
893{
894 if ( __kmp_set_user_lock_location_ != NULL ) {
895 ( *__kmp_set_user_lock_location_ )( lck, loc );
896 }
897}
898
899extern kmp_lock_flags_t ( *__kmp_get_user_lock_flags_ )( kmp_user_lock_p lck );
900
901extern void ( *__kmp_set_user_lock_flags_ )( kmp_user_lock_p lck, kmp_lock_flags_t flags );
902
Jim Cownie181b4bb2013-12-23 17:28:57 +0000903static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000904__kmp_set_user_lock_flags( kmp_user_lock_p lck, kmp_lock_flags_t flags )
905{
906 if ( __kmp_set_user_lock_flags_ != NULL ) {
907 ( *__kmp_set_user_lock_flags_ )( lck, flags );
908 }
909}
910
911//
912// The fuction which sets up all of the vtbl pointers for kmp_user_lock_t.
913//
914extern void __kmp_set_user_lock_vptrs( kmp_lock_kind_t user_lock_kind );
915
916
917
918// ----------------------------------------------------------------------------
919// User lock table & lock allocation
920// ----------------------------------------------------------------------------
921
922/*
923 On 64-bit Linux* OS (and OS X*) GNU compiler allocates only 4 bytems memory for lock variable, which
924 is not enough to store a pointer, so we have to use lock indexes instead of pointers and
925 maintain lock table to map indexes to pointers.
926
927
928 Note: The first element of the table is not a pointer to lock! It is a pointer to previously
929 allocated table (or NULL if it is the first table).
930
931 Usage:
932
933 if ( OMP_LOCK_T_SIZE < sizeof( <lock> ) ) { // or OMP_NEST_LOCK_T_SIZE
934 Lock table is fully utilized. User locks are indexes, so table is
935 used on user lock operation.
936 Note: it may be the case (lin_32) that we don't need to use a lock
937 table for regular locks, but do need the table for nested locks.
938 }
939 else {
940 Lock table initialized but not actually used.
941 }
942*/
943
944struct kmp_lock_table {
945 kmp_lock_index_t used; // Number of used elements
946 kmp_lock_index_t allocated; // Number of allocated elements
947 kmp_user_lock_p * table; // Lock table.
948};
949
950typedef struct kmp_lock_table kmp_lock_table_t;
951
952extern kmp_lock_table_t __kmp_user_lock_table;
953extern kmp_user_lock_p __kmp_lock_pool;
954
955struct kmp_block_of_locks {
956 struct kmp_block_of_locks * next_block;
957 void * locks;
958};
959
960typedef struct kmp_block_of_locks kmp_block_of_locks_t;
961
962extern kmp_block_of_locks_t *__kmp_lock_blocks;
963extern int __kmp_num_locks_in_block;
964
Jim Cownie181b4bb2013-12-23 17:28:57 +0000965extern kmp_user_lock_p __kmp_user_lock_allocate( void **user_lock, kmp_int32 gtid, kmp_lock_flags_t flags );
Jim Cownie5e8470a2013-09-27 10:38:44 +0000966extern void __kmp_user_lock_free( void **user_lock, kmp_int32 gtid, kmp_user_lock_p lck );
967extern kmp_user_lock_p __kmp_lookup_user_lock( void **user_lock, char const *func );
968extern void __kmp_cleanup_user_locks();
969
970#define KMP_CHECK_USER_LOCK_INIT() \
971 { \
972 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
973 __kmp_acquire_bootstrap_lock( &__kmp_initz_lock ); \
974 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
975 TCW_4( __kmp_init_user_locks, TRUE ); \
976 } \
977 __kmp_release_bootstrap_lock( &__kmp_initz_lock ); \
978 } \
979 }
980
981#undef KMP_PAD
982#undef KMP_GTID_DNE
983
984#ifdef __cplusplus
985} // extern "C"
986#endif // __cplusplus
987
988#endif /* KMP_LOCK_H */
989