Skip to content

Commit 175e795

Browse files
authored
Merge pull request #119 from janciesko/lock_API_extension
Add support for recursive locks with external lock allocation
2 parents 8e0f1f1 + 9f66114 commit 175e795

File tree

4 files changed

+182
-49
lines changed

4 files changed

+182
-49
lines changed

include/qt_atomics.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,6 @@ extern pthread_mutexattr_t _fastlock_attr;
144144
&& defined(QTHREAD_ATOMIC_INCR) \
145145
&& !defined(QTHREAD_MUTEX_INCREMENT)
146146

147-
typedef union qt_spin_trylock_s {
148-
aligned_t u;
149-
struct {
150-
haligned_t ticket;
151-
haligned_t users;
152-
} s;
153-
} Q_ALIGNED(QTHREAD_ALIGNMENT_ALIGNED_T) qt_spin_trylock_t;
154147

155148
# define QTHREAD_TRYLOCK_TYPE qt_spin_trylock_t
156149
# define QTHREAD_TRYLOCK_INIT(x) { (x).u = 0; }

include/qthread/qthread.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,28 @@ int qthread_queue_destroy(qthread_queue_t q);
456456
* (full, no waiters) state at any one time.
457457
*/
458458

459+
#define QTHREAD_SPINLOCK_IS_RECURSIVE (-1)
460+
#define QTHREAD_SPINLOCK_IS_NOT_RECURSIVE (-2)
461+
462+
typedef union qt_spin_trylock_s {
463+
aligned_t u;
464+
struct {
465+
haligned_t ticket;
466+
haligned_t users;
467+
} s;
468+
} Q_ALIGNED(QTHREAD_ALIGNMENT_ALIGNED_T) qt_spin_trylock_t;
469+
470+
typedef struct {
471+
int64_t s;
472+
int64_t count;
473+
} qthread_spinlock_state_t;
474+
475+
typedef struct {
476+
qt_spin_trylock_t lock;
477+
qthread_spinlock_state_t state;
478+
} qthread_spinlock_t;
479+
480+
459481
/* This function is just to assist with debugging; it returns 1 if the address
460482
* is full, and 0 if the address is empty */
461483
int qthread_feb_status(const aligned_t *addr);
@@ -587,6 +609,21 @@ int qthread_lock(const aligned_t *a);
587609
int qthread_unlock(const aligned_t *a);
588610
int qthread_trylock(const aligned_t *a);
589611

