~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
}