1 /******************************************************
2 The read-write lock (for threads)
6 Created 9/11/1995 Heikki Tuuri
7 *******************************************************/
9 /**********************************************************************
10 Lock an rw-lock in shared mode for the current thread. If the rw-lock is
11 locked in exclusive mode, or there is an exclusive lock request waiting,
12 the function spins a preset time (controlled by SYNC_SPIN_ROUNDS),
13 waiting for the lock before suspending the thread. */
18 rw_lock_t* lock, /* in: pointer to rw-lock */
19 ulint pass, /* in: pass value; != 0, if the lock will
20 be passed to another thread to unlock */
21 const char* file_name,/* in: file name where lock requested */
22 ulint line); /* in: line where requested */
23 #ifdef UNIV_SYNC_DEBUG
24 /**********************************************************************
25 Inserts the debug information for an rw-lock. */
28 rw_lock_add_debug_info(
29 /*===================*/
30 rw_lock_t* lock, /* in: rw-lock */
31 ulint pass, /* in: pass value */
32 ulint lock_type, /* in: lock type */
33 const char* file_name, /* in: file where requested */
34 ulint line); /* in: line where requested */
35 /**********************************************************************
36 Removes a debug information struct for an rw-lock. */
39 rw_lock_remove_debug_info(
40 /*======================*/
41 rw_lock_t* lock, /* in: rw-lock */
42 ulint pass, /* in: pass value */
43 ulint lock_type); /* in: lock type */
44 #endif /* UNIV_SYNC_DEBUG */
46 /************************************************************************
47 Accessor functions for rw lock. */
54 return(lock->waiters);
84 rw_lock_get_reader_count(
85 /*=====================*/
88 return(lock->reader_count);
92 rw_lock_set_reader_count(
93 /*=====================*/
97 lock->reader_count = count;
105 return(&(lock->mutex));
108 /**********************************************************************
109 Returns the value of writer_count for the lock. Does not reserve the lock
110 mutex, so the caller must be sure it is not changed during the call. */
113 rw_lock_get_x_lock_count(
114 /*=====================*/
115 /* out: value of writer_count */
116 rw_lock_t* lock) /* in: rw-lock */
118 return(lock->writer_count);
121 /**********************************************************************
122 Low-level function which tries to lock an rw-lock in s-mode. Performs no
128 /* out: TRUE if success */
129 rw_lock_t* lock, /* in: pointer to rw-lock */
130 ulint pass __attribute__((unused)),
131 /* in: pass value; != 0, if the lock will be
132 passed to another thread to unlock */
133 const char* file_name, /* in: file name where lock requested */
134 ulint line) /* in: line where requested */
136 ut_ad(mutex_own(rw_lock_get_mutex(lock)));
138 /* Check if the writer field is free */
140 if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) {
141 /* Set the shared lock by incrementing the reader count */
142 lock->reader_count++;
144 #ifdef UNIV_SYNC_DEBUG
145 rw_lock_add_debug_info(lock, pass, RW_LOCK_SHARED, file_name,
148 lock->last_s_file_name = file_name;
149 lock->last_s_line = line;
151 return(TRUE); /* locking succeeded */
154 return(FALSE); /* locking did not succeed */
157 /**********************************************************************
158 Low-level function which locks an rw-lock in s-mode when we know that it
159 is possible and none else is currently accessing the rw-lock structure.
160 Then we can do the locking without reserving the mutex. */
163 rw_lock_s_lock_direct(
164 /*==================*/
165 rw_lock_t* lock, /* in: pointer to rw-lock */
166 const char* file_name, /* in: file name where requested */
167 ulint line) /* in: line where lock requested */
169 ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
170 ut_ad(rw_lock_get_reader_count(lock) == 0);
172 /* Set the shared lock by incrementing the reader count */
173 lock->reader_count++;
175 lock->last_s_file_name = file_name;
176 lock->last_s_line = line;
178 #ifdef UNIV_SYNC_DEBUG
179 rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
183 /**********************************************************************
184 Low-level function which locks an rw-lock in x-mode when we know that it
185 is not locked and none else is currently accessing the rw-lock structure.
186 Then we can do the locking without reserving the mutex. */
189 rw_lock_x_lock_direct(
190 /*==================*/
191 rw_lock_t* lock, /* in: pointer to rw-lock */
192 const char* file_name, /* in: file name where requested */
193 ulint line) /* in: line where lock requested */
195 ut_ad(rw_lock_validate(lock));
196 ut_ad(rw_lock_get_reader_count(lock) == 0);
197 ut_ad(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
199 rw_lock_set_writer(lock, RW_LOCK_EX);
200 lock->writer_thread = os_thread_get_curr_id();
201 lock->writer_count++;
204 lock->last_x_file_name = file_name;
205 lock->last_x_line = line;
207 #ifdef UNIV_SYNC_DEBUG
208 rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
212 /**********************************************************************
213 NOTE! Use the corresponding macro, not directly this function! Lock an
214 rw-lock in shared mode for the current thread. If the rw-lock is locked
215 in exclusive mode, or there is an exclusive lock request waiting, the
216 function spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for
217 the lock, before suspending the thread. */
222 rw_lock_t* lock, /* in: pointer to rw-lock */
223 ulint pass, /* in: pass value; != 0, if the lock will
224 be passed to another thread to unlock */
225 const char* file_name,/* in: file name where lock requested */
226 ulint line) /* in: line where requested */
228 /* NOTE: As we do not know the thread ids for threads which have
229 s-locked a latch, and s-lockers will be served only after waiting
230 x-lock requests have been fulfilled, then if this thread already
231 owns an s-lock here, it may end up in a deadlock with another thread
232 which requests an x-lock here. Therefore, we will forbid recursive
233 s-locking of a latch: the following assert will warn the programmer
234 of the possibility of this kind of a deadlock. If we want to implement
235 safe recursive s-locking, we should keep in a list the thread ids of
236 the threads which have s-locked a latch. This would use some CPU
239 #ifdef UNIV_SYNC_DEBUG
240 ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
241 ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
242 #endif /* UNIV_SYNC_DEBUG */
244 mutex_enter(rw_lock_get_mutex(lock));
246 if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
247 mutex_exit(rw_lock_get_mutex(lock));
249 return; /* Success */
251 /* Did not succeed, try spin wait */
252 mutex_exit(rw_lock_get_mutex(lock));
254 rw_lock_s_lock_spin(lock, pass, file_name, line);
260 /**********************************************************************
261 NOTE! Use the corresponding macro, not directly this function! Lock an
262 rw-lock in shared mode for the current thread if the lock can be acquired
266 rw_lock_s_lock_func_nowait(
267 /*=======================*/
268 /* out: TRUE if success */
269 rw_lock_t* lock, /* in: pointer to rw-lock */
270 const char* file_name,/* in: file name where lock requested */
271 ulint line) /* in: line where requested */
273 ibool success = FALSE;
275 mutex_enter(rw_lock_get_mutex(lock));
277 if (lock->writer == RW_LOCK_NOT_LOCKED) {
278 /* Set the shared lock by incrementing the reader count */
279 lock->reader_count++;
281 #ifdef UNIV_SYNC_DEBUG
282 rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
286 lock->last_s_file_name = file_name;
287 lock->last_s_line = line;
292 mutex_exit(rw_lock_get_mutex(lock));
297 /**********************************************************************
298 NOTE! Use the corresponding macro, not directly this function! Lock an
299 rw-lock in exclusive mode for the current thread if the lock can be
300 obtained immediately. */
303 rw_lock_x_lock_func_nowait(
304 /*=======================*/
305 /* out: TRUE if success */
306 rw_lock_t* lock, /* in: pointer to rw-lock */
307 const char* file_name,/* in: file name where lock requested */
308 ulint line) /* in: line where requested */
310 ibool success = FALSE;
311 os_thread_id_t curr_thread = os_thread_get_curr_id();
312 mutex_enter(rw_lock_get_mutex(lock));
314 if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) {
315 } else if (UNIV_LIKELY(rw_lock_get_writer(lock)
316 == RW_LOCK_NOT_LOCKED)) {
317 rw_lock_set_writer(lock, RW_LOCK_EX);
318 lock->writer_thread = curr_thread;
321 lock->writer_count++;
323 #ifdef UNIV_SYNC_DEBUG
324 rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
327 lock->last_x_file_name = file_name;
328 lock->last_x_line = line;
331 } else if (rw_lock_get_writer(lock) == RW_LOCK_EX
333 && os_thread_eq(lock->writer_thread, curr_thread)) {
337 mutex_exit(rw_lock_get_mutex(lock));
339 ut_ad(rw_lock_validate(lock));
344 /**********************************************************************
345 Releases a shared mode lock. */
348 rw_lock_s_unlock_func(
349 /*==================*/
350 rw_lock_t* lock /* in: rw-lock */
351 #ifdef UNIV_SYNC_DEBUG
352 ,ulint pass /* in: pass value; != 0, if the lock may have
353 been passed to another thread to unlock */
357 mutex_t* mutex = &(lock->mutex);
360 /* Acquire the mutex protecting the rw-lock fields */
363 /* Reset the shared lock by decrementing the reader count */
365 ut_a(lock->reader_count > 0);
366 lock->reader_count--;
368 #ifdef UNIV_SYNC_DEBUG
369 rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
372 /* If there may be waiters and this was the last s-lock,
375 if (UNIV_UNLIKELY(lock->waiters)
376 && lock->reader_count == 0) {
379 rw_lock_set_waiters(lock, 0);
384 if (UNIV_UNLIKELY(sg)) {
386 os_event_set(lock->wait_ex_event);
388 os_event_set(lock->event);
389 sync_array_object_signalled(sync_primary_wait_array);
392 ut_ad(rw_lock_validate(lock));
394 #ifdef UNIV_SYNC_PERF_STAT
399 /**********************************************************************
400 Releases a shared mode lock when we know there are no waiters and none
401 else will access the lock during the time this function is executed. */
404 rw_lock_s_unlock_direct(
405 /*====================*/
406 rw_lock_t* lock) /* in: rw-lock */
408 /* Reset the shared lock by decrementing the reader count */
410 ut_ad(lock->reader_count > 0);
412 lock->reader_count--;
414 #ifdef UNIV_SYNC_DEBUG
415 rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
418 ut_ad(!lock->waiters);
419 ut_ad(rw_lock_validate(lock));
420 #ifdef UNIV_SYNC_PERF_STAT
425 /**********************************************************************
426 Releases an exclusive mode lock. */
429 rw_lock_x_unlock_func(
430 /*==================*/
431 rw_lock_t* lock /* in: rw-lock */
432 #ifdef UNIV_SYNC_DEBUG
433 ,ulint pass /* in: pass value; != 0, if the lock may have
434 been passed to another thread to unlock */
440 /* Acquire the mutex protecting the rw-lock fields */
441 mutex_enter(&(lock->mutex));
443 /* Reset the exclusive lock if this thread no longer has an x-mode
446 ut_ad(lock->writer_count > 0);
448 lock->writer_count--;
450 if (lock->writer_count == 0) {
451 rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
454 #ifdef UNIV_SYNC_DEBUG
455 rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
458 /* If there may be waiters, signal the lock */
459 if (UNIV_UNLIKELY(lock->waiters)
460 && lock->writer_count == 0) {
463 rw_lock_set_waiters(lock, 0);
466 mutex_exit(&(lock->mutex));
468 if (UNIV_UNLIKELY(sg)) {
470 os_event_set(lock->wait_ex_event);
472 os_event_set(lock->event);
473 sync_array_object_signalled(sync_primary_wait_array);
476 ut_ad(rw_lock_validate(lock));
478 #ifdef UNIV_SYNC_PERF_STAT
483 /**********************************************************************
484 Releases an exclusive mode lock when we know there are no waiters, and
485 none else will access the lock durint the time this function is executed. */
488 rw_lock_x_unlock_direct(
489 /*====================*/
490 rw_lock_t* lock) /* in: rw-lock */
492 /* Reset the exclusive lock if this thread no longer has an x-mode
495 ut_ad(lock->writer_count > 0);
497 lock->writer_count--;
499 if (lock->writer_count == 0) {
500 rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
503 #ifdef UNIV_SYNC_DEBUG
504 rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
507 ut_ad(!lock->waiters);
508 ut_ad(rw_lock_validate(lock));
510 #ifdef UNIV_SYNC_PERF_STAT