~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/include/sync0rw.ic

  • Committer: Monty Taylor
  • Date: 2008-09-16 01:37:05 UTC
  • mto: This revision was merged to the branch mainline in revision 391.
  • Revision ID: monty@inaugust.com-20080916013705-772d1t7rh9ah9j1x
Moved more functions into drizzle.c as part of the split of code.
Added accessor function for drizzle_port.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The read-write lock (for threads)
 
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
 
6
Created 9/11/1995 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
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. */
 
14
 
 
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. */
 
26
 
 
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. */
 
37
 
 
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 */
 
45
 
 
46
/************************************************************************
 
47
Accessor functions for rw lock. */
 
48
UNIV_INLINE
 
49
ulint
 
50
rw_lock_get_waiters(
 
51
/*================*/
 
52
        rw_lock_t*      lock)
 
53
{
 
54
        return(lock->waiters);
 
55
}
 
56
UNIV_INLINE
 
57
void
 
58
rw_lock_set_waiters(
 
59
/*================*/
 
60
        rw_lock_t*      lock,
 
61
        ulint           flag)
 
62
{
 
63
        lock->waiters = flag;
 
64
}
 
65
UNIV_INLINE
 
66
ulint
 
67
rw_lock_get_writer(
 
68
/*===============*/
 
69
        rw_lock_t*      lock)
 
70
{
 
71
        return(lock->writer);
 
72
}
 
73
UNIV_INLINE
 
74
void
 
75
rw_lock_set_writer(
 
76
/*===============*/
 
77
        rw_lock_t*      lock,
 
78
        ulint           flag)
 
79
{
 
80
        lock->writer = flag;
 
81
}
 
82
UNIV_INLINE
 
83
ulint
 
84
rw_lock_get_reader_count(
 
85
/*=====================*/
 
86
        rw_lock_t*      lock)
 
87
{
 
88
        return(lock->reader_count);
 
89
}
 
90
UNIV_INLINE
 
91
void
 
92
rw_lock_set_reader_count(
 
93
/*=====================*/
 
94
        rw_lock_t*      lock,
 
95
        ulint           count)
 
96
{
 
97
        lock->reader_count = count;
 
98
}
 
99
UNIV_INLINE
 
100
mutex_t*
 
101
rw_lock_get_mutex(
 
102
/*==============*/
 
103
        rw_lock_t*      lock)
 
104
{
 
105
        return(&(lock->mutex));
 
106
}
 
107
 
 
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 */
 
117
{
 
118
        return(lock->writer_count);
 
119
}
 
120
 
 
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 */
 
135
{
 
136
        ut_ad(mutex_own(rw_lock_get_mutex(lock)));
 
137
 
 
138
        /* Check if the writer field is free */
 
139
 
 
140
        if (UNIV_LIKELY(lock->writer == RW_LOCK_NOT_LOCKED)) {
 
141
                /* Set the shared lock by incrementing the reader count */
 
142
                lock->reader_count++;
 
143
 
 
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;
 
150
 
 
151
                return(TRUE);   /* locking succeeded */
 
152
        }
 
153
 
 
154
        return(FALSE);  /* locking did not succeed */
 
155
}
 
156
 
 
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 */
 
168
{
 
169
        ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
 
170
        ut_ad(rw_lock_get_reader_count(lock) == 0);
 
171
 
 
172
        /* Set the shared lock by incrementing the reader count */
 
173
        lock->reader_count++;
 
174
 
 
175
        lock->last_s_file_name = file_name;
 
176
        lock->last_s_line = line;
 
177
 
 
178
#ifdef UNIV_SYNC_DEBUG
 
179
        rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
 
180
#endif
 
181
}
 
182
 
 
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 */
 
194
{
 
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);
 
198
 
 
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;
 
203
 
 
204
        lock->last_x_file_name = file_name;
 
205
        lock->last_x_line = line;
 
206
 
 
207
#ifdef UNIV_SYNC_DEBUG
 
208
        rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
 
209
#endif
 
210
}
 
211
 
 
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 */
 
227
{
 
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. */
 
238
 
 
239
#ifdef UNIV_SYNC_DEBUG
 
240
        ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */
 
241
#endif /* UNIV_SYNC_DEBUG */
 
242
 
 
243
        mutex_enter(rw_lock_get_mutex(lock));
 
244
 
 
245
        if (UNIV_LIKELY(rw_lock_s_lock_low(lock, pass, file_name, line))) {
 
246
                mutex_exit(rw_lock_get_mutex(lock));
 
247
 
 
248
                return; /* Success */
 
249
        } else {
 
250
                /* Did not succeed, try spin wait */
 
251
                mutex_exit(rw_lock_get_mutex(lock));
 
252
 
 
253
                rw_lock_s_lock_spin(lock, pass, file_name, line);
 
254
 
 
255
                return;
 
256
        }
 
257
}
 
