mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / include / sync0rw.ic
blob2a674f00262092c19c759c1bac004ca8bf341d47
1 /******************************************************
2 The read-write lock (for threads)
4 (c) 1995 Innobase Oy
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. */
15 void
16 rw_lock_s_lock_spin(
17 /*================*/
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. */
27 void
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. */
38 void
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. */
48 UNIV_INLINE
49 ulint
50 rw_lock_get_waiters(
51 /*================*/
52         rw_lock_t*      lock)
54         return(lock->waiters);
56 UNIV_INLINE
57 void
58 rw_lock_set_waiters(
59 /*================*/
60         rw_lock_t*      lock,
61         ulint           flag)
63         lock->waiters = flag;
65 UNIV_INLINE
66 ulint
67 rw_lock_get_writer(
68 /*===============*/
69         rw_lock_t*      lock)
71         return(lock->writer);
73 UNIV_INLINE
74 void
75 rw_lock_set_writer(
76 /*===============*/
77         rw_lock_t*      lock,
78         ulint           flag)
80         lock->writer = flag;
82 UNIV_INLINE
83 ulint
84 rw_lock_get_reader_count(
85 /*=====================*/
86         rw_lock_t*      lock)
88         return(lock->reader_count);
90 UNIV_INLINE
91 void
92 rw_lock_set_reader_count(
93 /*=====================*/
94         rw_lock_t*      lock,
95         ulint           count)
97         lock->reader_count = count;
99 UNIV_INLINE
100 mutex_t*
101 rw_lock_get_mutex(
102 /*==============*/
103         rw_lock_t*      lock)
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. */
111 UNIV_INLINE
112 ulint
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
123 spinning. */
124 UNIV_INLINE
125 ibool
126 rw_lock_s_lock_low(
127 /*===============*/
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,
146                                        line);
147 #endif
148                 lock->last_s_file_name = file_name;
149                 lock->last_s_line = line;
151                 return(TRUE);   /* locking succeeded */
152         }
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. */
161 UNIV_INLINE
162 void
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);
180 #endif
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. */
187 UNIV_INLINE
188 void
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++;
202         lock->pass = 0;
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);
209 #endif
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. */
218 UNIV_INLINE
219 void
220 rw_lock_s_lock_func(
221 /*================*/
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
237         time. */
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 */
250         } else {
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);
256                 return;
257         }
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
263 immediately. */
264 UNIV_INLINE
265 ibool
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,
283                                        line);
284 #endif
286                 lock->last_s_file_name = file_name;
287                 lock->last_s_line = line;
289                 success = TRUE;
290         }
292         mutex_exit(rw_lock_get_mutex(lock));
294         return(success);
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. */
301 UNIV_INLINE
302 ibool
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;
319                 lock->pass = 0;
320 relock:
321                 lock->writer_count++;
323 #ifdef UNIV_SYNC_DEBUG
324                 rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
325 #endif
327                 lock->last_x_file_name = file_name;
328                 lock->last_x_line = line;
330                 success = TRUE;
331         } else if (rw_lock_get_writer(lock) == RW_LOCK_EX
332                    && lock->pass == 0
333                    && os_thread_eq(lock->writer_thread, curr_thread)) {
334                 goto relock;
335         }
337         mutex_exit(rw_lock_get_mutex(lock));
339         ut_ad(rw_lock_validate(lock));
341         return(success);
344 /**********************************************************************
345 Releases a shared mode lock. */
346 UNIV_INLINE
347 void
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 */
354 #endif
355         )
357         mutex_t*        mutex   = &(lock->mutex);
358         ibool           sg      = FALSE;
360         /* Acquire the mutex protecting the rw-lock fields */
361         mutex_enter(mutex);
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);
370 #endif
372         /* If there may be waiters and this was the last s-lock,
373         signal the object */
375         if (UNIV_UNLIKELY(lock->waiters)
376             && lock->reader_count == 0) {
377                 sg = TRUE;
379                 rw_lock_set_waiters(lock, 0);
380         }
382         mutex_exit(mutex);
384         if (UNIV_UNLIKELY(sg)) {
385 #ifdef __WIN__
386                 os_event_set(lock->wait_ex_event);
387 #endif
388                 os_event_set(lock->event);
389                 sync_array_object_signalled(sync_primary_wait_array);
390         }
392         ut_ad(rw_lock_validate(lock));
394 #ifdef UNIV_SYNC_PERF_STAT
395         rw_s_exit_count++;
396 #endif
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. */
402 UNIV_INLINE
403 void
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);
416 #endif
418         ut_ad(!lock->waiters);
419         ut_ad(rw_lock_validate(lock));
420 #ifdef UNIV_SYNC_PERF_STAT
421         rw_s_exit_count++;
422 #endif
425 /**********************************************************************
426 Releases an exclusive mode lock. */
427 UNIV_INLINE
428 void
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 */
435 #endif
436         )
438         ibool   sg      = FALSE;
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
444         lock */
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);
452         }
454 #ifdef UNIV_SYNC_DEBUG
455         rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
456 #endif
458         /* If there may be waiters, signal the lock */
459         if (UNIV_UNLIKELY(lock->waiters)
460             && lock->writer_count == 0) {
462                 sg = TRUE;
463                 rw_lock_set_waiters(lock, 0);
464         }
466         mutex_exit(&(lock->mutex));
468         if (UNIV_UNLIKELY(sg)) {
469 #ifdef __WIN__
470                 os_event_set(lock->wait_ex_event);
471 #endif
472                 os_event_set(lock->event);
473                 sync_array_object_signalled(sync_primary_wait_array);
474         }
476         ut_ad(rw_lock_validate(lock));
478 #ifdef UNIV_SYNC_PERF_STAT
479         rw_x_exit_count++;
480 #endif
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. */
486 UNIV_INLINE
487 void
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
493         lock */
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);
501         }
503 #ifdef UNIV_SYNC_DEBUG
504         rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
505 #endif
507         ut_ad(!lock->waiters);
508         ut_ad(rw_lock_validate(lock));
510 #ifdef UNIV_SYNC_PERF_STAT
511         rw_x_exit_count++;
512 #endif