612+
int qthread_spinlock_init(qthread_spinlock_t *a, const bool is_recursive);
613+
int qthread_spinlock_destroy(qthread_spinlock_t *a);
614+
int qthread_spinlock_lock(qthread_spinlock_t *a);
615+
int qthread_spinlock_unlock(qthread_spinlock_t *a);
616+
int qthread_spinlock_trylock(qthread_spinlock_t *a);
617+
618+
int qthread_spinlocks_init(qthread_spinlock_t *a, const bool is_recursive);
619+
int qthread_spinlocks_destroy(qthread_spinlock_t *a);
620+
621+
#define QTHREAD_SPINLOCK_IS_RECURSIVE (-1)
622+
#define QTHREAD_SPINLOCK_IS_NOT_RECURSIVE (-2)
623+
624+
#define QTHREAD_MUTEX_INITIALIZER {{.s={0,0}},{QTHREAD_SPINLOCK_IS_NOT_RECURSIVE,0}}
625+
#define QTHREAD_RECURSIVE_MUTEX_INITIALIZER {{.s={0,0}},{QTHREAD_SPINLOCK_IS_RECURSIVE,0}}
626+
590627
/* functions to implement spinlock-based locking/unlocking
591628
* if qthread_lock_init(adr) is called, subsequent locking over adr
592629
* uses spin locking instead of FEBs. Support recursive locking.

src/locks.c

Lines changed: 141 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,7 @@
1818

1919
#define SPINLOCK_IS_RECURSIVE (-1)
2020
#define SPINLOCK_IS_NOT_RECURSIVE (-2)
21-
22-
typedef struct {
23-
int64_t s;
24-
int64_t count;
25-
} qthread_spinlock_state_t;
2621

27-
typedef struct {
28-
qt_spin_trylock_t lock;
29-
qthread_spinlock_state_t state;
30-
} qthread_spinlock_t;
3122

3223
#define QTHREAD_CHOOSE_STRIPE2(addr) (qt_hash64((uint64_t)(uintptr_t)addr) & (QTHREAD_LOCKING_STRIPES - 1))
3324
#define LOCKBIN(key) QTHREAD_CHOOSE_STRIPE2(key)
@@ -66,16 +57,31 @@ INTERNAL int lock_hashmap_remove(const aligned_t * key) {
6657
return QTHREAD_OPFAIL;
6758
}
6859

69-
INTERNAL bool qthread_is_spin_lock(const aligned_t * a) {
60+
INTERNAL bool is_spin_lock_hashed(const aligned_t * a) {
7061
return (NULL != lock_hashmap_get(a));
7162
}
7263

73-
INTERNAL int qthread_spinlock_initialize() {
64+
INTERNAL int spinlocks_initialize() {
7465
qthread_spinlock_buckets = NULL;
7566
return QTHREAD_SUCCESS;
7667
}
7768

78-
INTERNAL int qthread_spinlock_init(const aligned_t * a, const bool is_recursive) {
69+
INTERNAL int spinlocks_finalize() {
70+
if(qthread_spinlock_buckets){
71+
for (unsigned i = 0; i < QTHREAD_LOCKING_STRIPES; i++) {
72+
assert(qthread_spinlock_buckets[i]);
73+
qt_hash_destroy_deallocate(qthread_spinlock_buckets[i],
74+
(qt_hash_deallocator_fn)
75+
qthread_spinlock_destroy_fn);
76+
}
77+
qt_free(qthread_spinlock_buckets);
78+
}
79+
return QTHREAD_SUCCESS;
80+
}
81+
82+
/* locks over addresses using internal hashmaps */
83+
84+
INTERNAL int spinlock_init_hashed(const aligned_t * a, const bool is_recursive) {
7985
uint_fast8_t need_sync = 1;
8086

8187
if(!qthread_spinlock_buckets){
@@ -87,7 +93,7 @@ INTERNAL int qthread_spinlock_init(const aligned_t * a, const bool is_recursive)
8793
}
8894
}
8995

