73
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
74
#define FORCE_DBUG_OFF
73
77
#include "mysys_priv.h"
75
79
#include "thr_lock.h"
76
#include <mystrings/m_string.h>
79
bool thr_lock_inited=0;
80
uint32_t locks_immediate = 0L, locks_waited = 0L;
83
my_bool thr_lock_inited=0;
84
ulong locks_immediate = 0L, locks_waited = 0L;
81
85
ulong table_lock_wait_timeout;
82
86
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
98
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
105
my_bool init_thr_lock()
103
107
thr_lock_inited=1;
111
static inline my_bool
108
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
110
114
return rhs == lhs;
113
118
#ifdef EXTRA_DEBUG
114
119
#define MAX_FOUND_ERRORS 10 /* Report 10 first errors */
115
static uint32_t found_errors=0;
120
static uint found_errors=0;
117
122
static int check_lock(struct st_lock_list *list, const char* lock_type,
118
const char *where, bool same_owner, bool no_cond)
123
const char *where, my_bool same_owner, my_bool no_cond)
120
125
THR_LOCK_DATA *data,**prev;
122
127
THR_LOCK_OWNER *first_owner;
124
129
prev= &list->data;
177
182
static void check_locks(THR_LOCK *lock, const char *where,
183
my_bool allow_no_locks)
180
uint32_t old_found_errors=found_errors;
185
uint old_found_errors=found_errors;
186
DBUG_ENTER("check_locks");
182
188
if (found_errors < MAX_FOUND_ERRORS)
190
196
if (found_errors < MAX_FOUND_ERRORS)
193
199
THR_LOCK_DATA *data;
194
200
for (data=lock->read.data ; data ; data=data->next)
196
202
if ((int) data->type == (int) TL_READ_NO_INSERT)
198
204
/* Protect against infinite loop. */
199
assert(count <= lock->read_no_write_count);
205
DBUG_ASSERT(count <= lock->read_no_write_count);
201
207
if (count != lock->read_no_write_count)
270
276
"Warning at '%s': Found lock of type %d that is write and read locked\n",
271
277
where, lock->write.data->type);
278
DBUG_PRINT("warning",("At '%s': Found lock of type %d that is write and read locked\n",
279
where, lock->write.data->type));
274
283
if (lock->read_wait.data)
300
313
void thr_lock_init(THR_LOCK *lock)
302
memset(lock, 0, sizeof(*lock));
303
pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST);
315
DBUG_ENTER("thr_lock_init");
316
bzero((char*) lock,sizeof(*lock));
317
VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
304
318
lock->read.last= &lock->read.data;
305
319
lock->read_wait.last= &lock->read_wait.data;
306
320
lock->write_wait.last= &lock->write_wait.data;
310
324
lock->list.data=(void*) lock;
311
325
thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
312
326
pthread_mutex_unlock(&THR_LOCK_lock);
317
331
void thr_lock_delete(THR_LOCK *lock)
319
pthread_mutex_destroy(&lock->mutex);
333
DBUG_ENTER("thr_lock_delete");
334
VOID(pthread_mutex_destroy(&lock->mutex));
320
335
pthread_mutex_lock(&THR_LOCK_lock);
321
336
thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
322
337
pthread_mutex_unlock(&THR_LOCK_lock);
373
388
static enum enum_thr_lock_result
374
389
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
390
my_bool in_wait_list)
377
392
struct st_my_thread_var *thread_var= my_thread_var;
378
393
pthread_cond_t *cond= &thread_var->suspend;
379
394
struct timespec wait_timeout;
380
395
enum enum_thr_lock_result result= THR_LOCK_ABORTED;
381
bool can_deadlock= test(data->owner->info->n_cursors);
396
my_bool can_deadlock= test(data->owner->info->n_cursors);
397
DBUG_ENTER("wait_for_lock");
383
399
if (!in_wait_list)
418
434
if (data->cond == 0)
436
DBUG_PRINT("thr_lock", ("lock granted/aborted"));
422
439
if (rc == ETIMEDOUT || rc == ETIME)
424
441
/* purecov: begin inspected */
442
DBUG_PRINT("thr_lock", ("lock timed out"));
425
443
result= THR_LOCK_WAIT_TIMEOUT;
427
445
/* purecov: end */
448
DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d",
449
thread_var->abort, in_wait_list));
430
451
if (data->cond || data->type == TL_UNLOCK)
432
453
if (data->cond) /* aborted or timed out */
470
492
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
471
493
struct st_lock_list *wait_queue;
472
494
THR_LOCK_DATA *lock_owner;
495
DBUG_ENTER("thr_lock");
475
498
data->cond=0; /* safety */
476
499
data->type=lock_type;
477
500
data->owner= owner; /* Must be reset ! */
478
pthread_mutex_lock(&lock->mutex);
501
VOID(pthread_mutex_lock(&lock->mutex));
502
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
503
(long) data, data->owner->info->thread_id,
504
(long) lock, (int) lock_type));
479
505
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
480
506
"enter read_lock" : "enter write_lock",0);
481
507
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
492
518
and the read lock is not TL_READ_NO_INSERT
521
DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
522
lock->write.data->owner->info->thread_id));
495
523
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
496
524
(lock->write.data->type <= TL_WRITE_DELAYED &&
497
525
(((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
603
631
We have already got a write lock or all locks are
604
632
TL_WRITE_ALLOW_WRITE
634
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
635
(ulong) lock->write_wait.data,
636
lock->write.data->type));
607
638
(*lock->write.last)=data; /* Add to running fifo */
608
639
data->prev=lock->write.last;
613
644
statistic_increment(locks_immediate,&THR_LOCK_lock);
647
DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
648
lock->write.data->owner->info->thread_id));
652
DBUG_PRINT("info", ("write_wait.data: 0x%lx",
653
(ulong) lock->write_wait.data));
619
654
if (!lock->write_wait.data)
620
655
{ /* no scheduled write locks */
621
bool concurrent_insert= 0;
656
my_bool concurrent_insert= 0;
622
657
if (lock_type == TL_WRITE_CONCURRENT_INSERT)
624
659
concurrent_insert= 1;
683
DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d",
684
lock->read.data->owner->info->thread_id, data->type));
649
686
wait_queue= &lock->write_wait;
657
694
lock_owner= lock->read.data ? lock->read.data : lock->write.data;
658
695
if (lock_owner && lock_owner->owner->info == owner->info)
697
DBUG_PRINT("lock",("deadlock"));
660
698
result= THR_LOCK_DEADLOCK;
663
701
/* Can't get lock yet; Wait for it */
664
return(wait_for_lock(wait_queue, data, 0));
702
DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
666
704
pthread_mutex_unlock(&lock->mutex);
671
709
static inline void free_all_read_locks(THR_LOCK *lock,
672
bool using_concurrent_insert)
710
my_bool using_concurrent_insert)
674
712
THR_LOCK_DATA *data=lock->read_wait.data;
706
744
lock->read_no_write_count++;
746
/* purecov: begin inspected */
747
DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
748
data->owner->info->thread_id));
708
750
data->cond=0; /* Mark thread free */
709
pthread_cond_signal(cond);
751
VOID(pthread_cond_signal(cond));
710
752
} while ((data=data->next));
711
753
*lock->read_wait.last=0;
712
754
if (!lock->read_wait.data)
721
763
THR_LOCK *lock=data->lock;
722
764
enum thr_lock_type lock_type=data->type;
765
DBUG_ENTER("thr_unlock");
766
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
767
(long) data, data->owner->info->thread_id, (long) lock));
723
768
pthread_mutex_lock(&lock->mutex);
724
769
check_locks(lock,"start of release lock",0);
786
833
lock->write_lock_count=0;
787
834
if (lock->read_wait.data)
836
DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
789
837
free_all_read_locks(lock,0);
803
851
if (data->type == TL_WRITE_CONCURRENT_INSERT &&
804
852
(*lock->check_status)(data->status_param))
805
853
data->type=TL_WRITE; /* Upgrade lock */
854
/* purecov: begin inspected */
855
DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%lx",
856
data->type, data->owner->info->thread_id));
807
859
pthread_cond_t *cond=data->cond;
808
860
data->cond=0; /* Mark thread free */
809
pthread_cond_signal(cond); /* Start waiting thread */
861
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
811
863
if (data->type != TL_WRITE_ALLOW_WRITE ||
812
864
!lock->write_wait.data ||
824
876
(data->type == TL_WRITE_CONCURRENT_INSERT ||
825
877
data->type == TL_WRITE_ALLOW_WRITE));
880
DBUG_PRINT("lock",("No waiting read locks to free"));
828
884
(lock_type=data->type) <= TL_WRITE_DELAYED &&
853
909
lock->write.last= &data->next;
854
910
data->next=0; /* Only one write lock */
855
911
data->cond=0; /* Mark thread free */
856
pthread_cond_signal(cond); /* Start waiting thread */
912
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
857
913
} while (lock_type == TL_WRITE_ALLOW_WRITE &&
858
914
(data=lock->write_wait.data) &&
859
915
data->type == TL_WRITE_ALLOW_WRITE);
881
#define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint) ((A)->type) < (unsigned char*) (B->lock)- (uint) ((B)->type))
937
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
883
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
939
static void sort_locks(THR_LOCK_DATA **data,uint count)
885
941
THR_LOCK_DATA **pos,**end,**prev,*tmp;
904
960
enum enum_thr_lock_result
905
thr_multi_lock(THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
961
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
907
963
THR_LOCK_DATA **pos,**end;
964
DBUG_ENTER("thr_multi_lock");
965
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
909
967
sort_locks(data,count);
910
968
/* lock everything */
914
972
if (result != THR_LOCK_SUCCESS)
916
974
thr_multi_unlock(data,(uint) (pos-data));
920
978
printf("Thread: %s Got lock: 0x%lx type: %d\n",my_thread_name(),
968
1026
} while (pos != data);
971
return(THR_LOCK_SUCCESS);
1029
DBUG_RETURN(THR_LOCK_SUCCESS);
974
1032
/* free all locks */
976
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
1034
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
978
1036
THR_LOCK_DATA **pos,**end;
1037
DBUG_ENTER("thr_multi_unlock");
1038
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
980
1040
for (pos=data,end=data+count; pos < end ; pos++)
987
1047
if ((*pos)->type != TL_UNLOCK)
988
1048
thr_unlock(*pos);
1051
DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
1052
(long) *pos, (*pos)->owner->info->thread_id,
1053
(long) (*pos)->lock));
995
1061
TL_WRITE_ONLY to abort any new accesses to the lock
998
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
1064
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
1000
1066
THR_LOCK_DATA *data;
1067
DBUG_ENTER("thr_abort_locks");
1001
1068
pthread_mutex_lock(&lock->mutex);
1003
1070
for (data=lock->read_wait.data; data ; data=data->next)
1029
1096
This is used to abort all locks for a specific thread
1032
bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
1099
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
1034
1101
THR_LOCK_DATA *data;
1102
my_bool found= FALSE;
1103
DBUG_ENTER("thr_abort_locks_for_thread");
1037
1105
pthread_mutex_lock(&lock->mutex);
1038
1106
for (data= lock->read_wait.data; data ; data= data->next)
1040
1108
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1110
DBUG_PRINT("info",("Aborting read-wait lock"));
1042
1111
data->type= TL_UNLOCK; /* Mark killed */
1043
1112
/* It's safe to signal the cond first: we're still holding the mutex. */
1045
1114
pthread_cond_signal(data->cond);
1046
1115
data->cond= 0; /* Removed from list */
1106
1176
enum thr_lock_type new_lock_type)
1108
1178
THR_LOCK *lock=in_data->lock;
1180
enum thr_lock_type old_lock_type= in_data->type;
1182
DBUG_ENTER("thr_downgrade_write_only_lock");
1110
1184
pthread_mutex_lock(&lock->mutex);
1185
DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
1186
DBUG_ASSERT(old_lock_type > new_lock_type);
1111
1187
in_data->type= new_lock_type;
1112
1188
check_locks(lock,"after downgrading lock",0);
1114
1190
pthread_mutex_unlock(&lock->mutex);
1118
1194
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1120
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1196
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1122
1198
THR_LOCK *lock=data->lock;
1199
DBUG_ENTER("thr_upgrade_write_delay_lock");
1124
1201
pthread_mutex_lock(&lock->mutex);
1125
1202
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1127
1204
pthread_mutex_unlock(&lock->mutex);
1128
return(data->type == TL_UNLOCK); /* Test if Aborted */
1205
DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */
1130
1207
check_locks(lock,"before upgrading lock",0);
1131
1208
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1139
1216
if (data->lock->get_status)
1140
1217
(*data->lock->get_status)(data->status_param, 0);
1141
1218
pthread_mutex_unlock(&lock->mutex);
1145
1222
if (((*data->prev)=data->next)) /* remove from lock-list */
1160
1237
check_locks(lock,"waiting for lock",0);
1162
return(wait_for_lock(&lock->write_wait,data,1));
1239
DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1166
1243
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1168
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1245
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1170
1247
THR_LOCK *lock=data->lock;
1248
DBUG_ENTER("thr_reschedule_write_lock");
1172
1250
pthread_mutex_lock(&lock->mutex);
1173
1251
if (!lock->read_wait.data) /* No waiting read locks */
1175
1253
pthread_mutex_unlock(&lock->mutex);
1179
1257
data->type=TL_WRITE_DELAYED;
1194
1272
free_all_read_locks(lock,0);
1196
1274
pthread_mutex_unlock(&lock->mutex);
1197
return(thr_upgrade_write_delay_lock(data));
1275
DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1201
1279
#include <my_sys.h>
1281
static void thr_print_lock(const char* name,struct st_lock_list *list)
1283
THR_LOCK_DATA *data,**prev;
1288
printf("%-10s: ",name);
1290
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
1292
printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
1294
if (data->prev != prev)
1295
printf("\nWarning: prev didn't point at previous lock\n");
1299
if (prev != list->last)
1300
printf("Warning: last didn't point at last lock\n");
1304
void thr_print_locks(void)
1309
pthread_mutex_lock(&THR_LOCK_lock);
1310
puts("Current locks:");
1311
for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
1312
list= list_rest(list))
1314
THR_LOCK *lock=(THR_LOCK*) list->data;
1315
VOID(pthread_mutex_lock(&lock->mutex));
1316
printf("lock: 0x%lx:",(ulong) lock);
1317
if ((lock->write_wait.data || lock->read_wait.data) &&
1318
(! lock->read.data && ! lock->write.data))
1319
printf(" WARNING: ");
1320
if (lock->write.data)
1322
if (lock->write_wait.data)
1323
printf(" write_wait");
1324
if (lock->read.data)
1326
if (lock->read_wait.data)
1327
printf(" read_wait");
1329
thr_print_lock("write",&lock->write);
1330
thr_print_lock("write_wait",&lock->write_wait);
1331
thr_print_lock("read",&lock->read);
1332
thr_print_lock("read_wait",&lock->read_wait);
1333
VOID(pthread_mutex_unlock(&lock->mutex));
1337
pthread_mutex_unlock(&THR_LOCK_lock);
1203
1340
/*****************************************************************************
1204
1341
** Test of thread locks
1205
1342
****************************************************************************/
1329
1466
thr_print_locks();
1330
1467
pthread_mutex_lock(&LOCK_thread_count);
1331
1468
thread_count--;
1332
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
1469
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1333
1470
pthread_mutex_unlock(&LOCK_thread_count);
1334
free((unsigned char*) arg);