codegen: support hacked ABI if using pointer compression
[ajla.git] / addrlock.c
blob741047ad58ca6293ceb4dc3bd8f950ddeb5ebb8c
1 /*
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
9 * version.
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/>.
19 #include "ajla.h"
21 #include "thread.h"
23 #include "addrlock.h"
25 static union {
26 mutex_t lock;
27 char padding[mutex_padding_size];
28 } attr_aligned(64) address_hash[N_POINTER_DEPTHS][POINTER_HASH_SIZE];
31 static union {
32 rwmutex_t lock;
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)
37 #define TEST_INIT
38 #endif
40 #ifdef TEST_INIT
41 static bool address_hash_initialized = false;
42 #endif
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)
52 unsigned hash;
53 #ifdef TEST_INIT
54 if (unlikely(!address_hash_initialized))
55 internal(file_line, "address_lock: address_hash_initialized not set");
56 #endif
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)
63 unsigned hash;
64 #ifdef TEST_INIT
65 if (unlikely(!address_hash_initialized))
66 internal(file_line, "address_unlock: address_hash_initialized not set");
67 #endif
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;
75 #ifdef TEST_INIT
76 if (unlikely(!address_hash_initialized))
77 internal(file_line, "address_lock_two: address_hash_initialized not set");
78 #endif
79 hash1 = address_hash_value(p1);
80 hash2 = address_hash_value(p2);
81 if (hash1 < hash2) {
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);
87 } else {
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;
95 #ifdef TEST_INIT
96 if (unlikely(!address_hash_initialized))
97 internal(file_line, "address_trylock_second: address_hash_initialized not set");
98 #endif
99 hash1 = address_hash_value(p1);
100 hash2 = address_hash_value(p2);
101 if (hash1 < hash2) {
102 mutex_lock(&address_hash[d][hash2].lock);
103 return true;
105 if (likely(hash1 > hash2)) {
106 return mutex_trylock(&address_hash[d][hash2].lock);
108 return true;
111 void attr_fastcall address_unlock_second(const void *p1, const void *p2, addrlock_depth d)
113 unsigned hash1, hash2;
114 #ifdef TEST_INIT
115 if (unlikely(!address_hash_initialized))
116 internal(file_line, "address_unlock_second: address_hash_initialized not set");
117 #endif
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)
126 unsigned hash;
127 #ifdef TEST_INIT
128 if (unlikely(!address_hash_initialized))
129 internal(file_line, "address_get_mutex: address_hash_initialized not set");
130 #endif
131 hash = address_hash_value(p);
132 return &address_hash[d][hash].lock;
135 void address_read_lock(const void *p)
137 unsigned hash;
138 #ifdef TEST_INIT
139 if (unlikely(!address_hash_initialized))
140 internal(file_line, "address_read_lock: address_hash_initialized not set");
141 #endif
142 hash = address_hash_value(p);
143 rwmutex_lock_read(&address_rwmutex_hash[hash].lock);
146 void address_read_unlock(const void *p)
148 unsigned hash;
149 #ifdef TEST_INIT
150 if (unlikely(!address_hash_initialized))
151 internal(file_line, "address_read_unlock: address_hash_initialized not set");
152 #endif
153 hash = address_hash_value(p);
154 rwmutex_unlock_read(&address_rwmutex_hash[hash].lock);
157 void address_write_lock(const void *p)
159 unsigned hash;
160 #ifdef TEST_INIT
161 if (unlikely(!address_hash_initialized))
162 internal(file_line, "address_write_lock: address_hash_initialized not set");
163 #endif
164 hash = address_hash_value(p);
165 rwmutex_lock_write(&address_rwmutex_hash[hash].lock);
168 void address_write_unlock(const void *p)
170 unsigned hash;
171 #ifdef TEST_INIT
172 if (unlikely(!address_hash_initialized))
173 internal(file_line, "address_write_unlock: address_hash_initialized not set");
174 #endif
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)
182 addrlock_depth i;
183 if (!address_hash_initialized)
184 return;
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);
192 #endif
194 void address_lock_init(void)
196 unsigned i, j;
197 #ifdef TEST_INIT
198 if (unlikely(address_hash_initialized))
199 internal(file_line, "address_lock_init: address_hash_initialized already set");
200 #endif
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);
206 #ifdef TEST_INIT
207 address_hash_initialized = true;
208 #endif
211 void address_lock_done(void)
213 unsigned i, j;
214 #ifdef TEST_INIT
215 if (unlikely(!address_hash_initialized))
216 internal(file_line, "address_lock_done: address_hash_initialized not set");
217 address_hash_initialized = false;
218 #endif
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);