blob: d40763e2e96a74ca7e98b75dee13a1b87db29acb [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
2 * kmp_lock.h -- lock header file
Jim Cownie5e8470a2013-09-27 10:38:44 +00003 */
4
5
6//===----------------------------------------------------------------------===//
7//
8// The LLVM Compiler Infrastructure
9//
10// This file is dual licensed under the MIT and the University of Illinois Open
11// Source Licenses. See LICENSE.txt for details.
12//
13//===----------------------------------------------------------------------===//
14
15
16#ifndef KMP_LOCK_H
17#define KMP_LOCK_H
18
19#include <limits.h> // CHAR_BIT
20#include <stddef.h> // offsetof
21
22#include "kmp_os.h"
23#include "kmp_debug.h"
24
25#ifdef __cplusplus
26extern "C" {
27#endif // __cplusplus
28
29// ----------------------------------------------------------------------------
30// Have to copy these definitions from kmp.h because kmp.h cannot be included
31// due to circular dependencies. Will undef these at end of file.
32
33#define KMP_PAD(type, sz) (sizeof(type) + (sz - ((sizeof(type) - 1) % (sz)) - 1))
34#define KMP_GTID_DNE (-2)
35
36// Forward declaration of ident and ident_t
37
38struct ident;
39typedef struct ident ident_t;
40
41// End of copied code.
42// ----------------------------------------------------------------------------
43
44//
45// We need to know the size of the area we can assume that the compiler(s)
46// allocated for obects of type omp_lock_t and omp_nest_lock_t. The Intel
47// compiler always allocates a pointer-sized area, as does visual studio.
48//
49// gcc however, only allocates 4 bytes for regular locks, even on 64-bit
50// intel archs. It allocates at least 8 bytes for nested lock (more on
51// recent versions), but we are bounded by the pointer-sized chunks that
52// the Intel compiler allocates.
53//
54
55#if KMP_OS_LINUX && defined(KMP_GOMP_COMPAT)
56# define OMP_LOCK_T_SIZE sizeof(int)
57# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
58#else
59# define OMP_LOCK_T_SIZE sizeof(void *)
60# define OMP_NEST_LOCK_T_SIZE sizeof(void *)
61#endif
62
63//
64// The Intel compiler allocates a 32-byte chunk for a critical section.
65// Both gcc and visual studio only allocate enough space for a pointer.
66// Sometimes we know that the space was allocated by the Intel compiler.
67//
68#define OMP_CRITICAL_SIZE sizeof(void *)
69#define INTEL_CRITICAL_SIZE 32
70
71//
72// lock flags
73//
74typedef kmp_uint32 kmp_lock_flags_t;
75
76#define kmp_lf_critical_section 1
77
78//
79// When a lock table is used, the indices are of kmp_lock_index_t
80//
81typedef kmp_uint32 kmp_lock_index_t;
82
83//
84// When memory allocated for locks are on the lock pool (free list),
85// it is treated as structs of this type.
86//
87struct kmp_lock_pool {
88 union kmp_user_lock *next;
89 kmp_lock_index_t index;
90};
91
92typedef struct kmp_lock_pool kmp_lock_pool_t;
93
94
95extern void __kmp_validate_locks( void );
96
97
98// ----------------------------------------------------------------------------
99//
100// There are 5 lock implementations:
101//
102// 1. Test and set locks.
103// 2. futex locks (Linux* OS on x86 and Intel(R) Many Integrated Core architecture)
104// 3. Ticket (Lamport bakery) locks.
105// 4. Queuing locks (with separate spin fields).
106// 5. DRPA (Dynamically Reconfigurable Distributed Polling Area) locks
107//
108// and 3 lock purposes:
109//
110// 1. Bootstrap locks -- Used for a few locks available at library startup-shutdown time.
111// These do not require non-negative global thread ID's.
112// 2. Internal RTL locks -- Used everywhere else in the RTL
113// 3. User locks (includes critical sections)
114//
115// ----------------------------------------------------------------------------
116
117
118// ============================================================================
119// Lock implementations.
120// ============================================================================
121
122
123// ----------------------------------------------------------------------------
124// Test and set locks.
125//
126// Non-nested test and set locks differ from the other lock kinds (except
127// futex) in that we use the memory allocated by the compiler for the lock,
128// rather than a pointer to it.
129//
130// On lin32, lin_32e, and win_32, the space allocated may be as small as 4
131// bytes, so we have to use a lock table for nested locks, and avoid accessing
132// the depth_locked field for non-nested locks.
133//
134// Information normally available to the tools, such as lock location,
135// lock usage (normal lock vs. critical section), etc. is not available with
136// test and set locks.
137// ----------------------------------------------------------------------------
138
139struct kmp_base_tas_lock {
140 volatile kmp_int32 poll; // 0 => unlocked
141 // locked: (gtid+1) of owning thread
142 kmp_int32 depth_locked; // depth locked, for nested locks only
143};
144
145typedef struct kmp_base_tas_lock kmp_base_tas_lock_t;
146
147union kmp_tas_lock {
148 kmp_base_tas_lock_t lk;
149 kmp_lock_pool_t pool; // make certain struct is large enough
150 double lk_align; // use worst case alignment
151 // no cache line padding
152};
153
154typedef union kmp_tas_lock kmp_tas_lock_t;
155
156//
157// Static initializer for test and set lock variables. Usage:
158// kmp_tas_lock_t xlock = KMP_TAS_LOCK_INITIALIZER( xlock );
159//
160#define KMP_TAS_LOCK_INITIALIZER( lock ) { { 0, 0 } }
161
162extern void __kmp_acquire_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
163extern int __kmp_test_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
164extern void __kmp_release_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
165extern void __kmp_init_tas_lock( kmp_tas_lock_t *lck );
166extern void __kmp_destroy_tas_lock( kmp_tas_lock_t *lck );
167
168extern void __kmp_acquire_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
169extern int __kmp_test_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
170extern void __kmp_release_nested_tas_lock( kmp_tas_lock_t *lck, kmp_int32 gtid );
171extern void __kmp_init_nested_tas_lock( kmp_tas_lock_t *lck );
172extern void __kmp_destroy_nested_tas_lock( kmp_tas_lock_t *lck );
173
174
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000175#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000176
177// ----------------------------------------------------------------------------
178// futex locks. futex locks are only available on Linux* OS.
179//
180// Like non-nested test and set lock, non-nested futex locks use the memory
181// allocated by the compiler for the lock, rather than a pointer to it.
182//
183// Information normally available to the tools, such as lock location,
184// lock usage (normal lock vs. critical section), etc. is not available with
185// test and set locks. With non-nested futex locks, the lock owner is not
186// even available.
187// ----------------------------------------------------------------------------
188
189struct kmp_base_futex_lock {
190 volatile kmp_int32 poll; // 0 => unlocked
191 // 2*(gtid+1) of owning thread, 0 if unlocked
192 // locked: (gtid+1) of owning thread
193 kmp_int32 depth_locked; // depth locked, for nested locks only
194};
195
196typedef struct kmp_base_futex_lock kmp_base_futex_lock_t;
197
198union kmp_futex_lock {
199 kmp_base_futex_lock_t lk;
200 kmp_lock_pool_t pool; // make certain struct is large enough
201 double lk_align; // use worst case alignment
202 // no cache line padding
203};
204
205typedef union kmp_futex_lock kmp_futex_lock_t;
206
207//
208// Static initializer for futex lock variables. Usage:
209// kmp_futex_lock_t xlock = KMP_FUTEX_LOCK_INITIALIZER( xlock );
210//
211#define KMP_FUTEX_LOCK_INITIALIZER( lock ) { { 0, 0 } }
212
213extern void __kmp_acquire_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
214extern int __kmp_test_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
215extern void __kmp_release_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
216extern void __kmp_init_futex_lock( kmp_futex_lock_t *lck );
217extern void __kmp_destroy_futex_lock( kmp_futex_lock_t *lck );
218
219extern void __kmp_acquire_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
220extern int __kmp_test_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
221extern void __kmp_release_nested_futex_lock( kmp_futex_lock_t *lck, kmp_int32 gtid );
222extern void __kmp_init_nested_futex_lock( kmp_futex_lock_t *lck );
223extern void __kmp_destroy_nested_futex_lock( kmp_futex_lock_t *lck );
224
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000225#endif // KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000226
227
228// ----------------------------------------------------------------------------
229// Ticket locks.
230// ----------------------------------------------------------------------------
231
232struct kmp_base_ticket_lock {
233 // `initialized' must be the first entry in the lock data structure!
234 volatile union kmp_ticket_lock * initialized; // points to the lock union if in initialized state
235 ident_t const * location; // Source code location of omp_init_lock().
236 volatile kmp_uint32 next_ticket; // ticket number to give to next thread which acquires
237 volatile kmp_uint32 now_serving; // ticket number for thread which holds the lock
238 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
239 kmp_int32 depth_locked; // depth locked, for nested locks only
240 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
241};
242
243typedef struct kmp_base_ticket_lock kmp_base_ticket_lock_t;
244
245union KMP_ALIGN_CACHE kmp_ticket_lock {
246 kmp_base_ticket_lock_t lk; // This field must be first to allow static initializing.
247 kmp_lock_pool_t pool;
248 double lk_align; // use worst case alignment
249 char lk_pad[ KMP_PAD( kmp_base_ticket_lock_t, CACHE_LINE ) ];
250};
251
252typedef union kmp_ticket_lock kmp_ticket_lock_t;
253
254//
255// Static initializer for simple ticket lock variables. Usage:
256// kmp_ticket_lock_t xlock = KMP_TICKET_LOCK_INITIALIZER( xlock );
257// Note the macro argument. It is important to make var properly initialized.
258//
259#define KMP_TICKET_LOCK_INITIALIZER( lock ) { { (kmp_ticket_lock_t *) & (lock), NULL, 0, 0, 0, -1 } }
260
261extern void __kmp_acquire_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
262extern int __kmp_test_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
263extern int __kmp_test_ticket_lock_with_cheks( kmp_ticket_lock_t *lck, kmp_int32 gtid );
264extern void __kmp_release_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
265extern void __kmp_init_ticket_lock( kmp_ticket_lock_t *lck );
266extern void __kmp_destroy_ticket_lock( kmp_ticket_lock_t *lck );
267
268extern void __kmp_acquire_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
269extern int __kmp_test_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
270extern void __kmp_release_nested_ticket_lock( kmp_ticket_lock_t *lck, kmp_int32 gtid );
271extern void __kmp_init_nested_ticket_lock( kmp_ticket_lock_t *lck );
272extern void __kmp_destroy_nested_ticket_lock( kmp_ticket_lock_t *lck );
273
274
275// ----------------------------------------------------------------------------
276// Queuing locks.
277// ----------------------------------------------------------------------------
278
279#if KMP_USE_ADAPTIVE_LOCKS
280
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000281struct kmp_adaptive_lock_info;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000282
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000283typedef struct kmp_adaptive_lock_info kmp_adaptive_lock_info_t;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000284
285#if KMP_DEBUG_ADAPTIVE_LOCKS
286
287struct kmp_adaptive_lock_statistics {
288 /* So we can get stats from locks that haven't been destroyed. */
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000289 kmp_adaptive_lock_info_t * next;
290 kmp_adaptive_lock_info_t * prev;
Jim Cownie5e8470a2013-09-27 10:38:44 +0000291
292 /* Other statistics */
293 kmp_uint32 successfulSpeculations;
294 kmp_uint32 hardFailedSpeculations;
295 kmp_uint32 softFailedSpeculations;
296 kmp_uint32 nonSpeculativeAcquires;
297 kmp_uint32 nonSpeculativeAcquireAttempts;
298 kmp_uint32 lemmingYields;
299};
300
301typedef struct kmp_adaptive_lock_statistics kmp_adaptive_lock_statistics_t;
302
303extern void __kmp_print_speculative_stats();
304extern void __kmp_init_speculative_stats();
305
306#endif // KMP_DEBUG_ADAPTIVE_LOCKS
307
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000308struct kmp_adaptive_lock_info
Jim Cownie5e8470a2013-09-27 10:38:44 +0000309{
310 /* Values used for adaptivity.
311 * Although these are accessed from multiple threads we don't access them atomically,
312 * because if we miss updates it probably doesn't matter much. (It just affects our
313 * decision about whether to try speculation on the lock).
314 */
315 kmp_uint32 volatile badness;
316 kmp_uint32 volatile acquire_attempts;
317 /* Parameters of the lock. */
318 kmp_uint32 max_badness;
319 kmp_uint32 max_soft_retries;
320
321#if KMP_DEBUG_ADAPTIVE_LOCKS
322 kmp_adaptive_lock_statistics_t volatile stats;
323#endif
324};
325
326#endif // KMP_USE_ADAPTIVE_LOCKS
327
328
329struct kmp_base_queuing_lock {
330
331 // `initialized' must be the first entry in the lock data structure!
332 volatile union kmp_queuing_lock *initialized; // Points to the lock union if in initialized state.
333
334 ident_t const * location; // Source code location of omp_init_lock().
335
336 KMP_ALIGN( 8 ) // tail_id must be 8-byte aligned!
337
338 volatile kmp_int32 tail_id; // (gtid+1) of thread at tail of wait queue, 0 if empty
339 // Must be no padding here since head/tail used in 8-byte CAS
340 volatile kmp_int32 head_id; // (gtid+1) of thread at head of wait queue, 0 if empty
341 // Decl order assumes little endian
342 // bakery-style lock
343 volatile kmp_uint32 next_ticket; // ticket number to give to next thread which acquires
344 volatile kmp_uint32 now_serving; // ticket number for thread which holds the lock
345 volatile kmp_int32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
346 kmp_int32 depth_locked; // depth locked, for nested locks only
347
348 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
Jim Cownie5e8470a2013-09-27 10:38:44 +0000349};
350
351typedef struct kmp_base_queuing_lock kmp_base_queuing_lock_t;
352
353KMP_BUILD_ASSERT( offsetof( kmp_base_queuing_lock_t, tail_id ) % 8 == 0 );
354
355union KMP_ALIGN_CACHE kmp_queuing_lock {
356 kmp_base_queuing_lock_t lk; // This field must be first to allow static initializing.
357 kmp_lock_pool_t pool;
358 double lk_align; // use worst case alignment
359 char lk_pad[ KMP_PAD( kmp_base_queuing_lock_t, CACHE_LINE ) ];
360};
361
362typedef union kmp_queuing_lock kmp_queuing_lock_t;
363
364extern void __kmp_acquire_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
365extern int __kmp_test_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
366extern void __kmp_release_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
367extern void __kmp_init_queuing_lock( kmp_queuing_lock_t *lck );
368extern void __kmp_destroy_queuing_lock( kmp_queuing_lock_t *lck );
369
370extern void __kmp_acquire_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
371extern int __kmp_test_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
372extern void __kmp_release_nested_queuing_lock( kmp_queuing_lock_t *lck, kmp_int32 gtid );
373extern void __kmp_init_nested_queuing_lock( kmp_queuing_lock_t *lck );
374extern void __kmp_destroy_nested_queuing_lock( kmp_queuing_lock_t *lck );
375
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000376#if KMP_USE_ADAPTIVE_LOCKS
377
378// ----------------------------------------------------------------------------
379// Adaptive locks.
380// ----------------------------------------------------------------------------
381struct kmp_base_adaptive_lock {
382 kmp_base_queuing_lock qlk;
383 KMP_ALIGN(CACHE_LINE)
384 kmp_adaptive_lock_info_t adaptive; // Information for the speculative adaptive lock
385};
386
387typedef struct kmp_base_adaptive_lock kmp_base_adaptive_lock_t;
388
389union KMP_ALIGN_CACHE kmp_adaptive_lock {
390 kmp_base_adaptive_lock_t lk;
391 kmp_lock_pool_t pool;
392 double lk_align;
393 char lk_pad[ KMP_PAD(kmp_base_adaptive_lock_t, CACHE_LINE) ];
394};
395typedef union kmp_adaptive_lock kmp_adaptive_lock_t;
396
397# define GET_QLK_PTR(l) ((kmp_queuing_lock_t *) & (l)->lk.qlk)
398
399#endif // KMP_USE_ADAPTIVE_LOCKS
Jim Cownie5e8470a2013-09-27 10:38:44 +0000400
401// ----------------------------------------------------------------------------
402// DRDPA ticket locks.
403// ----------------------------------------------------------------------------
404
405struct kmp_base_drdpa_lock {
406 //
407 // All of the fields on the first cache line are only written when
408 // initializing or reconfiguring the lock. These are relatively rare
409 // operations, so data from the first cache line will usually stay
410 // resident in the cache of each thread trying to acquire the lock.
411 //
412 // initialized must be the first entry in the lock data structure!
413 //
414 KMP_ALIGN_CACHE
415
416 volatile union kmp_drdpa_lock * initialized; // points to the lock union if in initialized state
417 ident_t const * location; // Source code location of omp_init_lock().
418 volatile struct kmp_lock_poll {
419 kmp_uint64 poll;
420 } * volatile polls;
421 volatile kmp_uint64 mask; // is 2**num_polls-1 for mod op
422 kmp_uint64 cleanup_ticket; // thread with cleanup ticket
423 volatile struct kmp_lock_poll * old_polls; // will deallocate old_polls
424 kmp_uint32 num_polls; // must be power of 2
425
426 //
427 // next_ticket it needs to exist in a separate cache line, as it is
428 // invalidated every time a thread takes a new ticket.
429 //
430 KMP_ALIGN_CACHE
431
432 volatile kmp_uint64 next_ticket;
433
434 //
435 // now_serving is used to store our ticket value while we hold the lock.
Alp Toker8f2d3f02014-02-24 10:40:15 +0000436 // It has a slightly different meaning in the DRDPA ticket locks (where
Jim Cownie5e8470a2013-09-27 10:38:44 +0000437 // it is written by the acquiring thread) than it does in the simple
438 // ticket locks (where it is written by the releasing thread).
439 //
440 // Since now_serving is only read an written in the critical section,
441 // it is non-volatile, but it needs to exist on a separate cache line,
442 // as it is invalidated at every lock acquire.
443 //
444 // Likewise, the vars used for nested locks (owner_id and depth_locked)
445 // are only written by the thread owning the lock, so they are put in
446 // this cache line. owner_id is read by other threads, so it must be
447 // declared volatile.
448 //
449 KMP_ALIGN_CACHE
450
451 kmp_uint64 now_serving; // doesn't have to be volatile
452 volatile kmp_uint32 owner_id; // (gtid+1) of owning thread, 0 if unlocked
453 kmp_int32 depth_locked; // depth locked
454 kmp_lock_flags_t flags; // lock specifics, e.g. critical section lock
455};
456
457typedef struct kmp_base_drdpa_lock kmp_base_drdpa_lock_t;
458
459union KMP_ALIGN_CACHE kmp_drdpa_lock {
460 kmp_base_drdpa_lock_t lk; // This field must be first to allow static initializing. */
461 kmp_lock_pool_t pool;
462 double lk_align; // use worst case alignment
463 char lk_pad[ KMP_PAD( kmp_base_drdpa_lock_t, CACHE_LINE ) ];
464};
465
466typedef union kmp_drdpa_lock kmp_drdpa_lock_t;
467
468extern void __kmp_acquire_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
469extern int __kmp_test_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
470extern void __kmp_release_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
471extern void __kmp_init_drdpa_lock( kmp_drdpa_lock_t *lck );
472extern void __kmp_destroy_drdpa_lock( kmp_drdpa_lock_t *lck );
473
474extern void __kmp_acquire_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
475extern int __kmp_test_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
476extern void __kmp_release_nested_drdpa_lock( kmp_drdpa_lock_t *lck, kmp_int32 gtid );
477extern void __kmp_init_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
478extern void __kmp_destroy_nested_drdpa_lock( kmp_drdpa_lock_t *lck );
479
480
481// ============================================================================
482// Lock purposes.
483// ============================================================================
484
485
486// ----------------------------------------------------------------------------
487// Bootstrap locks.
488// ----------------------------------------------------------------------------
489
490// Bootstrap locks -- very few locks used at library initialization time.
491// Bootstrap locks are currently implemented as ticket locks.
492// They could also be implemented as test and set lock, but cannot be
493// implemented with other lock kinds as they require gtids which are not
494// available at initialization time.
495
496typedef kmp_ticket_lock_t kmp_bootstrap_lock_t;
497
498#define KMP_BOOTSTRAP_LOCK_INITIALIZER( lock ) KMP_TICKET_LOCK_INITIALIZER( (lock) )
499
Jim Cownie181b4bb2013-12-23 17:28:57 +0000500static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000501__kmp_acquire_bootstrap_lock( kmp_bootstrap_lock_t *lck )
502{
503 __kmp_acquire_ticket_lock( lck, KMP_GTID_DNE );
504}
505
Jim Cownie181b4bb2013-12-23 17:28:57 +0000506static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000507__kmp_test_bootstrap_lock( kmp_bootstrap_lock_t *lck )
508{
509 return __kmp_test_ticket_lock( lck, KMP_GTID_DNE );
510}
511
Jim Cownie181b4bb2013-12-23 17:28:57 +0000512static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000513__kmp_release_bootstrap_lock( kmp_bootstrap_lock_t *lck )
514{
515 __kmp_release_ticket_lock( lck, KMP_GTID_DNE );
516}
517
Jim Cownie181b4bb2013-12-23 17:28:57 +0000518static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000519__kmp_init_bootstrap_lock( kmp_bootstrap_lock_t *lck )
520{
521 __kmp_init_ticket_lock( lck );
522}
523
Jim Cownie181b4bb2013-12-23 17:28:57 +0000524static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000525__kmp_destroy_bootstrap_lock( kmp_bootstrap_lock_t *lck )
526{
527 __kmp_destroy_ticket_lock( lck );
528}
529
530
531// ----------------------------------------------------------------------------
532// Internal RTL locks.
533// ----------------------------------------------------------------------------
534
535//
536// Internal RTL locks are also implemented as ticket locks, for now.
537//
538// FIXME - We should go through and figure out which lock kind works best for
Jim Cownie3051f972014-08-07 10:12:54 +0000539// each internal lock, and use the type declaration and function calls for
Jim Cownie5e8470a2013-09-27 10:38:44 +0000540// that explicit lock kind (and get rid of this section).
541//
542
543typedef kmp_ticket_lock_t kmp_lock_t;
544
Jim Cownie181b4bb2013-12-23 17:28:57 +0000545static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000546__kmp_acquire_lock( kmp_lock_t *lck, kmp_int32 gtid )
547{
548 __kmp_acquire_ticket_lock( lck, gtid );
549}
550
Jim Cownie181b4bb2013-12-23 17:28:57 +0000551static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000552__kmp_test_lock( kmp_lock_t *lck, kmp_int32 gtid )
553{
554 return __kmp_test_ticket_lock( lck, gtid );
555}
556
Jim Cownie181b4bb2013-12-23 17:28:57 +0000557static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000558__kmp_release_lock( kmp_lock_t *lck, kmp_int32 gtid )
559{
560 __kmp_release_ticket_lock( lck, gtid );
561}
562
Jim Cownie181b4bb2013-12-23 17:28:57 +0000563static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000564__kmp_init_lock( kmp_lock_t *lck )
565{
566 __kmp_init_ticket_lock( lck );
567}
568
Jim Cownie181b4bb2013-12-23 17:28:57 +0000569static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000570__kmp_destroy_lock( kmp_lock_t *lck )
571{
572 __kmp_destroy_ticket_lock( lck );
573}
574
575
576// ----------------------------------------------------------------------------
577// User locks.
578// ----------------------------------------------------------------------------
579
580//
581// Do not allocate objects of type union kmp_user_lock!!!
582// This will waste space unless __kmp_user_lock_kind == lk_drdpa.
583// Instead, check the value of __kmp_user_lock_kind and allocate objects of
584// the type of the appropriate union member, and cast their addresses to
585// kmp_user_lock_p.
586//
587
588enum kmp_lock_kind {
589 lk_default = 0,
590 lk_tas,
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000591#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000592 lk_futex,
593#endif
594 lk_ticket,
595 lk_queuing,
596 lk_drdpa,
597#if KMP_USE_ADAPTIVE_LOCKS
598 lk_adaptive
599#endif // KMP_USE_ADAPTIVE_LOCKS
600};
601
602typedef enum kmp_lock_kind kmp_lock_kind_t;
603
604extern kmp_lock_kind_t __kmp_user_lock_kind;
605
606union kmp_user_lock {
607 kmp_tas_lock_t tas;
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000608#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000609 kmp_futex_lock_t futex;
610#endif
611 kmp_ticket_lock_t ticket;
612 kmp_queuing_lock_t queuing;
613 kmp_drdpa_lock_t drdpa;
614#if KMP_USE_ADAPTIVE_LOCKS
615 kmp_adaptive_lock_t adaptive;
616#endif // KMP_USE_ADAPTIVE_LOCKS
617 kmp_lock_pool_t pool;
618};
619
620typedef union kmp_user_lock *kmp_user_lock_p;
621
Andrey Churbanov5c56fb52015-02-20 18:05:17 +0000622#if ! KMP_USE_DYNAMIC_LOCK
623
Jim Cownie5e8470a2013-09-27 10:38:44 +0000624extern size_t __kmp_base_user_lock_size;
625extern size_t __kmp_user_lock_size;
626
627extern kmp_int32 ( *__kmp_get_user_lock_owner_ )( kmp_user_lock_p lck );
628
Jim Cownie181b4bb2013-12-23 17:28:57 +0000629static inline kmp_int32
Jim Cownie5e8470a2013-09-27 10:38:44 +0000630__kmp_get_user_lock_owner( kmp_user_lock_p lck )
631{
632 KMP_DEBUG_ASSERT( __kmp_get_user_lock_owner_ != NULL );
633 return ( *__kmp_get_user_lock_owner_ )( lck );
634}
635
636extern void ( *__kmp_acquire_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
637
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000638#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000639
640#define __kmp_acquire_user_lock_with_checks(lck,gtid) \
641 if (__kmp_user_lock_kind == lk_tas) { \
642 if ( __kmp_env_consistency_check ) { \
643 char const * const func = "omp_set_lock"; \
644 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE ) \
645 && lck->tas.lk.depth_locked != -1 ) { \
646 KMP_FATAL( LockNestableUsedAsSimple, func ); \
647 } \
648 if ( ( gtid >= 0 ) && ( lck->tas.lk.poll - 1 == gtid ) ) { \
649 KMP_FATAL( LockIsAlreadyOwned, func ); \
650 } \
651 } \
652 if ( ( lck->tas.lk.poll != 0 ) || \
653 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
654 kmp_uint32 spins; \
655 KMP_FSYNC_PREPARE( lck ); \
656 KMP_INIT_YIELD( spins ); \
657 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
658 KMP_YIELD( TRUE ); \
659 } else { \
660 KMP_YIELD_SPIN( spins ); \
661 } \
662 while ( ( lck->tas.lk.poll != 0 ) || \
663 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
664 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
665 KMP_YIELD( TRUE ); \
666 } else { \
667 KMP_YIELD_SPIN( spins ); \
668 } \
669 } \
670 } \
671 KMP_FSYNC_ACQUIRED( lck ); \
672 } else { \
673 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL ); \
674 ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid ); \
675 }
676
677#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000678static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000679__kmp_acquire_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
680{
681 KMP_DEBUG_ASSERT( __kmp_acquire_user_lock_with_checks_ != NULL );
682 ( *__kmp_acquire_user_lock_with_checks_ )( lck, gtid );
683}
684#endif
685
686extern int ( *__kmp_test_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
687
Andrey Churbanovcbda8682015-01-13 14:43:35 +0000688#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000689
690#include "kmp_i18n.h" /* AC: KMP_FATAL definition */
691extern int __kmp_env_consistency_check; /* AC: copy from kmp.h here */
Jim Cownie181b4bb2013-12-23 17:28:57 +0000692static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000693__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
694{
695 if ( __kmp_user_lock_kind == lk_tas ) {
696 if ( __kmp_env_consistency_check ) {
697 char const * const func = "omp_test_lock";
698 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_LOCK_T_SIZE )
699 && lck->tas.lk.depth_locked != -1 ) {
700 KMP_FATAL( LockNestableUsedAsSimple, func );
701 }
702 }
703 return ( ( lck->tas.lk.poll == 0 ) &&
704 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
705 } else {
706 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
707 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
708 }
709}
710#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000711static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000712__kmp_test_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
713{
714 KMP_DEBUG_ASSERT( __kmp_test_user_lock_with_checks_ != NULL );
715 return ( *__kmp_test_user_lock_with_checks_ )( lck, gtid );
716}
717#endif
718
719extern void ( *__kmp_release_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
720
Jim Cownie181b4bb2013-12-23 17:28:57 +0000721static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000722__kmp_release_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
723{
724 KMP_DEBUG_ASSERT( __kmp_release_user_lock_with_checks_ != NULL );
725 ( *__kmp_release_user_lock_with_checks_ ) ( lck, gtid );
726}
727
728extern void ( *__kmp_init_user_lock_with_checks_ )( kmp_user_lock_p lck );
729
Jim Cownie181b4bb2013-12-23 17:28:57 +0000730static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000731__kmp_init_user_lock_with_checks( kmp_user_lock_p lck )
732{
733 KMP_DEBUG_ASSERT( __kmp_init_user_lock_with_checks_ != NULL );
734 ( *__kmp_init_user_lock_with_checks_ )( lck );
735}
736
737//
738// We need a non-checking version of destroy lock for when the RTL is
739// doing the cleanup as it can't always tell if the lock is nested or not.
740//
741extern void ( *__kmp_destroy_user_lock_ )( kmp_user_lock_p lck );
742
Jim Cownie181b4bb2013-12-23 17:28:57 +0000743static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000744__kmp_destroy_user_lock( kmp_user_lock_p lck )
745{
746 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_ != NULL );
747 ( *__kmp_destroy_user_lock_ )( lck );
748}
749
750extern void ( *__kmp_destroy_user_lock_with_checks_ )( kmp_user_lock_p lck );
751
Jim Cownie181b4bb2013-12-23 17:28:57 +0000752static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000753__kmp_destroy_user_lock_with_checks( kmp_user_lock_p lck )
754{
755 KMP_DEBUG_ASSERT( __kmp_destroy_user_lock_with_checks_ != NULL );
756 ( *__kmp_destroy_user_lock_with_checks_ )( lck );
757}
758
759extern void ( *__kmp_acquire_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
760
761#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
762
763#define __kmp_acquire_nested_user_lock_with_checks(lck,gtid) \
764 if (__kmp_user_lock_kind == lk_tas) { \
765 if ( __kmp_env_consistency_check ) { \
766 char const * const func = "omp_set_nest_lock"; \
767 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE ) \
768 && lck->tas.lk.depth_locked == -1 ) { \
769 KMP_FATAL( LockSimpleUsedAsNestable, func ); \
770 } \
771 } \
772 if ( lck->tas.lk.poll - 1 == gtid ) { \
773 lck->tas.lk.depth_locked += 1; \
774 } else { \
775 if ( ( lck->tas.lk.poll != 0 ) || \
776 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
777 kmp_uint32 spins; \
778 KMP_FSYNC_PREPARE( lck ); \
779 KMP_INIT_YIELD( spins ); \
780 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
781 KMP_YIELD( TRUE ); \
782 } else { \
783 KMP_YIELD_SPIN( spins ); \
784 } \
785 while ( ( lck->tas.lk.poll != 0 ) || \
786 ( ! KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) ) ) { \
787 if ( TCR_4(__kmp_nth) > (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc) ) { \
788 KMP_YIELD( TRUE ); \
789 } else { \
790 KMP_YIELD_SPIN( spins ); \
791 } \
792 } \
793 } \
794 lck->tas.lk.depth_locked = 1; \
795 } \
796 KMP_FSYNC_ACQUIRED( lck ); \
797 } else { \
798 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL ); \
799 ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid ); \
800 }
801
802#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000803static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000804__kmp_acquire_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
805{
806 KMP_DEBUG_ASSERT( __kmp_acquire_nested_user_lock_with_checks_ != NULL );
807 ( *__kmp_acquire_nested_user_lock_with_checks_ )( lck, gtid );
808}
809#endif
810
811extern int ( *__kmp_test_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
812
813#if KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64)
Jim Cownie181b4bb2013-12-23 17:28:57 +0000814static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000815__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
816{
817 if ( __kmp_user_lock_kind == lk_tas ) {
818 int retval;
819 if ( __kmp_env_consistency_check ) {
820 char const * const func = "omp_test_nest_lock";
821 if ( ( sizeof ( kmp_tas_lock_t ) <= OMP_NEST_LOCK_T_SIZE )
822 && lck->tas.lk.depth_locked == -1 ) {
823 KMP_FATAL( LockSimpleUsedAsNestable, func );
824 }
825 }
826 KMP_DEBUG_ASSERT( gtid >= 0 );
827 if ( lck->tas.lk.poll - 1 == gtid ) { /* __kmp_get_tas_lock_owner( lck ) == gtid */
828 return ++lck->tas.lk.depth_locked; /* same owner, depth increased */
829 }
830 retval = ( ( lck->tas.lk.poll == 0 ) &&
831 KMP_COMPARE_AND_STORE_ACQ32( &(lck->tas.lk.poll), 0, gtid + 1 ) );
832 if ( retval ) {
833 KMP_MB();
834 lck->tas.lk.depth_locked = 1;
835 }
836 return retval;
837 } else {
838 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
839 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
840 }
841}
842#else
Jim Cownie181b4bb2013-12-23 17:28:57 +0000843static inline int
Jim Cownie5e8470a2013-09-27 10:38:44 +0000844__kmp_test_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
845{
846 KMP_DEBUG_ASSERT( __kmp_test_nested_user_lock_with_checks_ != NULL );
847 return ( *__kmp_test_nested_user_lock_with_checks_ )( lck, gtid );
848}
849#endif
850
851extern void ( *__kmp_release_nested_user_lock_with_checks_ )( kmp_user_lock_p lck, kmp_int32 gtid );
852
Jim Cownie181b4bb2013-12-23 17:28:57 +0000853static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000854__kmp_release_nested_user_lock_with_checks( kmp_user_lock_p lck, kmp_int32 gtid )
855{
856 KMP_DEBUG_ASSERT( __kmp_release_nested_user_lock_with_checks_ != NULL );
857 ( *__kmp_release_nested_user_lock_with_checks_ )( lck, gtid );
858}
859
860extern void ( *__kmp_init_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
861
Jim Cownie181b4bb2013-12-23 17:28:57 +0000862static inline void __kmp_init_nested_user_lock_with_checks( kmp_user_lock_p lck )
Jim Cownie5e8470a2013-09-27 10:38:44 +0000863{
864 KMP_DEBUG_ASSERT( __kmp_init_nested_user_lock_with_checks_ != NULL );
865 ( *__kmp_init_nested_user_lock_with_checks_ )( lck );
866}
867
868extern void ( *__kmp_destroy_nested_user_lock_with_checks_ )( kmp_user_lock_p lck );
869
Jim Cownie181b4bb2013-12-23 17:28:57 +0000870static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000871__kmp_destroy_nested_user_lock_with_checks( kmp_user_lock_p lck )
872{
873 KMP_DEBUG_ASSERT( __kmp_destroy_nested_user_lock_with_checks_ != NULL );
874 ( *__kmp_destroy_nested_user_lock_with_checks_ )( lck );
875}
876
877//
878// user lock functions which do not necessarily exist for all lock kinds.
879//
880// The "set" functions usually have wrapper routines that check for a NULL set
881// function pointer and call it if non-NULL.
882//
883// In some cases, it makes sense to have a "get" wrapper function check for a
884// NULL get function pointer and return NULL / invalid value / error code if
885// the function pointer is NULL.
886//
887// In other cases, the calling code really should differentiate between an
888// unimplemented function and one that is implemented but returning NULL /
889// invalied value. If this is the case, no get function wrapper exists.
890//
891
892extern int ( *__kmp_is_user_lock_initialized_ )( kmp_user_lock_p lck );
893
894// no set function; fields set durining local allocation
895
896extern const ident_t * ( *__kmp_get_user_lock_location_ )( kmp_user_lock_p lck );
897
Jim Cownie181b4bb2013-12-23 17:28:57 +0000898static inline const ident_t *
Jim Cownie5e8470a2013-09-27 10:38:44 +0000899__kmp_get_user_lock_location( kmp_user_lock_p lck )
900{
901 if ( __kmp_get_user_lock_location_ != NULL ) {
902 return ( *__kmp_get_user_lock_location_ )( lck );
903 }
904 else {
905 return NULL;
906 }
907}
908
909extern void ( *__kmp_set_user_lock_location_ )( kmp_user_lock_p lck, const ident_t *loc );
910
Jim Cownie181b4bb2013-12-23 17:28:57 +0000911static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000912__kmp_set_user_lock_location( kmp_user_lock_p lck, const ident_t *loc )
913{
914 if ( __kmp_set_user_lock_location_ != NULL ) {
915 ( *__kmp_set_user_lock_location_ )( lck, loc );
916 }
917}
918
919extern kmp_lock_flags_t ( *__kmp_get_user_lock_flags_ )( kmp_user_lock_p lck );
920
921extern void ( *__kmp_set_user_lock_flags_ )( kmp_user_lock_p lck, kmp_lock_flags_t flags );
922
Jim Cownie181b4bb2013-12-23 17:28:57 +0000923static inline void
Jim Cownie5e8470a2013-09-27 10:38:44 +0000924__kmp_set_user_lock_flags( kmp_user_lock_p lck, kmp_lock_flags_t flags )
925{
926 if ( __kmp_set_user_lock_flags_ != NULL ) {
927 ( *__kmp_set_user_lock_flags_ )( lck, flags );
928 }
929}
930
931//
932// The fuction which sets up all of the vtbl pointers for kmp_user_lock_t.
933//
934extern void __kmp_set_user_lock_vptrs( kmp_lock_kind_t user_lock_kind );
935
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000936//
937// Macros for binding user lock functions.
938//
939#define KMP_BIND_USER_LOCK_TEMPLATE(nest, kind, suffix) { \
940 __kmp_acquire##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p, kmp_int32 ) ) \
941 __kmp_acquire##nest##kind##_##suffix; \
942 __kmp_release##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p, kmp_int32 ) ) \
943 __kmp_release##nest##kind##_##suffix; \
944 __kmp_test##nest##user_lock_with_checks_ = ( int (*)( kmp_user_lock_p, kmp_int32 ) ) \
945 __kmp_test##nest##kind##_##suffix; \
946 __kmp_init##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p ) ) \
947 __kmp_init##nest##kind##_##suffix; \
948 __kmp_destroy##nest##user_lock_with_checks_ = ( void (*)( kmp_user_lock_p ) ) \
949 __kmp_destroy##nest##kind##_##suffix; \
950}
Jim Cownie5e8470a2013-09-27 10:38:44 +0000951
Jim Cownie4cc4bb42014-10-07 16:25:50 +0000952#define KMP_BIND_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock)
953#define KMP_BIND_USER_LOCK_WITH_CHECKS(kind) KMP_BIND_USER_LOCK_TEMPLATE(_, kind, lock_with_checks)
954#define KMP_BIND_NESTED_USER_LOCK(kind) KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock)
955#define KMP_BIND_NESTED_USER_LOCK_WITH_CHECKS(kind) KMP_BIND_USER_LOCK_TEMPLATE(_nested_, kind, lock_with_checks)
Jim Cownie5e8470a2013-09-27 10:38:44 +0000956
957// ----------------------------------------------------------------------------
958// User lock table & lock allocation
959// ----------------------------------------------------------------------------
960
961/*
962 On 64-bit Linux* OS (and OS X*) GNU compiler allocates only 4 bytems memory for lock variable, which
963 is not enough to store a pointer, so we have to use lock indexes instead of pointers and
964 maintain lock table to map indexes to pointers.
965
966
967 Note: The first element of the table is not a pointer to lock! It is a pointer to previously
968 allocated table (or NULL if it is the first table).
969
970 Usage:
971
972 if ( OMP_LOCK_T_SIZE < sizeof( <lock> ) ) { // or OMP_NEST_LOCK_T_SIZE
973 Lock table is fully utilized. User locks are indexes, so table is
974 used on user lock operation.
975 Note: it may be the case (lin_32) that we don't need to use a lock
976 table for regular locks, but do need the table for nested locks.
977 }
978 else {
979 Lock table initialized but not actually used.
980 }
981*/
982
983struct kmp_lock_table {
984 kmp_lock_index_t used; // Number of used elements
985 kmp_lock_index_t allocated; // Number of allocated elements
986 kmp_user_lock_p * table; // Lock table.
987};
988
989typedef struct kmp_lock_table kmp_lock_table_t;
990
991extern kmp_lock_table_t __kmp_user_lock_table;
992extern kmp_user_lock_p __kmp_lock_pool;
993
994struct kmp_block_of_locks {
995 struct kmp_block_of_locks * next_block;
996 void * locks;
997};
998
999typedef struct kmp_block_of_locks kmp_block_of_locks_t;
1000
1001extern kmp_block_of_locks_t *__kmp_lock_blocks;
1002extern int __kmp_num_locks_in_block;
1003
Jim Cownie181b4bb2013-12-23 17:28:57 +00001004extern 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 +00001005extern void __kmp_user_lock_free( void **user_lock, kmp_int32 gtid, kmp_user_lock_p lck );
1006extern kmp_user_lock_p __kmp_lookup_user_lock( void **user_lock, char const *func );
1007extern void __kmp_cleanup_user_locks();
1008
1009#define KMP_CHECK_USER_LOCK_INIT() \
1010 { \
1011 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
1012 __kmp_acquire_bootstrap_lock( &__kmp_initz_lock ); \
1013 if ( ! TCR_4( __kmp_init_user_locks ) ) { \
1014 TCW_4( __kmp_init_user_locks, TRUE ); \
1015 } \
1016 __kmp_release_bootstrap_lock( &__kmp_initz_lock ); \
1017 } \
1018 }
1019
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001020#endif // KMP_USE_DYNAMIC_LOCK
1021
Jim Cownie5e8470a2013-09-27 10:38:44 +00001022#undef KMP_PAD
1023#undef KMP_GTID_DNE
1024
Andrey Churbanov5c56fb52015-02-20 18:05:17 +00001025#if KMP_USE_DYNAMIC_LOCK
1026
1027#define DYNA_HAS_FUTEX (KMP_OS_LINUX && (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM))
1028#define DYNA_HAS_HLE (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_MIC)
1029#define DYNA_USE_FAST_FUTEX 0 && DYNA_HAS_FUTEX
1030#define DYNA_USE_FAST_TAS 1 && DYNA_HAS_FUTEX
1031
1032// List of lock definitions; all nested locks are indirect locks.
1033// hle lock is xchg lock prefixed with XACQUIRE/XRELEASE.
1034// All nested locks are indirect lock types.
1035#if DYNA_HAS_FUTEX
1036# if DYNA_HAS_HLE
1037# define FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a) m(hle, a)
1038# define DYNA_LAST_D_LOCK_SEQ lockseq_hle
1039# else
1040# define FOREACH_D_LOCK(m, a) m(tas, a) m(futex, a)
1041# define DYNA_LAST_D_LOCK_SEQ lockseq_futex
1042# endif // DYNA_HAS_HLE
1043# if KMP_USE_ADAPTIVE_LOCKS
1044# define FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) \
1045 m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a) \
1046 m(nested_queuing, a) m(nested_drdpa, a)
1047# else
1048# define FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(drdpa, a) \
1049 m(nested_tas, a) m(nested_futex, a) m(nested_ticket, a) \
1050 m(nested_queuing, a) m(nested_drdpa, a)
1051# endif // KMP_USE_ADAPTIVE_LOCKS
1052#else
1053# if DYNA_HAS_HLE
1054# define FOREACH_D_LOCK(m, a) m(tas, a) m(hle, a)
1055# define DYNA_LAST_D_LOCK_SEQ lockseq_hle
1056# else
1057# define FOREACH_D_LOCK(m, a) m(tas, a)
1058# define DYNA_LAST_D_LOCK_SEQ lockseq_tas
1059# endif // DYNA_HAS_HLE
1060# if KMP_USE_ADAPTIVE_LOCKS
1061# define FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(adaptive, a) m(drdpa, a) \
1062 m(nested_tas, a) m(nested_ticket, a) \
1063 m(nested_queuing, a) m(nested_drdpa, a)
1064# else
1065# define FOREACH_I_LOCK(m, a) m(ticket, a) m(queuing, a) m(drdpa, a) \
1066 m(nested_tas, a) m(nested_ticket, a) \
1067 m(nested_queuing, a) m(nested_drdpa, a)
1068# endif // KMP_USE_ADAPTIVE_LOCKS
1069#endif // DYNA_HAS_FUTEX
1070
1071// Information used in dynamic dispatch
1072#define DYNA_LOCK_VALUE_SHIFT 8
1073#define DYNA_LOCK_TYPE_MASK ((1<<DYNA_LOCK_VALUE_SHIFT)-1)
1074#define DYNA_NUM_D_LOCKS DYNA_LAST_D_LOCK_SEQ
1075#define DYNA_NUM_I_LOCKS (locktag_nested_drdpa+1)
1076
1077// Base type for dynamic locks.
1078typedef kmp_uint32 kmp_dyna_lock_t;
1079
1080// Lock sequence that enumerates all lock kinds.
1081// Always make this enumeration consistent with kmp_lockseq_t in the include directory.
1082typedef enum {
1083 lockseq_indirect = 0,
1084#define expand_seq(l,a) lockseq_##l,
1085 FOREACH_D_LOCK(expand_seq, 0)
1086 FOREACH_I_LOCK(expand_seq, 0)
1087#undef expand_seq
1088} kmp_dyna_lockseq_t;
1089
1090// Enumerates indirect lock tags.
1091typedef enum {
1092#define expand_tag(l,a) locktag_##l,
1093 FOREACH_I_LOCK(expand_tag, 0)
1094#undef expand_tag
1095} kmp_indirect_locktag_t;
1096
1097// Utility macros that extract information from lock sequences.
1098#define DYNA_IS_D_LOCK(seq) (seq >= lockseq_tas && seq <= DYNA_LAST_D_LOCK_SEQ)
1099#define DYNA_IS_I_LOCK(seq) (seq >= lockseq_ticket && seq <= lockseq_nested_drdpa)
1100#define DYNA_GET_I_TAG(seq) (kmp_indirect_locktag_t)(seq - lockseq_ticket)
1101#define DYNA_GET_D_TAG(seq) (seq<<1 | 1)
1102
1103// Enumerates direct lock tags starting from indirect tag.
1104typedef enum {
1105#define expand_tag(l,a) locktag_##l = DYNA_GET_D_TAG(lockseq_##l),
1106 FOREACH_D_LOCK(expand_tag, 0)
1107#undef expand_tag
1108} kmp_direct_locktag_t;
1109
1110// Indirect lock type
1111typedef struct {
1112 kmp_user_lock_p lock;
1113 kmp_indirect_locktag_t type;
1114} kmp_indirect_lock_t;
1115
1116// Function tables for direct locks. Set/unset/test differentiate functions with/without consistency checking.
1117extern void (*__kmp_direct_init_ops[])(kmp_dyna_lock_t *, kmp_dyna_lockseq_t);
1118extern void (*__kmp_direct_destroy_ops[])(kmp_dyna_lock_t *);
1119extern void (*(*__kmp_direct_set_ops))(kmp_dyna_lock_t *, kmp_int32);
1120extern void (*(*__kmp_direct_unset_ops))(kmp_dyna_lock_t *, kmp_int32);
1121extern int (*(*__kmp_direct_test_ops))(kmp_dyna_lock_t *, kmp_int32);
1122
1123// Function tables for indirect locks. Set/unset/test differentiate functions with/withuot consistency checking.
1124extern void (*__kmp_indirect_init_ops[])(kmp_user_lock_p);
1125extern void (*__kmp_indirect_destroy_ops[])(kmp_user_lock_p);
1126extern void (*(*__kmp_indirect_set_ops))(kmp_user_lock_p, kmp_int32);
1127extern void (*(*__kmp_indirect_unset_ops))(kmp_user_lock_p, kmp_int32);
1128extern int (*(*__kmp_indirect_test_ops))(kmp_user_lock_p, kmp_int32);
1129
1130// Extracts direct lock tag from a user lock pointer
1131#define DYNA_EXTRACT_D_TAG(l) (*((kmp_dyna_lock_t *)(l)) & DYNA_LOCK_TYPE_MASK & -(*((kmp_dyna_lock_t *)(l)) & 1))
1132
1133// Extracts indirect lock index from a user lock pointer
1134#define DYNA_EXTRACT_I_INDEX(l) (*(kmp_lock_index_t *)(l) >> 1)
1135
1136// Returns function pointer to the direct lock function with l (kmp_dyna_lock_t *) and op (operation type).
1137#define DYNA_D_LOCK_FUNC(l, op) __kmp_direct_##op##_ops[DYNA_EXTRACT_D_TAG(l)]
1138
1139// Returns function pointer to the indirect lock function with l (kmp_indirect_lock_t *) and op (operation type).
1140#define DYNA_I_LOCK_FUNC(l, op) __kmp_indirect_##op##_ops[((kmp_indirect_lock_t *)(l))->type]
1141
1142// Initializes a direct lock with the given lock pointer and lock sequence.
1143#define DYNA_INIT_D_LOCK(l, seq) __kmp_direct_init_ops[DYNA_GET_D_TAG(seq)]((kmp_dyna_lock_t *)l, seq)
1144
1145// Initializes an indirect lock with the given lock pointer and lock sequence.
1146#define DYNA_INIT_I_LOCK(l, seq) __kmp_direct_init_ops[0]((kmp_dyna_lock_t *)(l), seq)
1147
1148// Returns "free" lock value for the given lock type.
1149#define DYNA_LOCK_FREE(type) (locktag_##type)
1150
1151// Returns "busy" lock value for the given lock teyp.
1152#define DYNA_LOCK_BUSY(v, type) ((v)<<DYNA_LOCK_VALUE_SHIFT | locktag_##type)
1153
1154// Returns lock value after removing (shifting) lock tag.
1155#define DYNA_LOCK_STRIP(v) ((v)>>DYNA_LOCK_VALUE_SHIFT)
1156
1157// Updates __kmp_user_lock_seq with the give lock type.
1158#define DYNA_STORE_LOCK_SEQ(type) (__kmp_user_lock_seq = lockseq_##type)
1159
1160// Internal entries for hinted lock initializers.
1161extern void __kmp_init_lock_hinted(void **, int);
1162extern void __kmp_init_nest_lock_hinted(void **, int);
1163
1164// Initializes global states and data structures for managing dynamic user locks.
1165extern void __kmp_init_dynamic_user_locks();
1166
1167// Allocates and returns an indirect lock with the given indirect lock tag.
1168extern kmp_indirect_lock_t * __kmp_allocate_indirect_lock(void **, kmp_int32, kmp_indirect_locktag_t);
1169
1170// Cleans up global states and data structures for managing dynamic user locks.
1171extern void __kmp_cleanup_indirect_user_locks();
1172
1173// Default user lock sequence when not using hinted locks.
1174extern kmp_dyna_lockseq_t __kmp_user_lock_seq;
1175
1176// Jump table for "set lock location", available only for indirect locks.
1177extern void (*__kmp_indirect_set_location[DYNA_NUM_I_LOCKS])(kmp_user_lock_p, const ident_t *);
1178#define DYNA_SET_I_LOCK_LOCATION(lck, loc) { \
1179 if (__kmp_indirect_set_location[(lck)->type] != NULL) \
1180 __kmp_indirect_set_location[(lck)->type]((lck)->lock, loc); \
1181}
1182
1183// Jump table for "set lock flags", available only for indirect locks.
1184extern void (*__kmp_indirect_set_flags[DYNA_NUM_I_LOCKS])(kmp_user_lock_p, kmp_lock_flags_t);
1185#define DYNA_SET_I_LOCK_FLAGS(lck, flag) { \
1186 if (__kmp_indirect_set_flags[(lck)->type] != NULL) \
1187 __kmp_indirect_set_flags[(lck)->type]((lck)->lock, flag); \
1188}
1189
1190// Jump table for "get lock location", available only for indirect locks.
1191extern const ident_t * (*__kmp_indirect_get_location[DYNA_NUM_I_LOCKS])(kmp_user_lock_p);
1192#define DYNA_GET_I_LOCK_LOCATION(lck) ( __kmp_indirect_get_location[(lck)->type] != NULL \
1193 ? __kmp_indirect_get_location[(lck)->type]((lck)->lock) \
1194 : NULL )
1195
1196// Jump table for "get lock flags", available only for indirect locks.
1197extern kmp_lock_flags_t (*__kmp_indirect_get_flags[DYNA_NUM_I_LOCKS])(kmp_user_lock_p);
1198#define DYNA_GET_I_LOCK_FLAGS(lck) ( __kmp_indirect_get_flags[(lck)->type] != NULL \
1199 ? __kmp_indirect_get_flags[(lck)->type]((lck)->lock) \
1200 : NULL )
1201
1202//
1203// Lock table for indirect locks.
1204//
1205// Simple linear structure is used to keep pointers to allocated indirect locks.
1206extern kmp_indirect_lock_t **__kmp_indirect_lock_table;
1207// Current size of the lock table; it may increase but never shrink.
1208extern kmp_lock_index_t __kmp_indirect_lock_table_size;
1209// Next index to be used for a new indirect lock (= number of indirect locks allocated).
1210extern kmp_lock_index_t __kmp_indirect_lock_table_next;
1211// Number of locks in a lock block, which is fixed to "1" now.
1212// TODO: No lock block implementation now. If we do support, we need to manage lock block data
1213// structure for each indirect lock type.
1214extern int __kmp_num_locks_in_block;
1215
1216// Fast lock table lookup without consistency checking
1217#define DYNA_LOOKUP_I_LOCK(l) ( (OMP_LOCK_T_SIZE < sizeof(void *)) \
1218 ? __kmp_indirect_lock_table[DYNA_EXTRACT_I_INDEX(l)] \
1219 : *((kmp_indirect_lock_t **)l) )
1220
1221// Used once in kmp_error.c
1222extern kmp_int32
1223__kmp_get_user_lock_owner(kmp_user_lock_p, kmp_uint32);
1224
1225#else // KMP_USE_DYNAMIC_LOCK
1226
1227# define DYNA_LOCK_BUSY(v, type) (v)
1228# define DYNA_LOCK_FREE(type) 0
1229# define DYNA_LOCK_STRIP(v) (v)
1230# define DYNA_STORE_LOCK_SEQ(seq)
1231
1232#endif // KMP_USE_DYNAMIC_LOCK
1233
Jim Cownie5e8470a2013-09-27 10:38:44 +00001234#ifdef __cplusplus
1235} // extern "C"
1236#endif // __cplusplus
1237
1238#endif /* KMP_LOCK_H */
1239