90-
if (!qthread_is_spin_lock(a)) {
96+
if (!is_spin_lock_hashed(a)) {
9197
qthread_spinlock_t * l = qt_malloc (sizeof(qthread_spinlock_t));
9298
assert(l);
9399
l->state.s = is_recursive ? SPINLOCK_IS_RECURSIVE : SPINLOCK_IS_NOT_RECURSIVE;
@@ -99,25 +105,98 @@ INTERNAL int qthread_spinlock_init(const aligned_t * a, const bool is_recursive)
99105
return QTHREAD_OPFAIL;
100106
}
101107

102-
INTERNAL int qthread_spinlock_destroy(const aligned_t * a) {
108+
INTERNAL int spinlock_destroy_hashed(const aligned_t * a) {
103109
return lock_hashmap_remove(a);
104110
}
105111

106-
INTERNAL int qthread_spinlock_finalize() {
107-
if(qthread_spinlock_buckets){
108-
for (unsigned i = 0; i < QTHREAD_LOCKING_STRIPES; i++) {
109-
assert(qthread_spinlock_buckets[i]);
110-
qt_hash_destroy_deallocate(qthread_spinlock_buckets[i],
111-
(qt_hash_deallocator_fn)
112-
qthread_spinlock_destroy_fn);
112+
INTERNAL int spinlock_lock_hashed(const aligned_t * a) {
113+
qthread_spinlock_t * l = lock_hashmap_get(a);
114+
if (l != NULL) {
115+
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
116+
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){ // Reentrant
117+
++l->state.count;
118+
MACHINE_FENCE;
119+
}else {
120+
QTHREAD_TRYLOCK_LOCK(&l->lock);
121+
l->state.s = qthread_readstate(CURRENT_UNIQUE_WORKER);
122+
++l->state.count;
123+
MACHINE_FENCE;
124+
}
125+
} else {
126+
QTHREAD_TRYLOCK_LOCK(&l->lock);
113127
}
114-
qt_free(qthread_spinlock_buckets);
128+
return QTHREAD_SUCCESS;
115129
}
116-
return QTHREAD_SUCCESS;
130+
return QTHREAD_OPFAIL;
117131
}
118132

119-
INTERNAL int qthread_spinlock_lock(const aligned_t * a) {
133+
INTERNAL int spinlock_trylock_hashed(const aligned_t * a) {
120134
qthread_spinlock_t * l = lock_hashmap_get(a);
135+
if (l != NULL) {
136+
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
137+
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){ // Reentrant
138+
++l->state.count;
139+
MACHINE_FENCE;
140+
}else {
141+
if(QTHREAD_TRYLOCK_TRY(&l->lock)) {
142+
l->state.s = qthread_readstate(CURRENT_UNIQUE_WORKER);
143+
++l->state.count;
144+
MACHINE_FENCE;
145+
} else {
146+
return QTHREAD_OPFAIL;
147+
}
148+
}
149+
} else {
150+
return QTHREAD_TRYLOCK_TRY(&l->lock);
151+
152+
}
153+
return QTHREAD_SUCCESS;
154+
}
155+
return QTHREAD_OPFAIL;
156+
}
157+
158+
INTERNAL int spinlock_unlock_hashed(const aligned_t * a) {
159+
qthread_spinlock_t * l = lock_hashmap_get(a);
160+
if (l != NULL) {
161+
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
162+
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){
163+
--l->state.count;
164+
if(!l->state.count) {
165+
l->state.s = SPINLOCK_IS_RECURSIVE; // Reset
166+
MACHINE_FENCE;
167+
QTHREAD_TRYLOCK_UNLOCK(&l->lock);
168+
}
169+
}else {
170+
if(l->state.count)
171+
return QTHREAD_OPFAIL;
172+
}
173+
} else {
174+
QTHREAD_TRYLOCK_UNLOCK(&l->lock);
175+
}
176+
return QTHREAD_SUCCESS;
177+
}
178+
return QTHREAD_OPFAIL;
179+
}
180+
181+
/* locks over lock types externally allocated */
182+
183+
INTERNAL int spinlock_init(qthread_spinlock_t * a, const bool is_recursive) {
184+
if (is_recursive) {
185+
const qthread_spinlock_t init_mutex = QTHREAD_RECURSIVE_MUTEX_INITIALIZER;
186+
memcpy(a, &init_mutex, sizeof(qthread_spinlock_t));
187+
} else {
188+
const qthread_spinlock_t init_mutex = QTHREAD_MUTEX_INITIALIZER;
189+
memcpy(a, &init_mutex, sizeof(qthread_spinlock_t));
190+
}
191+
return QTHREAD_SUCCESS;
192+
}
193+
194+
INTERNAL int spinlock_destroy(qthread_spinlock_t * a) {
195+
return QTHREAD_SUCCESS;
196+
}
197+
198+
INTERNAL int spinlock_lock(qthread_spinlock_t * a) {
199+
qthread_spinlock_t * l = a;
121200
if (l != NULL) {
122201
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
123202
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){ // Reentrant
@@ -137,8 +216,8 @@ INTERNAL int qthread_spinlock_lock(const aligned_t * a) {
137216
return QTHREAD_OPFAIL;
138217
}
139218

140-
INTERNAL int qthread_spinlock_trylock(const aligned_t * a) {
141-
qthread_spinlock_t * l = lock_hashmap_get(a);
219+
INTERNAL int spinlock_trylock(qthread_spinlock_t * a) {
220+
qthread_spinlock_t * l = a;
142221
if (l != NULL) {
143222
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
144223
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){ // Reentrant
@@ -162,8 +241,8 @@ INTERNAL int qthread_spinlock_trylock(const aligned_t * a) {
162241
return QTHREAD_OPFAIL;
163242
}
164243

165-
INTERNAL int qthread_spinlock_unlock(const aligned_t * a) {
166-
qthread_spinlock_t * l = lock_hashmap_get(a);
244+
INTERNAL int spinlock_unlock(qthread_spinlock_t * a) {
245+
qthread_spinlock_t * l = a;
167246
if (l != NULL) {
168247
if (l->state.s >= SPINLOCK_IS_RECURSIVE) {
169248
if(l->state.s == qthread_readstate(CURRENT_UNIQUE_WORKER)){
@@ -189,39 +268,64 @@ INTERNAL int qthread_spinlock_unlock(const aligned_t * a) {
189268

190269
int API_FUNC qthread_lock_init(const aligned_t *a, const bool is_recursive)
191270
{ /*{{{ */
192-
return qthread_spinlock_init(a, is_recursive);
271+
return spinlock_init_hashed(a, is_recursive);
193272
} /*}}} */
194273

195274
int API_FUNC qthread_lock_destroy(aligned_t *a)
196275
{ /*{{{ */
197-
if (!qthread_is_spin_lock(a)) {
276+
if (!is_spin_lock_hashed(a)) {
198277
return QTHREAD_SUCCESS;
199278
}
200-
return qthread_spinlock_destroy(a);
279+
return spinlock_destroy_hashed(a);
201280
} /*}}} */
202281

203282
int API_FUNC qthread_lock(const aligned_t *a)
204283
{ /*{{{ */
205-
if (!qthread_is_spin_lock(a)) {
284+
if (!is_spin_lock_hashed(a)) {
206285
return qthread_readFE(NULL, a);
207286
}
208-
return qthread_spinlock_lock(a);
287+
return spinlock_lock_hashed(a);
209288
} /*}}} */
210289

211290
int API_FUNC qthread_trylock(const aligned_t *a)
212291
{ /*{{{ */
213-
if (!qthread_is_spin_lock(a)){
292+
if (!is_spin_lock_hashed(a)){
214293
return qthread_readFE_nb(NULL, a);
215294
}
216-
return qthread_spinlock_trylock(a);
295+
return spinlock_trylock_hashed(a);
217296
} /*}}} */
218297

219298
int API_FUNC qthread_unlock(const aligned_t *a)
220299
{ /*{{{ */
221-
if (!qthread_is_spin_lock(a)) {
300+
if (!is_spin_lock_hashed(a)) {
222301
return qthread_fill(a);
223302
}
224-
return qthread_spinlock_unlock(a);
303+
return spinlock_unlock_hashed(a);
304+
} /*}}} */
305+
306+
int API_FUNC qthread_spinlock_init(qthread_spinlock_t *a, const bool is_recursive)
307+
{ /*{{{ */
308+
return spinlock_init(a, is_recursive);
309+
} /*}}} */
310+
311+
int API_FUNC qthread_spinlock_destroy(qthread_spinlock_t *a)
312+
{ /*{{{ */
313+
return spinlock_destroy(a);
314+
} /*}}} */
315+
316+
int API_FUNC qthread_spinlock_lock(qthread_spinlock_t *a)
317+
{ /*{{{ */
318+
return spinlock_lock(a);
319+
} /*}}} */
320+
321+
int API_FUNC qthread_spinlock_trylock(qthread_spinlock_t *a)
322+
{ /*{{{ */
323+
return spinlock_trylock(a);
324+
} /*}}} */
325+
326+
int API_FUNC qthread_spinlock_unlock(qthread_spinlock_t *a)
327+
{ /*{{{ */
328+
return spinlock_unlock(a);
225329
} /*}}} */
226330

227331
#undef qt_hash_t

src/qthread.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,8 @@ int GUARD_PAGES = 1;
132132
#define GUARD_PAGES 0
133133
#endif
134134

135-
//extern qt_hash * qthread_spinlock_buckets;
136-
extern int INTERNAL qthread_spinlock_finalize();
137-
extern int INTERNAL qthread_spinlock_initialize();
135+
extern int INTERNAL spinlocks_finalize();
136+
extern int INTERNAL spinlocks_initialize();
138137

139138
/* Internal Prototypes */
140139
#ifdef QTHREAD_MAKECONTEXT_SPLIT
@@ -1016,7 +1015,7 @@ int API_FUNC qthread_initialize(void)
10161015
qthread_debug(SHEPHERD_DETAILS, "shepherd %i set up (%p)\n", i, &qlib->shepherds[i]);
10171016
}
10181017

1019-
qthread_spinlock_initialize();
1018+
spinlocks_initialize();
10201019

10211020
qthread_debug(SHEPHERD_DETAILS, "done setting up shepherds.\n");
10221021

@@ -1574,7 +1573,7 @@ void API_FUNC qthread_finalize(void)
15741573
qthread_debug(CORE_DETAILS, "freeing shep0's threadqueue\n");
15751574
qt_threadqueue_free(shep0->ready);
15761575

1577-
qthread_spinlock_finalize();
1576+
spinlocks_finalize();
15781577

15791578
qthread_debug(CORE_DETAILS, "calling cleanup functions\n");
15801579
while (qt_cleanup_funcs != NULL) {

0 commit comments

Comments
 (0)