1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
Read and write locks for Posix threads. All tread must acquire
18
all locks it needs through thr_multi_lock() to avoid dead-locks.
19
A lock consists of a master lock (THR_LOCK), and lock instances
21
Any thread can have any number of lock instances (read and write:s) on
22
any lock. All lock instances must be freed.
23
Locks are prioritized according to:
25
The current lock types are:
27
TL_READ # Low priority read
28
TL_READ_WITH_SHARED_LOCKS
29
TL_READ_HIGH_PRIORITY # High priority read
30
TL_READ_NO_INSERT # Read without concurrent inserts
31
TL_WRITE_ALLOW_WRITE # Write lock that allows other writers
32
TL_WRITE_ALLOW_READ # Write lock, but allow reading
33
TL_WRITE_CONCURRENT_INSERT
34
# Insert that can be mixed when selects
35
TL_WRITE_DELAYED # Used by delayed insert
36
# Allows lower locks to take over
37
TL_WRITE_LOW_PRIORITY # Low priority write
38
TL_WRITE # High priority write
39
TL_WRITE_ONLY # High priority write
40
# Abort all new lock request with an error
42
Locks are prioritized according to:
44
WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
45
WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
47
Locks in the same privilege level are scheduled in first-in-first-out order.
49
To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
50
should put a pointer to the following functions in the lock structure:
51
(If the pointer is zero (default), the function is not called)
54
Before giving a lock of type TL_WRITE_CONCURRENT_INSERT,
55
we check if this function exists and returns 0.
56
If not, then the lock is upgraded to TL_WRITE_LOCK
57
In MyISAM this is a simple check if the insert can be done
58
at the end of the datafile.
60
Before a write lock is released, this function is called.
61
In MyISAM this functions updates the count and length of the datafile
63
When one gets a lock this functions is called.
64
In MyISAM this stores the number of rows and size of the datafile
67
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
68
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
73
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
74
#define FORCE_DBUG_OFF
77
#include "mysys_priv.h"
84
my_bool thr_lock_inited=0;
85
ulong locks_immediate = 0L, locks_waited = 0L;
86
ulong table_lock_wait_timeout;
87
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
89
/* The following constants are only for debug output */
90
#define MAX_THREADS 100
94
LIST *thr_lock_thread_list; /* List of threads in use */
95
ulong max_write_lock_count= ~(ulong) 0L;
97
static inline pthread_cond_t *get_cond(void)
99
return &my_thread_var->suspend;
103
** For the future (now the thread specific cond is alloced by my_pthread.c)
106
my_bool init_thr_lock()
112
static inline my_bool
113
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
120
#define MAX_FOUND_ERRORS 10 /* Report 10 first errors */
121
static uint found_errors=0;
123
static int check_lock(struct st_lock_list *list, const char* lock_type,
124
const char *where, my_bool same_owner, my_bool no_cond)
126
THR_LOCK_DATA *data,**prev;
128
THR_LOCK_OWNER *first_owner;
133
enum thr_lock_type last_lock_type=list->data->type;
135
if (same_owner && list->data)
136
first_owner= list->data->owner;
137
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
139
if (data->type != last_lock_type)
140
last_lock_type=TL_IGNORE;
141
if (data->prev != prev)
144
"Warning: prev link %d didn't point at previous lock at %s: %s\n",
145
count, lock_type, where);
149
!thr_lock_owner_equal(data->owner, first_owner) &&
150
last_lock_type != TL_WRITE_ALLOW_WRITE)
153
"Warning: Found locks from different threads in %s: %s\n",
157
if (no_cond && data->cond)
160
"Warning: Found active lock with not reset cond %s: %s\n",
168
fprintf(stderr,"Warning: found too many locks at %s: %s\n",
173
if (prev != list->last)
175
fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
183
static void check_locks(THR_LOCK *lock, const char *where,
184
my_bool allow_no_locks)
186
uint old_found_errors=found_errors;
187
DBUG_ENTER("check_locks");
189
if (found_errors < MAX_FOUND_ERRORS)
191
if (check_lock(&lock->write,"write",where,1,1) |
192
check_lock(&lock->write_wait,"write_wait",where,0,0) |
193
check_lock(&lock->read,"read",where,0,1) |
194
check_lock(&lock->read_wait,"read_wait",where,0,0))
197
if (found_errors < MAX_FOUND_ERRORS)
201
for (data=lock->read.data ; data ; data=data->next)
203
if ((int) data->type == (int) TL_READ_NO_INSERT)
205
/* Protect against infinite loop. */
206
DBUG_ASSERT(count <= lock->read_no_write_count);
208
if (count != lock->read_no_write_count)
212
"Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
215
if (!lock->write.data)
217
if (!allow_no_locks && !lock->read.data &&
218
(lock->write_wait.data || lock->read_wait.data))
222
"Warning at '%s': No locks in use but locks are in wait queue\n",
225
if (!lock->write_wait.data)
227
if (!allow_no_locks && lock->read_wait.data)
231
"Warning at '%s': No write locks and waiting read locks\n",
237
if (!allow_no_locks &&
238
(((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
239
lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
240
!lock->read_no_write_count) ||
241
lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
242
(lock->write_wait.data->type == TL_WRITE_DELAYED &&
247
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
252
{ /* Have write lock */
253
if (lock->write_wait.data)
255
if (!allow_no_locks &&
256
lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
257
lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
261
"Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
267
if (!thr_lock_owner_equal(lock->write.data->owner,
268
lock->read.data->owner) &&
269
((lock->write.data->type > TL_WRITE_DELAYED &&
270
lock->write.data->type != TL_WRITE_ONLY) ||
271
((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
272
lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
273
lock->read_no_write_count)))
277
"Warning at '%s': Found lock of type %d that is write and read locked\n",
278
where, lock->write.data->type);
279
DBUG_PRINT("warning",("At '%s': Found lock of type %d that is write and read locked\n",
280
where, lock->write.data->type));
284
if (lock->read_wait.data)
286
if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
287
lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
291
"Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
293
(int) lock->read_wait.data->type,
294
(int) lock->write.data->type);
299
if (found_errors != old_found_errors)
301
DBUG_PRINT("error",("Found wrong lock"));
307
#else /* EXTRA_DEBUG */
308
#define check_locks(A,B,C)
312
/* Initialize a lock */
314
void thr_lock_init(THR_LOCK *lock)
316
DBUG_ENTER("thr_lock_init");
317
bzero((char*) lock,sizeof(*lock));
318
VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
319
lock->read.last= &lock->read.data;
320
lock->read_wait.last= &lock->read_wait.data;
321
lock->write_wait.last= &lock->write_wait.data;
322
lock->write.last= &lock->write.data;
324
pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */
325
lock->list.data=(void*) lock;
326
thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
327
pthread_mutex_unlock(&THR_LOCK_lock);
332
void thr_lock_delete(THR_LOCK *lock)
334
DBUG_ENTER("thr_lock_delete");
335
VOID(pthread_mutex_destroy(&lock->mutex));
336
pthread_mutex_lock(&THR_LOCK_lock);
337
thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
338
pthread_mutex_unlock(&THR_LOCK_lock);
343
void thr_lock_info_init(THR_LOCK_INFO *info)
345
struct st_my_thread_var *tmp= my_thread_var;
346
info->thread= tmp->pthread_self;
347
info->thread_id= tmp->id;
351
/* Initialize a lock instance */
353
void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
356
data->type=TL_UNLOCK;
357
data->owner= 0; /* no owner yet */
358
data->status_param=param;
363
static inline my_bool
364
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
366
for ( ; data ; data=data->next)
368
if (thr_lock_owner_equal(data->owner, owner))
369
return 1; /* Already locked by thread */
374
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
375
enum thr_lock_type type)
377
for ( ; data ; data=data->next)
379
if (data->type == type)
386
static void wake_up_waiters(THR_LOCK *lock);
389
static enum enum_thr_lock_result
390
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
391
my_bool in_wait_list)
393
struct st_my_thread_var *thread_var= my_thread_var;
394
pthread_cond_t *cond= &thread_var->suspend;
395
struct timespec wait_timeout;
396
enum enum_thr_lock_result result= THR_LOCK_ABORTED;
397
my_bool can_deadlock= test(data->owner->info->n_cursors);
398
DBUG_ENTER("wait_for_lock");
402
(*wait->last)=data; /* Wait for lock */
403
data->prev= wait->last;
404
wait->last= &data->next;
407
statistic_increment(locks_waited, &THR_LOCK_lock);
409
/* Set up control struct to allow others to abort locks */
410
thread_var->current_mutex= &data->lock->mutex;
411
thread_var->current_cond= cond;
415
set_timespec(wait_timeout, table_lock_wait_timeout);
416
while (!thread_var->abort || in_wait_list)
418
int rc= (can_deadlock ?
419
pthread_cond_timedwait(cond, &data->lock->mutex,
421
pthread_cond_wait(cond, &data->lock->mutex));
423
We must break the wait if one of the following occurs:
424
- the connection has been aborted (!thread_var->abort), but
425
this is not a delayed insert thread (in_wait_list). For a delayed
426
insert thread the proper action at shutdown is, apparently, to
427
acquire the lock and complete the insert.
428
- the lock has been granted (data->cond is set to NULL by the granter),
429
or the waiting has been aborted (additionally data->type is set to
431
- the wait has timed out (rc == ETIMEDOUT)
432
Order of checks below is important to not report about timeout
433
if the predicate is true.
437
DBUG_PRINT("thr_lock", ("lock granted/aborted"));
440
if (rc == ETIMEDOUT || rc == ETIME)
442
/* purecov: begin inspected */
443
DBUG_PRINT("thr_lock", ("lock timed out"));
444
result= THR_LOCK_WAIT_TIMEOUT;
449
DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d",
450
thread_var->abort, in_wait_list));
452
if (data->cond || data->type == TL_UNLOCK)
454
if (data->cond) /* aborted or timed out */
456
if (((*data->prev)=data->next)) /* remove from wait-list */
457
data->next->prev= data->prev;
459
wait->last=data->prev;
460
data->type= TL_UNLOCK; /* No lock */
461
check_locks(data->lock, "killed or timed out wait_for_lock", 1);
462
wake_up_waiters(data->lock);
466
DBUG_PRINT("thr_lock", ("lock aborted"));
467
check_locks(data->lock, "aborted wait_for_lock", 0);
472
result= THR_LOCK_SUCCESS;
473
if (data->lock->get_status)
474
(*data->lock->get_status)(data->status_param, 0);
475
check_locks(data->lock,"got wait_for_lock",0);
477
pthread_mutex_unlock(&data->lock->mutex);
479
/* The following must be done after unlock of lock->mutex */
480
pthread_mutex_lock(&thread_var->mutex);
481
thread_var->current_mutex= 0;
482
thread_var->current_cond= 0;
483
pthread_mutex_unlock(&thread_var->mutex);
488
enum enum_thr_lock_result
489
thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
490
enum thr_lock_type lock_type)
492
THR_LOCK *lock=data->lock;
493
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
494
struct st_lock_list *wait_queue;
495
THR_LOCK_DATA *lock_owner;
496
DBUG_ENTER("thr_lock");
499
data->cond=0; /* safety */
500
data->type=lock_type;
501
data->owner= owner; /* Must be reset ! */
502
VOID(pthread_mutex_lock(&lock->mutex));
503
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
504
(long) data, data->owner->info->thread_id,
505
(long) lock, (int) lock_type));
506
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
507
"enter read_lock" : "enter write_lock",0);
508
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
510
/* Request for READ lock */
511
if (lock->write.data)
513
/* We can allow a read lock even if there is already a write lock
514
on the table in one the following cases:
515
- This thread alread have a write lock on the table
516
- The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
517
and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
518
- The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
519
and the read lock is not TL_READ_NO_INSERT
522
DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
523
lock->write.data->owner->info->thread_id));
524
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
525
(lock->write.data->type <= TL_WRITE_DELAYED &&
526
(((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
527
(lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
528
lock->write.data->type != TL_WRITE_ALLOW_READ))))
529
{ /* Already got a write lock */
530
(*lock->read.last)=data; /* Add to running FIFO */
531
data->prev=lock->read.last;
532
lock->read.last= &data->next;
533
if (lock_type == TL_READ_NO_INSERT)
534
lock->read_no_write_count++;
535
check_locks(lock,"read lock with old write lock",0);
536
if (lock->get_status)
537
(*lock->get_status)(data->status_param, 0);
538
statistic_increment(locks_immediate,&THR_LOCK_lock);
541
if (lock->write.data->type == TL_WRITE_ONLY)
543
/* We are not allowed to get a READ lock in this case */
544
data->type=TL_UNLOCK;
545
result= THR_LOCK_ABORTED; /* Can't wait for this one */
549
else if (!lock->write_wait.data ||
550
lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
551
lock_type == TL_READ_HIGH_PRIORITY ||
552
have_old_read_lock(lock->read.data, data->owner))
553
{ /* No important write-locks */
554
(*lock->read.last)=data; /* Add to running FIFO */
555
data->prev=lock->read.last;
556
lock->read.last= &data->next;
557
if (lock->get_status)
558
(*lock->get_status)(data->status_param, 0);
559
if (lock_type == TL_READ_NO_INSERT)
560
lock->read_no_write_count++;
561
check_locks(lock,"read lock with no write locks",0);
562
statistic_increment(locks_immediate,&THR_LOCK_lock);
566
We're here if there is an active write lock or no write
567
lock but a high priority write waiting in the write_wait queue.
568
In the latter case we should yield the lock to the writer.
570
wait_queue= &lock->read_wait;
572
else /* Request for WRITE lock */
574
if (lock_type == TL_WRITE_DELAYED)
576
if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
578
data->type=TL_UNLOCK;
579
result= THR_LOCK_ABORTED; /* Can't wait for this one */
583
if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
584
(TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
586
if ((!lock->write.data ||
587
lock->write.data->type != TL_WRITE_ALLOW_READ) &&
588
!have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
589
(lock->write.data || lock->read.data))
591
/* Add delayed write lock to write_wait queue, and return at once */
592
(*lock->write_wait.last)=data;
593
data->prev=lock->write_wait.last;
594
lock->write_wait.last= &data->next;
595
data->cond=get_cond();
597
We don't have to do get_status here as we will do it when we change
598
the delayed lock to a real write lock
600
statistic_increment(locks_immediate,&THR_LOCK_lock);
604
else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
605
data->type=lock_type= thr_upgraded_concurrent_insert_lock;
607
if (lock->write.data) /* If there is a write lock */
609
if (lock->write.data->type == TL_WRITE_ONLY)
611
/* Allow lock owner to bypass TL_WRITE_ONLY. */
612
if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
614
/* We are not allowed to get a lock in this case */
615
data->type=TL_UNLOCK;
616
result= THR_LOCK_ABORTED; /* Can't wait for this one */
622
The following test will not work if the old lock was a
623
TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
624
the same thread, but this will never happen within MySQL.
626
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
627
(lock_type == TL_WRITE_ALLOW_WRITE &&
628
!lock->write_wait.data &&
629
lock->write.data->type == TL_WRITE_ALLOW_WRITE))
632
We have already got a write lock or all locks are
635
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
636
(ulong) lock->write_wait.data,
637
lock->write.data->type));
639
(*lock->write.last)=data; /* Add to running fifo */
640
data->prev=lock->write.last;
641
lock->write.last= &data->next;
642
check_locks(lock,"second write lock",0);
643
if (data->lock->get_status)
644
(*data->lock->get_status)(data->status_param, 0);
645
statistic_increment(locks_immediate,&THR_LOCK_lock);
648
DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
649
lock->write.data->owner->info->thread_id));
653
DBUG_PRINT("info", ("write_wait.data: 0x%lx",
654
(ulong) lock->write_wait.data));
655
if (!lock->write_wait.data)
656
{ /* no scheduled write locks */
657
my_bool concurrent_insert= 0;
658
if (lock_type == TL_WRITE_CONCURRENT_INSERT)
660
concurrent_insert= 1;
661
if ((*lock->check_status)(data->status_param))
663
concurrent_insert= 0;
664
data->type=lock_type= thr_upgraded_concurrent_insert_lock;
668
if (!lock->read.data ||
669
(lock_type <= TL_WRITE_DELAYED &&
670
((lock_type != TL_WRITE_CONCURRENT_INSERT &&
671
lock_type != TL_WRITE_ALLOW_WRITE) ||
672
!lock->read_no_write_count)))
674
(*lock->write.last)=data; /* Add as current write lock */
675
data->prev=lock->write.last;
676
lock->write.last= &data->next;
677
if (data->lock->get_status)
678
(*data->lock->get_status)(data->status_param, concurrent_insert);
679
check_locks(lock,"only write lock",0);
680
statistic_increment(locks_immediate,&THR_LOCK_lock);
684
DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d",
685
lock->read.data->owner->info->thread_id, data->type));
687
wait_queue= &lock->write_wait;
690
Try to detect a trivial deadlock when using cursors: attempt to
691
lock a table that is already locked by an open cursor within the
692
same connection. lock_owner can be zero if we succumbed to a high
693
priority writer in the write_wait queue.
695
lock_owner= lock->read.data ? lock->read.data : lock->write.data;
696
if (lock_owner && lock_owner->owner->info == owner->info)
698
DBUG_PRINT("lock",("deadlock"));
699
result= THR_LOCK_DEADLOCK;
702
/* Can't get lock yet; Wait for it */
703
DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
705
pthread_mutex_unlock(&lock->mutex);
710
static inline void free_all_read_locks(THR_LOCK *lock,
711
my_bool using_concurrent_insert)
713
THR_LOCK_DATA *data=lock->read_wait.data;
715
check_locks(lock,"before freeing read locks",1);
717
/* move all locks from read_wait list to read list */
718
(*lock->read.last)=data;
719
data->prev=lock->read.last;
720
lock->read.last=lock->read_wait.last;
722
/* Clear read_wait list */
723
lock->read_wait.last= &lock->read_wait.data;
727
pthread_cond_t *cond=data->cond;
728
if ((int) data->type == (int) TL_READ_NO_INSERT)
730
if (using_concurrent_insert)
733
We can't free this lock;
734
Link lock away from read chain back into read_wait chain
736
if (((*data->prev)=data->next))
737
data->next->prev=data->prev;
739
lock->read.last=data->prev;
740
*lock->read_wait.last= data;
741
data->prev= lock->read_wait.last;
742
lock->read_wait.last= &data->next;
745
lock->read_no_write_count++;
747
/* purecov: begin inspected */
748
DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
749
data->owner->info->thread_id));
751
data->cond=0; /* Mark thread free */
752
VOID(pthread_cond_signal(cond));
753
} while ((data=data->next));
754
*lock->read_wait.last=0;
755
if (!lock->read_wait.data)
756
lock->write_lock_count=0;
757
check_locks(lock,"after giving read locks",0);
760
/* Unlock lock and free next thread on same lock */
762
void thr_unlock(THR_LOCK_DATA *data)
764
THR_LOCK *lock=data->lock;
765
enum thr_lock_type lock_type=data->type;
766
DBUG_ENTER("thr_unlock");
767
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
768
(long) data, data->owner->info->thread_id, (long) lock));
769
pthread_mutex_lock(&lock->mutex);
770
check_locks(lock,"start of release lock",0);
772
if (((*data->prev)=data->next)) /* remove from lock-list */
773
data->next->prev= data->prev;
774
else if (lock_type <= TL_READ_NO_INSERT)
775
lock->read.last=data->prev;
776
else if (lock_type == TL_WRITE_DELAYED && data->cond)
779
This only happens in extreme circumstances when a
780
write delayed lock that is waiting for a lock
782
lock->write_wait.last=data->prev; /* Put it on wait queue */
785
lock->write.last=data->prev;
786
if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
788
if (lock->update_status)
789
(*lock->update_status)(data->status_param);
793
if (lock->restore_status)
794
(*lock->restore_status)(data->status_param);
796
if (lock_type == TL_READ_NO_INSERT)
797
lock->read_no_write_count--;
798
data->type=TL_UNLOCK; /* Mark unlocked */
799
check_locks(lock,"after releasing lock",1);
800
wake_up_waiters(lock);
801
pthread_mutex_unlock(&lock->mutex);
807
@brief Wake up all threads which pending requests for the lock
810
@param lock Lock for which threads should be woken up
814
static void wake_up_waiters(THR_LOCK *lock)
817
enum thr_lock_type lock_type;
819
DBUG_ENTER("wake_up_waiters");
821
if (!lock->write.data) /* If no active write locks */
823
data=lock->write_wait.data;
824
if (!lock->read.data) /* If no more locks in use */
826
/* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
828
(data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
829
lock->read_wait.data->type < TL_READ_HIGH_PRIORITY))
831
if (lock->write_lock_count++ > max_write_lock_count)
833
/* Too many write locks in a row; Release all waiting read locks */
834
lock->write_lock_count=0;
835
if (lock->read_wait.data)
837
DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
838
free_all_read_locks(lock,0);
844
if (((*data->prev)=data->next)) /* remove from wait-list */
845
data->next->prev= data->prev;
847
lock->write_wait.last=data->prev;
848
(*lock->write.last)=data; /* Put in execute list */
849
data->prev=lock->write.last;
851
lock->write.last= &data->next;
852
if (data->type == TL_WRITE_CONCURRENT_INSERT &&
853
(*lock->check_status)(data->status_param))
854
data->type=TL_WRITE; /* Upgrade lock */
855
/* purecov: begin inspected */
856
DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%lx",
857
data->type, data->owner->info->thread_id));
860
pthread_cond_t *cond=data->cond;
861
data->cond=0; /* Mark thread free */
862
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
864
if (data->type != TL_WRITE_ALLOW_WRITE ||
865
!lock->write_wait.data ||
866
lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
868
data=lock->write_wait.data; /* Free this too */
870
if (data->type >= TL_WRITE_LOW_PRIORITY)
872
/* Release possible read locks together with the write lock */
874
if (lock->read_wait.data)
875
free_all_read_locks(lock,
877
(data->type == TL_WRITE_CONCURRENT_INSERT ||
878
data->type == TL_WRITE_ALLOW_WRITE));
881
DBUG_PRINT("lock",("No waiting read locks to free"));
885
(lock_type=data->type) <= TL_WRITE_DELAYED &&
886
((lock_type != TL_WRITE_CONCURRENT_INSERT &&
887
lock_type != TL_WRITE_ALLOW_WRITE) ||
888
!lock->read_no_write_count))
891
For DELAYED, ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks
892
start WRITE locks together with the READ locks
894
if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
895
(*lock->check_status)(data->status_param))
897
data->type=TL_WRITE; /* Upgrade lock */
898
if (lock->read_wait.data)
899
free_all_read_locks(lock,0);
903
pthread_cond_t *cond=data->cond;
904
if (((*data->prev)=data->next)) /* remove from wait-list */
905
data->next->prev= data->prev;
907
lock->write_wait.last=data->prev;
908
(*lock->write.last)=data; /* Put in execute list */
909
data->prev=lock->write.last;
910
lock->write.last= &data->next;
911
data->next=0; /* Only one write lock */
912
data->cond=0; /* Mark thread free */
913
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
914
} while (lock_type == TL_WRITE_ALLOW_WRITE &&
915
(data=lock->write_wait.data) &&
916
data->type == TL_WRITE_ALLOW_WRITE);
917
if (lock->read_wait.data)
918
free_all_read_locks(lock,
919
(lock_type == TL_WRITE_CONCURRENT_INSERT ||
920
lock_type == TL_WRITE_ALLOW_WRITE));
922
else if (!data && lock->read_wait.data)
923
free_all_read_locks(lock,0);
926
check_locks(lock, "after waking up waiters", 0);
932
** Get all locks in a specific order to avoid dead-locks
933
** Sort acording to lock position and put write_locks before read_locks if
934
** lock on same lock.
938
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
940
static void sort_locks(THR_LOCK_DATA **data,uint count)
942
THR_LOCK_DATA **pos,**end,**prev,*tmp;
944
/* Sort locks with insertion sort (fast because almost always few locks) */
946
for (pos=data+1,end=data+count; pos < end ; pos++)
949
if (LOCK_CMP(tmp,pos[-1]))
954
} while (--prev != data && LOCK_CMP(tmp,prev[-1]));
961
enum enum_thr_lock_result
962
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
964
THR_LOCK_DATA **pos,**end;
965
DBUG_ENTER("thr_multi_lock");
966
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
968
sort_locks(data,count);
969
/* lock everything */
970
for (pos=data,end=data+count; pos < end ; pos++)
972
enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
973
if (result != THR_LOCK_SUCCESS)
975
thr_multi_unlock(data,(uint) (pos-data));
979
printf("Thread: %s Got lock: 0x%lx type: %d\n",my_thread_name(),
980
(long) pos[0]->lock, pos[0]->type); fflush(stdout);
984
Ensure that all get_locks() have the same status
985
If we lock the same table multiple times, we must use the same
988
#if !defined(DONT_USE_RW_LOCKS)
991
THR_LOCK_DATA *last_lock= end[-1];
996
if (last_lock->lock == (*pos)->lock &&
997
last_lock->lock->copy_status)
999
if (last_lock->type <= TL_READ_NO_INSERT)
1001
THR_LOCK_DATA **read_lock;
1003
If we are locking the same table with read locks we must ensure
1004
that all tables share the status of the last write lock or
1008
(*pos)->type <= TL_READ_NO_INSERT &&
1010
pos[-1]->lock == (*pos)->lock ;
1016
(last_lock->lock->copy_status)((*read_lock)->status_param,
1017
(*pos)->status_param);
1018
} while (*(read_lock++) != last_lock);
1019
last_lock= (*pos); /* Point at last write lock */
1022
(*last_lock->lock->copy_status)((*pos)->status_param,
1023
last_lock->status_param);
1027
} while (pos != data);
1030
DBUG_RETURN(THR_LOCK_SUCCESS);
1033
/* free all locks */
1035
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
1037
THR_LOCK_DATA **pos,**end;
1038
DBUG_ENTER("thr_multi_unlock");
1039
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
1041
for (pos=data,end=data+count; pos < end ; pos++)
1044
printf("Thread: %s Rel lock: 0x%lx type: %d\n",
1045
my_thread_name(), (long) pos[0]->lock, pos[0]->type);
1048
if ((*pos)->type != TL_UNLOCK)
1052
DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
1053
(long) *pos, (*pos)->owner->info->thread_id,
1054
(long) (*pos)->lock));
1061
Abort all threads waiting for a lock. The lock will be upgraded to
1062
TL_WRITE_ONLY to abort any new accesses to the lock
1065
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
1067
THR_LOCK_DATA *data;
1068
DBUG_ENTER("thr_abort_locks");
1069
pthread_mutex_lock(&lock->mutex);
1071
for (data=lock->read_wait.data; data ; data=data->next)
1073
data->type=TL_UNLOCK; /* Mark killed */
1074
/* It's safe to signal the cond first: we're still holding the mutex. */
1075
pthread_cond_signal(data->cond);
1076
data->cond=0; /* Removed from list */
1078
for (data=lock->write_wait.data; data ; data=data->next)
1080
data->type=TL_UNLOCK;
1081
pthread_cond_signal(data->cond);
1084
lock->read_wait.last= &lock->read_wait.data;
1085
lock->write_wait.last= &lock->write_wait.data;
1086
lock->read_wait.data=lock->write_wait.data=0;
1087
if (upgrade_lock && lock->write.data)
1088
lock->write.data->type=TL_WRITE_ONLY;
1089
pthread_mutex_unlock(&lock->mutex);
1095
Abort all locks for specific table/thread combination
1097
This is used to abort all locks for a specific thread
1100
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
1102
THR_LOCK_DATA *data;
1103
my_bool found= FALSE;
1104
DBUG_ENTER("thr_abort_locks_for_thread");
1106
pthread_mutex_lock(&lock->mutex);
1107
for (data= lock->read_wait.data; data ; data= data->next)
1109
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1111
DBUG_PRINT("info",("Aborting read-wait lock"));
1112
data->type= TL_UNLOCK; /* Mark killed */
1113
/* It's safe to signal the cond first: we're still holding the mutex. */
1115
pthread_cond_signal(data->cond);
1116
data->cond= 0; /* Removed from list */
1118
if (((*data->prev)= data->next))
1119
data->next->prev= data->prev;
1121
lock->read_wait.last= data->prev;
1124
for (data= lock->write_wait.data; data ; data= data->next)
1126
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1128
DBUG_PRINT("info",("Aborting write-wait lock"));
1129
data->type= TL_UNLOCK;
1131
pthread_cond_signal(data->cond);
1134
if (((*data->prev)= data->next))
1135
data->next->prev= data->prev;
1137
lock->write_wait.last= data->prev;
1140
wake_up_waiters(lock);
1141
pthread_mutex_unlock(&lock->mutex);
1147
Downgrade a WRITE_* to a lower WRITE level
1149
thr_downgrade_write_lock()
1150
in_data Lock data of thread downgrading its lock
1151
new_lock_type New write lock type
1155
This can be used to downgrade a lock already owned. When the downgrade
1156
occurs also other waiters, both readers and writers can be allowed to
1158
The previous lock is often TL_WRITE_ONLY but can also be
1159
TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
1160
TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
1161
TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
1162
operation didn't need such a high lock.
1163
TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
1165
TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
1166
already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
1167
The implementation is conservative and rather don't start rather than
1168
go on unknown paths to start, the common cases are handled.
1171
In its current implementation it is only allowed to downgrade from
1172
TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
1176
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
1177
enum thr_lock_type new_lock_type)
1179
THR_LOCK *lock=in_data->lock;
1181
enum thr_lock_type old_lock_type= in_data->type;
1183
#ifdef TO_BE_REMOVED
1184
THR_LOCK_DATA *data, *next;
1185
bool start_writers= FALSE;
1186
bool start_readers= FALSE;
1188
DBUG_ENTER("thr_downgrade_write_only_lock");
1190
pthread_mutex_lock(&lock->mutex);
1191
DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
1192
DBUG_ASSERT(old_lock_type > new_lock_type);
1193
in_data->type= new_lock_type;
1194
check_locks(lock,"after downgrading lock",0);
1197
switch (old_lock_type)
1201
case TL_WRITE_LOW_PRIORITY:
1203
Previous lock was exclusive we are now ready to start up most waiting
1206
switch (new_lock_type)
1208
case TL_WRITE_ALLOW_READ:
1209
/* Still cannot start WRITE operations. Can only start readers. */
1210
start_readers= TRUE;
1213
case TL_WRITE_LOW_PRIORITY:
1215
Still cannot start anything, but new requests are no longer
1219
case TL_WRITE_ALLOW_WRITE:
1221
We can start both writers and readers.
1223
start_writers= TRUE;
1224
start_readers= TRUE;
1226
case TL_WRITE_CONCURRENT_INSERT:
1227
case TL_WRITE_DELAYED:
1229
This routine is not designed for those. Lock will be downgraded
1230
but no start of waiters will occur. This is not the optimal but
1231
should be a correct behaviour.
1238
case TL_WRITE_DELAYED:
1239
case TL_WRITE_CONCURRENT_INSERT:
1241
This routine is not designed for those. Lock will be downgraded
1242
but no start of waiters will occur. This is not the optimal but
1243
should be a correct behaviour.
1246
case TL_WRITE_ALLOW_READ:
1247
DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
1249
Previously writers were not allowed to start, now it is ok to
1250
start them again. Readers are already allowed so no reason to
1253
start_writers= TRUE;
1262
At this time the only active writer can be ourselves. Thus we need
1263
not worry about that there are other concurrent write operations
1264
active on the table. Thus we only need to worry about starting
1266
We also only come here with TL_WRITE_ALLOW_WRITE as the new
1267
lock type, thus we can start other writers also of the same type.
1268
If we find a lock at exclusive level >= TL_WRITE_LOW_PRIORITY we
1269
don't start any more operations that would be mean those operations
1270
will have to wait for things started afterwards.
1272
DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
1273
for (data=lock->write_wait.data; data ; data= next)
1276
All WRITE requests compatible with new lock type are also
1280
if (start_writers && data->type == new_lock_type)
1282
pthread_cond_t *cond= data->cond;
1284
It is ok to start this waiter.
1285
Move from being first in wait queue to be last in write queue.
1287
if (((*data->prev)= data->next))
1288
data->next->prev= data->prev;
1290
lock->write_wait.last= data->prev;
1291
data->prev= lock->write.last;
1292
lock->write.last= &data->next;
1294
check_locks(lock, "Started write lock after downgrade",0);
1296
pthread_cond_signal(cond);
1301
We found an incompatible lock, we won't start any more write
1302
requests to avoid letting writers pass other writers in the
1305
start_writers= FALSE;
1306
if (data->type >= TL_WRITE_LOW_PRIORITY)
1309
We have an exclusive writer in the queue so we won't start
1312
start_readers= FALSE;
1319
DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE ||
1320
new_lock_type == TL_WRITE_ALLOW_READ);
1322
When we come here we know that the write locks are
1323
TL_WRITE_ALLOW_WRITE or TL_WRITE_ALLOW_READ. This means that reads
1326
for (data=lock->read_wait.data; data ; data=next)
1330
All reads are ok to start now except TL_READ_NO_INSERT when
1331
write lock is TL_WRITE_ALLOW_READ.
1333
if (new_lock_type != TL_WRITE_ALLOW_READ ||
1334
data->type != TL_READ_NO_INSERT)
1336
pthread_cond_t *cond= data->cond;
1337
if (((*data->prev)= data->next))
1338
data->next->prev= data->prev;
1340
lock->read_wait.last= data->prev;
1341
data->prev= lock->read.last;
1342
lock->read.last= &data->next;
1345
if (data->type == TL_READ_NO_INSERT)
1346
lock->read_no_write_count++;
1347
check_locks(lock, "Started read lock after downgrade",0);
1349
pthread_cond_signal(cond);
1353
check_locks(lock,"after starting waiters after downgrading lock",0);
1355
pthread_mutex_unlock(&lock->mutex);
1359
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1361
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1363
THR_LOCK *lock=data->lock;
1364
DBUG_ENTER("thr_upgrade_write_delay_lock");
1366
pthread_mutex_lock(&lock->mutex);
1367
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1369
pthread_mutex_unlock(&lock->mutex);
1370
DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */
1372
check_locks(lock,"before upgrading lock",0);
1373
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1374
data->type=TL_WRITE; /* Upgrade lock */
1376
/* Check if someone has given us the lock */
1379
if (!lock->read.data) /* No read locks */
1380
{ /* We have the lock */
1381
if (data->lock->get_status)
1382
(*data->lock->get_status)(data->status_param, 0);
1383
pthread_mutex_unlock(&lock->mutex);
1387
if (((*data->prev)=data->next)) /* remove from lock-list */
1388
data->next->prev= data->prev;
1390
lock->write.last=data->prev;
1392
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1393
data->next->prev= &data->next;
1395
lock->write_wait.last= &data->next;
1396
data->prev= &lock->write_wait.data;
1397
lock->write_wait.data=data;
1398
check_locks(lock,"upgrading lock",0);
1402
check_locks(lock,"waiting for lock",0);
1404
DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1408
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1410
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1412
THR_LOCK *lock=data->lock;
1413
DBUG_ENTER("thr_reschedule_write_lock");
1415
pthread_mutex_lock(&lock->mutex);
1416
if (!lock->read_wait.data) /* No waiting read locks */
1418
pthread_mutex_unlock(&lock->mutex);
1422
data->type=TL_WRITE_DELAYED;
1423
if (lock->update_status)
1424
(*lock->update_status)(data->status_param);
1425
if (((*data->prev)=data->next)) /* remove from lock-list */
1426
data->next->prev= data->prev;
1428
lock->write.last=data->prev;
1430
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1431
data->next->prev= &data->next;
1433
lock->write_wait.last= &data->next;
1434
data->prev= &lock->write_wait.data;
1435
data->cond=get_cond(); /* This was zero */
1436
lock->write_wait.data=data;
1437
free_all_read_locks(lock,0);
1439
pthread_mutex_unlock(&lock->mutex);
1440
DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1446
static void thr_print_lock(const char* name,struct st_lock_list *list)
1448
THR_LOCK_DATA *data,**prev;
1453
printf("%-10s: ",name);
1455
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
1457
printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
1459
if (data->prev != prev)
1460
printf("\nWarning: prev didn't point at previous lock\n");
1464
if (prev != list->last)
1465
printf("Warning: last didn't point at last lock\n");
1469
void thr_print_locks(void)
1474
pthread_mutex_lock(&THR_LOCK_lock);
1475
puts("Current locks:");
1476
for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
1477
list= list_rest(list))
1479
THR_LOCK *lock=(THR_LOCK*) list->data;
1480
VOID(pthread_mutex_lock(&lock->mutex));
1481
printf("lock: 0x%lx:",(ulong) lock);
1482
if ((lock->write_wait.data || lock->read_wait.data) &&
1483
(! lock->read.data && ! lock->write.data))
1484
printf(" WARNING: ");
1485
if (lock->write.data)
1487
if (lock->write_wait.data)
1488
printf(" write_wait");
1489
if (lock->read.data)
1491
if (lock->read_wait.data)
1492
printf(" read_wait");
1494
thr_print_lock("write",&lock->write);
1495
thr_print_lock("write_wait",&lock->write_wait);
1496
thr_print_lock("read",&lock->read);
1497
thr_print_lock("read_wait",&lock->read_wait);
1498
VOID(pthread_mutex_unlock(&lock->mutex));
1502
pthread_mutex_unlock(&THR_LOCK_lock);
1507
/*****************************************************************************
1508
** Test of thread locks
1509
****************************************************************************/
1517
enum thr_lock_type lock_type;
1520
THR_LOCK locks[5]; /* 4 locks */
1522
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
1523
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
1524
struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
1525
struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
1526
struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
1527
struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
1528
struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
1529
struct st_test test_7[] = {{3,TL_READ}};
1530
struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}}; /* Should be quick */
1531
struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
1532
struct st_test test_10[] ={{4,TL_WRITE}};
1533
struct st_test test_11[] = {{0,TL_WRITE_LOW_PRIORITY},{1,TL_WRITE_LOW_PRIORITY},{2,TL_WRITE_LOW_PRIORITY},{3,TL_WRITE_LOW_PRIORITY}}; /* Many writes */
1534
struct st_test test_12[] = {{0,TL_WRITE_ALLOW_READ},{1,TL_WRITE_ALLOW_READ},{2,TL_WRITE_ALLOW_READ},{3,TL_WRITE_ALLOW_READ}}; /* Many writes */
1535
struct st_test test_13[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_WRITE_CONCURRENT_INSERT},{2,TL_WRITE_CONCURRENT_INSERT},{3,TL_WRITE_CONCURRENT_INSERT}};
1536
struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
1537
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
1538
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
1540
struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
1541
test_7,test_8,test_9,test_10,test_11,test_12,
1542
test_13,test_14,test_15,test_16};
1543
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
1544
sizeof(test_1)/sizeof(struct st_test),
1545
sizeof(test_2)/sizeof(struct st_test),
1546
sizeof(test_3)/sizeof(struct st_test),
1547
sizeof(test_4)/sizeof(struct st_test),
1548
sizeof(test_5)/sizeof(struct st_test),
1549
sizeof(test_6)/sizeof(struct st_test),
1550
sizeof(test_7)/sizeof(struct st_test),
1551
sizeof(test_8)/sizeof(struct st_test),
1552
sizeof(test_9)/sizeof(struct st_test),
1553
sizeof(test_10)/sizeof(struct st_test),
1554
sizeof(test_11)/sizeof(struct st_test),
1555
sizeof(test_12)/sizeof(struct st_test),
1556
sizeof(test_13)/sizeof(struct st_test),
1557
sizeof(test_14)/sizeof(struct st_test),
1558
sizeof(test_15)/sizeof(struct st_test),
1559
sizeof(test_16)/sizeof(struct st_test)
1563
static pthread_cond_t COND_thread_count;
1564
static pthread_mutex_t LOCK_thread_count;
1565
static uint thread_count;
1568
#define MAX_LOCK_COUNT 8
1570
/* The following functions is for WRITE_CONCURRENT_INSERT */
1572
static void test_get_status(void* param __attribute__((unused)),
1573
int concurrent_insert __attribute__((unused)))
1577
static void test_update_status(void* param __attribute__((unused)))
1581
static void test_copy_status(void* to __attribute__((unused)) ,
1582
void *from __attribute__((unused)))
1586
static my_bool test_check_status(void* param __attribute__((unused)))
1592
static void *test_thread(void *arg)
1594
int i,j,param=*((int*) arg);
1595
THR_LOCK_DATA data[MAX_LOCK_COUNT];
1596
THR_LOCK_OWNER owner;
1597
THR_LOCK_INFO lock_info;
1598
THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
1601
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
1604
thr_lock_info_init(&lock_info);
1605
thr_lock_owner_init(&owner, &lock_info);
1606
for (i=0; i < lock_counts[param] ; i++)
1607
thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
1608
for (j=1 ; j < 10 ; j++) /* try locking 10 times */
1610
for (i=0; i < lock_counts[param] ; i++)
1611
{ /* Init multi locks */
1612
multi_locks[i]= &data[i];
1613
data[i].type= tests[param][i].lock_type;
1615
thr_multi_lock(multi_locks, lock_counts[param], &owner);
1616
pthread_mutex_lock(&LOCK_thread_count);
1618
int tmp=rand() & 7; /* Do something from 0-2 sec */
1626
for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
1630
pthread_mutex_unlock(&LOCK_thread_count);
1631
thr_multi_unlock(multi_locks,lock_counts[param]);
1634
printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
1636
pthread_mutex_lock(&LOCK_thread_count);
1638
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1639
pthread_mutex_unlock(&LOCK_thread_count);
1645
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
1648
pthread_attr_t thr_attr;
1651
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
1652
DBUG_PUSH(argv[1]+2);
1654
printf("Main thread: %s\n",my_thread_name());
1656
if ((error=pthread_cond_init(&COND_thread_count,NULL)))
1658
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1662
if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST)))
1664
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1669
for (i=0 ; i < (int) array_elements(locks) ; i++)
1671
thr_lock_init(locks+i);
1672
locks[i].check_status= test_check_status;
1673
locks[i].update_status=test_update_status;
1674
locks[i].copy_status= test_copy_status;
1675
locks[i].get_status= test_get_status;
1677
if ((error=pthread_attr_init(&thr_attr)))
1679
fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
1683
if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
1686
"Got error: %d from pthread_attr_setdetachstate (errno: %d)",
1690
#ifndef pthread_attr_setstacksize /* void return value */
1691
if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
1693
fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
1698
#ifdef HAVE_THR_SETCONCURRENCY
1699
VOID(thr_setconcurrency(2));
1701
for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1703
param=(int*) malloc(sizeof(int));
1706
if ((error=pthread_mutex_lock(&LOCK_thread_count)))
1708
fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
1712
if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
1714
fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
1716
pthread_mutex_unlock(&LOCK_thread_count);
1720
pthread_mutex_unlock(&LOCK_thread_count);
1723
pthread_attr_destroy(&thr_attr);
1724
if ((error=pthread_mutex_lock(&LOCK_thread_count)))
1725
fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
1726
while (thread_count)
1728
if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
1729
fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
1731
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
1732
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
1733
for (i=0 ; i < (int) array_elements(locks) ; i++)
1734
thr_lock_delete(locks+i);
1737
printf("Got %d warnings\n",found_errors);
1740
printf("Test succeeded\n");
1746
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
1748
printf("thr_lock disabled because we are not using threads\n");