258
 
 
259
/**********************************************************************
 
260
NOTE! Use the corresponding macro, not directly this function! Lock an
 
261
rw-lock in shared mode for the current thread if the lock can be acquired
 
262
immediately. */
 
263
UNIV_INLINE
 
264
ibool
 
265
rw_lock_s_lock_func_nowait(
 
266
/*=======================*/
 
267
                                /* out: TRUE if success */
 
268
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
269
        const char*     file_name,/* in: file name where lock requested */
 
270
        ulint           line)   /* in: line where requested */
 
271
{
 
272
        ibool   success = FALSE;
 
273
 
 
274
        mutex_enter(rw_lock_get_mutex(lock));
 
275
 
 
276
        if (lock->writer == RW_LOCK_NOT_LOCKED) {
 
277
                /* Set the shared lock by incrementing the reader count */
 
278
                lock->reader_count++;
 
279
 
 
280
#ifdef UNIV_SYNC_DEBUG
 
281
                rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name,
 
282
                                       line);
 
283
#endif
 
284
 
 
285
                lock->last_s_file_name = file_name;
 
286
                lock->last_s_line = line;
 
287
 
 
288
                success = TRUE;
 
289
        }
 
290
 
 
291
        mutex_exit(rw_lock_get_mutex(lock));
 
292
 
 
293
        return(success);
 
294
}
 
295
 
 
296
/**********************************************************************
 
297
NOTE! Use the corresponding macro, not directly this function! Lock an
 
298
rw-lock in exclusive mode for the current thread if the lock can be
 
299
obtained immediately. */
 
300
UNIV_INLINE
 
301
ibool
 
302
rw_lock_x_lock_func_nowait(
 
303
/*=======================*/
 
304
                                /* out: TRUE if success */
 
305
        rw_lock_t*      lock,   /* in: pointer to rw-lock */
 
306
        const char*     file_name,/* in: file name where lock requested */
 
307
        ulint           line)   /* in: line where requested */
 
308
{
 
309
        ibool           success         = FALSE;
 
310
        os_thread_id_t  curr_thread     = os_thread_get_curr_id();
 
311
        mutex_enter(rw_lock_get_mutex(lock));
 
312
 
 
313
        if (UNIV_UNLIKELY(rw_lock_get_reader_count(lock) != 0)) {
 
314
        } else if (UNIV_LIKELY(rw_lock_get_writer(lock)
 
315
                               == RW_LOCK_NOT_LOCKED)) {
 
316
                rw_lock_set_writer(lock, RW_LOCK_EX);
 
317
                lock->writer_thread = curr_thread;
 
318
                lock->pass = 0;
 
319
relock:
 
320
                lock->writer_count++;
 
321
 
 
322
#ifdef UNIV_SYNC_DEBUG
 
323
                rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
 
324
#endif
 
325
 
 
326
                lock->last_x_file_name = file_name;
 
327
                lock->last_x_line = line;
 
328
 
 
329
                success = TRUE;
 
330
        } else if (rw_lock_get_writer(lock) == RW_LOCK_EX
 
331
                   && lock->pass == 0
 
332
                   && os_thread_eq(lock->writer_thread, curr_thread)) {
 
333
                goto relock;
 
334
        }
 
335
 
 
336
        mutex_exit(rw_lock_get_mutex(lock));
 
337
 
 
338
        ut_ad(rw_lock_validate(lock));
 
339
 
 
340
        return(success);
 
341
}
 
342
 
 
343
/**********************************************************************
 
344
Releases a shared mode lock. */
 
345
UNIV_INLINE
 
346
void
 
347
rw_lock_s_unlock_func(
 
348
/*==================*/
 
349
        rw_lock_t*      lock    /* in: rw-lock */
 
350
#ifdef UNIV_SYNC_DEBUG
 
351
        ,ulint          pass    /* in: pass value; != 0, if the lock may have
 
352
                                been passed to another thread to unlock */
 
353
#endif
 
354
        )
 
355
{
 
356
        mutex_t*        mutex   = &(lock->mutex);
 
357
        ibool           sg      = FALSE;
 
358
 
 
359
        /* Acquire the mutex protecting the rw-lock fields */
 
360
        mutex_enter(mutex);
 
361
 
 
362
        /* Reset the shared lock by decrementing the reader count */
 
363
 
 
364
        ut_a(lock->reader_count > 0);
 
365
        lock->reader_count--;
 
366
 
 
367
#ifdef UNIV_SYNC_DEBUG
 
368
        rw_lock_remove_debug_info(lock, pass, RW_LOCK_SHARED);
 
369
#endif
 
370
 
 
371
        /* If there may be waiters and this was the last s-lock,
 
372
        signal the object */
 
373
 
 
374
        if (UNIV_UNLIKELY(lock->waiters)
 
375
            && lock->reader_count == 0) {
 
376
                sg = TRUE;
 
377
 
 
378
                rw_lock_set_waiters(lock, 0);
 
379
        }
 
380
 
 
381
        mutex_exit(mutex);
 
382
 
 
383
        if (UNIV_UNLIKELY(sg)) {
 
384
                sync_array_signal_object(sync_primary_wait_array, lock);
 
385
        }
 
386
 
 
387
        ut_ad(rw_lock_validate(lock));
 
388
 
 
389
#ifdef UNIV_SYNC_PERF_STAT
 
390
        rw_s_exit_count++;
 
391
#endif
 
392
}
 
