1 /* Copyright (C) 2009-2014 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Transactional Memory Library (libitm).
6 Libitm is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #ifndef LIBITM_STMLOCK_H
26 #define LIBITM_STMLOCK_H 1
28 namespace GTM HIDDEN
{
30 /* A versioned write lock on a cacheline. This must be wide enough to
31 store a pointer, and preferably wide enough to avoid overflowing the
32 version counter. Thus we use a "word", which should be 64-bits on
33 64-bit systems even when their pointer size is forced smaller. */
34 typedef gtm_word gtm_stmlock
;
36 /* This has to be the same size as gtm_stmlock, we just use this name
37 for documentation purposes. */
38 typedef gtm_word gtm_version
;
40 /* The maximum value a version number can have. This is a consequence
41 of having the low bit of gtm_stmlock reserved for the owned bit. */
42 #define GTM_VERSION_MAX (~(gtm_version)0 >> 1)
44 /* A value that may be used to indicate "uninitialized" for a version. */
45 #define GTM_VERSION_INVALID (~(gtm_version)0)
47 /* This bit is set when the write lock is held. When set, the balance of
48 the bits in the lock is a pointer that references STM backend specific
49 data; it is up to the STM backend to determine if this thread holds the
50 lock. If this bit is clear, the balance of the bits are the last
51 version number committed to the cacheline. */
53 gtm_stmlock_owned_p (gtm_stmlock lock
)
58 static inline gtm_stmlock
59 gtm_stmlock_set_owned (void *data
)
61 return (gtm_stmlock
)(uintptr_t)data
| 1;
65 gtm_stmlock_get_addr (gtm_stmlock lock
)
67 return (void *)((uintptr_t)lock
& ~(uintptr_t)1);
70 static inline gtm_version
71 gtm_stmlock_get_version (gtm_stmlock lock
)
76 static inline gtm_stmlock
77 gtm_stmlock_set_version (gtm_version ver
)
82 /* We use a fixed set of locks for all memory, hashed into the
84 #define LOCK_ARRAY_SIZE (1024 * 1024)
85 extern gtm_stmlock gtm_stmlock_array
[LOCK_ARRAY_SIZE
];
87 static inline gtm_stmlock
*
88 gtm_get_stmlock (const gtm_cacheline
*addr
)
90 size_t idx
= ((uintptr_t) addr
/ CACHELINE_SIZE
) % LOCK_ARRAY_SIZE
;
91 return gtm_stmlock_array
+ idx
;
94 /* The current global version number. */
95 extern atomic
<gtm_version
> gtm_clock
;
97 static inline gtm_version
100 atomic_thread_fence(memory_order_release
);
101 return gtm_clock
.load(memory_order_acquire
);
104 static inline gtm_version
107 /* ??? Here we have a choice, the pre-inc operator mapping to
108 __atomic_add_fetch with memory_order_seq_cst, or fetch_add
109 with memory_order_acq_rel plus another separate increment.
110 We really ought to recognize and optimize fetch_op(x) op x... */
111 gtm_version r
= ++gtm_clock
;
113 /* ??? Ought to handle wraparound for 32-bit. */
114 if (sizeof(r
) < 8 && r
> GTM_VERSION_MAX
)
122 #endif // LIBITM_STMLOCK_H