74ccb94fd9542edc1fd0b76bef443a6b14867a9e
[cacao.git] / src / threads / lockword.hpp
1 /* src/threads/lockword.hpp - lockword implementation
2
3    Copyright (C) 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #ifndef _LOCKWORD_HPP
27 #define _LOCKWORD_HPP
28
29 #include <stdint.h>
30
31
32 #ifdef __cplusplus
33
34 /**
35  * Lockword.
36  */
37 class Lockword {
38 private:
39         static const int       THIN_LOCK_WORD_SIZE   = SIZEOF_VOID_P * 8; // Pointer size multiplied by 8-bit.
40         static const int       THIN_LOCK_SHAPE_BIT   = 0x01;
41
42         static const uintptr_t THIN_UNLOCKED         = 0;
43
44         static const int       THIN_LOCK_COUNT_SHIFT = 1;
45         static const int       THIN_LOCK_COUNT_SIZE  = 8;
46         static const int       THIN_LOCK_COUNT_INCR  = (1 << THIN_LOCK_COUNT_SHIFT);
47         static const int       THIN_LOCK_COUNT_MAX   = ((1 << THIN_LOCK_COUNT_SIZE) - 1);
48
49         static const int       THIN_LOCK_COUNT_MASK  = (THIN_LOCK_COUNT_MAX << THIN_LOCK_COUNT_SHIFT);
50
51         static const int       THIN_LOCK_TID_SHIFT   = (THIN_LOCK_COUNT_SIZE + THIN_LOCK_COUNT_SHIFT);
52         static const int       THIN_LOCK_TID_SIZE    = (THIN_LOCK_WORD_SIZE - THIN_LOCK_TID_SHIFT);
53
54 private:
55         // The actual lockword.
56         uintptr_t _lockword;
57
58 private:
59         Lockword(uintptr_t lockword) : _lockword(lockword) {}
60
61 public:
62         Lockword() : _lockword(THIN_UNLOCKED) {}
63
64         void init() { _lockword = THIN_UNLOCKED; } // REMOVEME
65
66         static inline uintptr_t pre_compute_thinlock(int32_t index);
67
68         inline bool is_thin_lock         () const;
69         inline bool is_fat_lock          () const;
70
71         inline bool is_unlocked() const;
72         inline bool lock       (uintptr_t thinlock);
73         inline void unlock     ();
74
75         inline uintptr_t             get_thin_lock              () const;
76         inline uintptr_t             get_thin_lock_without_count() const;
77         inline int32_t               get_thin_lock_count        () const;
78         inline int32_t               get_thin_lock_thread_index () const;
79         inline struct lock_record_t* get_fat_lock               () const;
80
81         inline void set(uintptr_t lockword);
82         inline void set(struct lock_record_t* lr);
83
84         inline bool is_max_thin_lock_count  () const;
85         inline void increase_thin_lock_count();
86         inline void decrease_thin_lock_count();
87
88         void inflate(struct lock_record_t* lr);
89 };
90
91
92 // Includes.
93 #include <assert.h>
94
95 #include "threads/atomic.hpp"
96
97
98 /**
99  * Pre-compute the thin lock value for a thread index.
100  *
101  * @param index The thead index (>= 1).
102  *
103  * @return The thin lock value for this thread index.
104  */
105 uintptr_t Lockword::pre_compute_thinlock(int32_t index)
106 {
107         return (index << THIN_LOCK_TID_SHIFT) | THIN_UNLOCKED;
108 }
109
110
111 bool Lockword::is_thin_lock() const
112 {
113         return ((_lockword & THIN_LOCK_SHAPE_BIT) == 0);
114 }
115
116
117 bool Lockword::is_fat_lock() const
118 {
119         return ((_lockword & THIN_LOCK_SHAPE_BIT) != 0);
120 }
121
122
123 /**
124  * Check if the lockword is an unlocked thin-lock.
125  *
126  * @return true if unlocked, false otherwise.
127  */
128 bool Lockword::is_unlocked() const
129 {
130         return (_lockword == THIN_UNLOCKED);
131 }
132
133
134 /**
135  * Try to lock the lockword with the given thin-lock value.
136  *
137  * @param thinlock Thin-lock value to store in the Lockword.
138  *
139  * @return true if lock was successful, false otherwise.
140  */
141 bool Lockword::lock(uintptr_t thinlock)
142 {
143         // Atomically exchange the lockword value.
144         uintptr_t oldlockword = Atomic::compare_and_swap(&_lockword, THIN_UNLOCKED, thinlock);
145
146         return Lockword(oldlockword).is_unlocked();
147 }
148
149
150 /**
151  * Set the lockword to THIN_UNLOCKED.
152  */
153 void Lockword::unlock()
154 {
155         _lockword = THIN_UNLOCKED;
156 }
157
158
159 uintptr_t Lockword::get_thin_lock() const
160 {
161         return _lockword;
162 }
163
164
165 uintptr_t Lockword::get_thin_lock_without_count() const
166 {
167         return (_lockword & ~THIN_LOCK_COUNT_MASK);
168 }
169
170
171 int32_t Lockword::get_thin_lock_count() const
172 {
173         return (int32_t) (_lockword & THIN_LOCK_COUNT_MASK) >> THIN_LOCK_COUNT_SHIFT;
174 }
175
176
177 int32_t Lockword::get_thin_lock_thread_index() const
178 {
179         return (int32_t) (_lockword >> THIN_LOCK_TID_SHIFT);
180 }
181
182
183 struct lock_record_t* Lockword::get_fat_lock() const
184 {
185         return (struct lock_record_t*) (_lockword & ~THIN_LOCK_SHAPE_BIT);
186 }
187
188
189 void Lockword::set(uintptr_t lockword)
190 {
191         _lockword = lockword;
192 }
193
194
195 void Lockword::set(struct lock_record_t* lr)
196 {
197         _lockword = ((uintptr_t) lr) | THIN_LOCK_SHAPE_BIT;
198 }
199
200
201 bool Lockword::is_max_thin_lock_count() const
202 {
203         return (get_thin_lock_count() >= THIN_LOCK_COUNT_MAX);
204 }
205
206
207 void Lockword::increase_thin_lock_count()
208 {
209         // Sanity check.
210         assert(get_thin_lock_count() < THIN_LOCK_COUNT_MAX);
211
212         _lockword += (1 << THIN_LOCK_COUNT_SHIFT);
213 }
214
215
216 void Lockword::decrease_thin_lock_count()
217 {
218         // Sanity check.
219         assert(get_thin_lock_count() > 0);
220
221         _lockword -= (1 << THIN_LOCK_COUNT_SHIFT);
222 }
223
224 #else
225
226 // This structure must have the same layout as the C++ class above.
227 typedef struct Lockword {
228         uintptr_t _lockword;
229 } Lockword;
230
231 #endif
232
233 #endif // _LOCKWORD_HPP
234
235
236 /*
237  * These are local overrides for various environment variables in Emacs.
238  * Please do not remove this and leave it at the end of the file, where
239  * Emacs will automagically detect them.
240  * ---------------------------------------------------------------------
241  * Local variables:
242  * mode: c++
243  * indent-tabs-mode: t
244  * c-basic-offset: 4
245  * tab-width: 4
246  * End:
247  * vim:noexpandtab:sw=4:ts=4:
248  */