393
 
 
394
/**********************************************************************
 
395
Releases a shared mode lock when we know there are no waiters and none
 
396
else will access the lock during the time this function is executed. */
 
397
UNIV_INLINE
 
398
void
 
399
rw_lock_s_unlock_direct(
 
400
/*====================*/
 
401
        rw_lock_t*      lock)   /* in: rw-lock */
 
402
{
 
403
        /* Reset the shared lock by decrementing the reader count */
 
404
 
 
405
        ut_ad(lock->reader_count > 0);
 
406
 
 
407
        lock->reader_count--;
 
408
 
 
409
#ifdef UNIV_SYNC_DEBUG
 
410
        rw_lock_remove_debug_info(lock, 0, RW_LOCK_SHARED);
 
411
#endif
 
412
 
 
413
        ut_ad(!lock->waiters);
 
414
        ut_ad(rw_lock_validate(lock));
 
415
#ifdef UNIV_SYNC_PERF_STAT
 
416
        rw_s_exit_count++;
 
417
#endif
 
418
}
 
419
 
 
420
/**********************************************************************
 
421
Releases an exclusive mode lock. */
 
422
UNIV_INLINE
 
423
void
 
424
rw_lock_x_unlock_func(
 
425
/*==================*/
 
426
        rw_lock_t*      lock    /* in: rw-lock */
 
427
#ifdef UNIV_SYNC_DEBUG
 
428
        ,ulint          pass    /* in: pass value; != 0, if the lock may have
 
429
                                been passed to another thread to unlock */
 
430
#endif
 
431
        )
 
432
{
 
433
        ibool   sg      = FALSE;
 
434
 
 
435
        /* Acquire the mutex protecting the rw-lock fields */
 
436
        mutex_enter(&(lock->mutex));
 
437
 
 
438
        /* Reset the exclusive lock if this thread no longer has an x-mode
 
439
        lock */
 
440
 
 
441
        ut_ad(lock->writer_count > 0);
 
442
 
 
443
        lock->writer_count--;
 
444
 
 
445
        if (lock->writer_count == 0) {
 
446
                rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
 
447
        }
 
448
 
 
449
#ifdef UNIV_SYNC_DEBUG
 
450
        rw_lock_remove_debug_info(lock, pass, RW_LOCK_EX);
 
451
#endif
 
452
 
 
453
        /* If there may be waiters, signal the lock */
 
454
        if (UNIV_UNLIKELY(lock->waiters)
 
455
            && lock->writer_count == 0) {
 
456
 
 
457
                sg = TRUE;
 
458
                rw_lock_set_waiters(lock, 0);
 
459
        }
 
460
 
 
461
        mutex_exit(&(lock->mutex));
 
462
 
 
463
        if (UNIV_UNLIKELY(sg)) {
 
464
                sync_array_signal_object(sync_primary_wait_array, lock);
 
465
        }
 
466
 
 
467
        ut_ad(rw_lock_validate(lock));
 
468
 
 
469
#ifdef UNIV_SYNC_PERF_STAT
 
470
        rw_x_exit_count++;
 
471
#endif
 
472
}
 
473
 
 
474
/**********************************************************************
 
475
Releases an exclusive mode lock when we know there are no waiters, and
 
476
none else will access the lock durint the time this function is executed. */
 
477
UNIV_INLINE
 
478
void
 
479
rw_lock_x_unlock_direct(
 
480
/*====================*/
 
481
        rw_lock_t*      lock)   /* in: rw-lock */
 
482
{
 
483
        /* Reset the exclusive lock if this thread no longer has an x-mode
 
484
        lock */
 
485
 
 
486
        ut_ad(lock->writer_count > 0);
 
487
 
 
488
        lock->writer_count--;
 
489
 
 
490
        if (lock->writer_count == 0) {
 
491
                rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
 
492
        }
 
493
 
 
494
#ifdef UNIV_SYNC_DEBUG
 
495
        rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX);
 
496
#endif
 
497
 
 
498
        ut_ad(!lock->waiters);
 
499
        ut_ad(rw_lock_validate(lock));
 
500
 
 
501
#ifdef UNIV_SYNC_PERF_STAT
 
502
        rw_x_exit_count++;
 
503
#endif
 
504
}