2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
27 char padding
[mutex_padding_size
];
28 } attr_aligned(64) address_hash
[N_POINTER_DEPTHS
][POINTER_HASH_SIZE
];
33 char padding
[rwmutex_padding_size
];
34 } attr_aligned(64) address_rwmutex_hash
[POINTER_HASH_SIZE
];
36 #if defined(DEBUG) || defined(DEBUG_ALLOC_INSIDE_LOCKS)
41 static bool address_hash_initialized
= false;
44 static unsigned address_hash_value(const void *p
)
46 uintptr_t num
= ptr_to_num(p
);
47 return (unsigned)(num
^ (num
>> POINTER_HASH_BITS
) ^ (num
>> POINTER_HASH_BITS
* 2)) & (POINTER_HASH_SIZE
- 1);
50 void attr_fastcall
address_lock(const void *p
, addrlock_depth d
)
54 if (unlikely(!address_hash_initialized
))
55 internal(file_line
, "address_lock: address_hash_initialized not set");
57 hash
= address_hash_value(p
);
58 mutex_lock(&address_hash
[d
][hash
].lock
);
61 void attr_fastcall
address_unlock(const void *p
, addrlock_depth d
)
65 if (unlikely(!address_hash_initialized
))
66 internal(file_line
, "address_unlock: address_hash_initialized not set");
68 hash
= address_hash_value(p
);
69 mutex_unlock(&address_hash
[d
][hash
].lock
);
72 void attr_fastcall
address_lock_two(const void *p1
, const void *p2
, addrlock_depth d
)
74 unsigned hash1
, hash2
;
76 if (unlikely(!address_hash_initialized
))
77 internal(file_line
, "address_lock_two: address_hash_initialized not set");
79 hash1
= address_hash_value(p1
);
80 hash2
= address_hash_value(p2
);
82 mutex_lock(&address_hash
[d
][hash1
].lock
);
83 mutex_lock(&address_hash
[d
][hash2
].lock
);
84 } else if (likely(hash1
> hash2
)) {
85 mutex_lock(&address_hash
[d
][hash2
].lock
);
86 mutex_lock(&address_hash
[d
][hash1
].lock
);
88 mutex_lock(&address_hash
[d
][hash1
].lock
);
92 bool attr_fastcall
address_trylock_second(const void *p1
, const void *p2
, addrlock_depth d
)
94 unsigned hash1
, hash2
;
96 if (unlikely(!address_hash_initialized
))
97 internal(file_line
, "address_trylock_second: address_hash_initialized not set");
99 hash1
= address_hash_value(p1
);
100 hash2
= address_hash_value(p2
);
102 mutex_lock(&address_hash
[d
][hash2
].lock
);
105 if (likely(hash1
> hash2
)) {
106 return mutex_trylock(&address_hash
[d
][hash2
].lock
);
111 void attr_fastcall
address_unlock_second(const void *p1
, const void *p2
, addrlock_depth d
)
113 unsigned hash1
, hash2
;
115 if (unlikely(!address_hash_initialized
))
116 internal(file_line
, "address_unlock_second: address_hash_initialized not set");
118 hash1
= address_hash_value(p1
);
119 hash2
= address_hash_value(p2
);
120 if (likely(hash1
!= hash2
))
121 mutex_unlock(&address_hash
[d
][hash2
].lock
);
124 mutex_t
* attr_fastcall
address_get_mutex(const void *p
, addrlock_depth d
)
128 if (unlikely(!address_hash_initialized
))
129 internal(file_line
, "address_get_mutex: address_hash_initialized not set");
131 hash
= address_hash_value(p
);
132 return &address_hash
[d
][hash
].lock
;
135 void address_read_lock(const void *p
)
139 if (unlikely(!address_hash_initialized
))
140 internal(file_line
, "address_read_lock: address_hash_initialized not set");
142 hash
= address_hash_value(p
);
143 rwmutex_lock_read(&address_rwmutex_hash
[hash
].lock
);
146 void address_read_unlock(const void *p
)
150 if (unlikely(!address_hash_initialized
))
151 internal(file_line
, "address_read_unlock: address_hash_initialized not set");
153 hash
= address_hash_value(p
);
154 rwmutex_unlock_read(&address_rwmutex_hash
[hash
].lock
);
157 void address_write_lock(const void *p
)
161 if (unlikely(!address_hash_initialized
))
162 internal(file_line
, "address_write_lock: address_hash_initialized not set");
164 hash
= address_hash_value(p
);
165 rwmutex_lock_write(&address_rwmutex_hash
[hash
].lock
);
168 void address_write_unlock(const void *p
)
172 if (unlikely(!address_hash_initialized
))
173 internal(file_line
, "address_write_unlock: address_hash_initialized not set");
175 hash
= address_hash_value(p
);
176 rwmutex_unlock_write(&address_rwmutex_hash
[hash
].lock
);
179 #ifdef DEBUG_ALLOC_INSIDE_LOCKS
180 void address_lock_verify(void)
183 if (!address_hash_initialized
)
185 for (i
= 0; i
< N_POINTER_DEPTHS
; i
++) {
186 address_lock(NULL
, i
);
187 address_unlock(NULL
, i
);
189 address_write_lock(NULL
);
190 address_write_unlock(NULL
);
194 void address_lock_init(void)
198 if (unlikely(address_hash_initialized
))
199 internal(file_line
, "address_lock_init: address_hash_initialized already set");
201 for (j
= 0; j
< N_POINTER_DEPTHS
; j
++)
202 for (i
= 0; i
< POINTER_HASH_SIZE
; i
++)
203 mutex_init(&address_hash
[j
][i
].lock
);
204 for (i
= 0; i
< POINTER_HASH_SIZE
; i
++)
205 rwmutex_init(&address_rwmutex_hash
[i
].lock
);
207 address_hash_initialized
= true;
211 void address_lock_done(void)
215 if (unlikely(!address_hash_initialized
))
216 internal(file_line
, "address_lock_done: address_hash_initialized not set");
217 address_hash_initialized
= false;
219 for (j
= 0; j
< N_POINTER_DEPTHS
; j
++)
220 for (i
= 0; i
< POINTER_HASH_SIZE
; i
++)
221 mutex_done(&address_hash
[j
][i
].lock
);
222 for (i
= 0; i
< POINTER_HASH_SIZE
; i
++)
223 rwmutex_done(&address_rwmutex_hash
[i
].lock
);