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
#if TIME_WITH_SYS_TIME
80
# include <sys/time.h>
84
# include <sys/time.h>
90
#include <drizzled/util/test.h>
92
bool thr_lock_inited=0;
93
uint32_t locks_immediate = 0L, locks_waited = 0L;
83
my_bool thr_lock_inited=0;
84
ulong locks_immediate = 0L, locks_waited = 0L;
94
85
ulong table_lock_wait_timeout;
95
86
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
111
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
105
my_bool init_thr_lock()
116
107
thr_lock_inited=1;
111
static inline my_bool
121
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
123
114
return rhs == lhs;
126
118
#ifdef EXTRA_DEBUG
127
119
#define MAX_FOUND_ERRORS 10 /* Report 10 first errors */
128
static uint32_t found_errors=0;
120
static uint found_errors=0;
130
122
static int check_lock(struct st_lock_list *list, const char* lock_type,
131
const char *where, bool same_owner, bool no_cond)
123
const char *where, my_bool same_owner, my_bool no_cond)
133
125
THR_LOCK_DATA *data,**prev;
135
127
THR_LOCK_OWNER *first_owner;
137
129
prev= &list->data;
190
182
static void check_locks(THR_LOCK *lock, const char *where,
183
my_bool allow_no_locks)
193
uint32_t old_found_errors=found_errors;
185
uint old_found_errors=found_errors;
186
DBUG_ENTER("check_locks");
195
188
if (found_errors < MAX_FOUND_ERRORS)
203
196
if (found_errors < MAX_FOUND_ERRORS)
206
199
THR_LOCK_DATA *data;
207
200
for (data=lock->read.data ; data ; data=data->next)
209
202
if ((int) data->type == (int) TL_READ_NO_INSERT)
211
204
/* Protect against infinite loop. */
212
assert(count <= lock->read_no_write_count);
205
DBUG_ASSERT(count <= lock->read_no_write_count);
214
207
if (count != lock->read_no_write_count)
283
276
"Warning at '%s': Found lock of type %d that is write and read locked\n",
284
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));
287
283
if (lock->read_wait.data)
313
313
void thr_lock_init(THR_LOCK *lock)
315
memset(lock, 0, sizeof(*lock));
316
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));
317
318
lock->read.last= &lock->read.data;
318
319
lock->read_wait.last= &lock->read_wait.data;
319
320
lock->write_wait.last= &lock->write_wait.data;
323
324
lock->list.data=(void*) lock;
324
325
thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
325
326
pthread_mutex_unlock(&THR_LOCK_lock);
330
331
void thr_lock_delete(THR_LOCK *lock)
332
pthread_mutex_destroy(&lock->mutex);
333
DBUG_ENTER("thr_lock_delete");
334
VOID(pthread_mutex_destroy(&lock->mutex));
333
335
pthread_mutex_lock(&THR_LOCK_lock);
334
336
thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
335
337
pthread_mutex_unlock(&THR_LOCK_lock);
386
388
static enum enum_thr_lock_result
387
389
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
390
my_bool in_wait_list)
390
392
struct st_my_thread_var *thread_var= my_thread_var;
391
393
pthread_cond_t *cond= &thread_var->suspend;
392
394
struct timespec wait_timeout;
393
395
enum enum_thr_lock_result result= THR_LOCK_ABORTED;
394
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");
396
399
if (!in_wait_list)
431
434
if (data->cond == 0)
436
DBUG_PRINT("thr_lock", ("lock granted/aborted"));
435
439
if (rc == ETIMEDOUT || rc == ETIME)
437
441
/* purecov: begin inspected */
442
DBUG_PRINT("thr_lock", ("lock timed out"));
438
443
result= THR_LOCK_WAIT_TIMEOUT;
440
445
/* purecov: end */
448
DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d",
449
thread_var->abort, in_wait_list));
443
451
if (data->cond || data->type == TL_UNLOCK)
445
453
if (data->cond) /* aborted or timed out */
483
492
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
484
493
struct st_lock_list *wait_queue;
485
494
THR_LOCK_DATA *lock_owner;
495
DBUG_ENTER("thr_lock");
488
498
data->cond=0; /* safety */
489
499
data->type=lock_type;
490
500
data->owner= owner; /* Must be reset ! */
491
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));
492
505
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
493
506
"enter read_lock" : "enter write_lock",0);
494
507
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
505
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));
508
523
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
509
524
(lock->write.data->type <= TL_WRITE_DELAYED &&
510
525
(((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
616
631
We have already got a write lock or all locks are
617
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));
620
638
(*lock->write.last)=data; /* Add to running fifo */
621
639
data->prev=lock->write.last;
626
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));
632
654
if (!lock->write_wait.data)
633
655
{ /* no scheduled write locks */
634
bool concurrent_insert= 0;
656
my_bool concurrent_insert= 0;
635
657
if (lock_type == TL_WRITE_CONCURRENT_INSERT)
637
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));
662
686
wait_queue= &lock->write_wait;
670
694
lock_owner= lock->read.data ? lock->read.data : lock->write.data;
671
695
if (lock_owner && lock_owner->owner->info == owner->info)
697
DBUG_PRINT("lock",("deadlock"));
673
698
result= THR_LOCK_DEADLOCK;
676
701
/* Can't get lock yet; Wait for it */
677
return(wait_for_lock(wait_queue, data, 0));
702
DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
679
704
pthread_mutex_unlock(&lock->mutex);
684
709
static inline void free_all_read_locks(THR_LOCK *lock,
685
bool using_concurrent_insert)
710
my_bool using_concurrent_insert)
687
712
THR_LOCK_DATA *data=lock->read_wait.data;
719
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));
721
750
data->cond=0; /* Mark thread free */
722
pthread_cond_signal(cond);
751
VOID(pthread_cond_signal(cond));
723
752
} while ((data=data->next));
724
753
*lock->read_wait.last=0;
725
754
if (!lock->read_wait.data)
734
763
THR_LOCK *lock=data->lock;
735
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));
736
768
pthread_mutex_lock(&lock->mutex);
737
769
check_locks(lock,"start of release lock",0);
799
833
lock->write_lock_count=0;
800
834
if (lock->read_wait.data)
836
DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
802
837
free_all_read_locks(lock,0);
816
851
if (data->type == TL_WRITE_CONCURRENT_INSERT &&
817
852
(*lock->check_status)(data->status_param))
818
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));
820
859
pthread_cond_t *cond=data->cond;
821
860
data->cond=0; /* Mark thread free */
822
pthread_cond_signal(cond); /* Start waiting thread */
861
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
824
863
if (data->type != TL_WRITE_ALLOW_WRITE ||
825
864
!lock->write_wait.data ||
837
876
(data->type == TL_WRITE_CONCURRENT_INSERT ||
838
877
data->type == TL_WRITE_ALLOW_WRITE));
880
DBUG_PRINT("lock",("No waiting read locks to free"));
841
884
(lock_type=data->type) <= TL_WRITE_DELAYED &&
866
909
lock->write.last= &data->next;
867
910
data->next=0; /* Only one write lock */
868
911
data->cond=0; /* Mark thread free */
869
pthread_cond_signal(cond); /* Start waiting thread */
912
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
870
913
} while (lock_type == TL_WRITE_ALLOW_WRITE &&
871
914
(data=lock->write_wait.data) &&
872
915
data->type == TL_WRITE_ALLOW_WRITE);
894
#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))
896
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
939
static void sort_locks(THR_LOCK_DATA **data,uint count)
898
941
THR_LOCK_DATA **pos,**end,**prev,*tmp;
917
960
enum enum_thr_lock_result
918
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)
920
963
THR_LOCK_DATA **pos,**end;
964
DBUG_ENTER("thr_multi_lock");
965
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
922
967
sort_locks(data,count);
923
968
/* lock everything */
927
972
if (result != THR_LOCK_SUCCESS)
929
974
thr_multi_unlock(data,(uint) (pos-data));
933
978
printf("Thread: %s Got lock: 0x%lx type: %d\n",my_thread_name(),
981
1026
} while (pos != data);
984
return(THR_LOCK_SUCCESS);
1029
DBUG_RETURN(THR_LOCK_SUCCESS);
987
1032
/* free all locks */
989
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
1034
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
991
1036
THR_LOCK_DATA **pos,**end;
1037
DBUG_ENTER("thr_multi_unlock");
1038
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
993
1040
for (pos=data,end=data+count; pos < end ; pos++)
1000
1047
if ((*pos)->type != TL_UNLOCK)
1001
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));
1008
1061
TL_WRITE_ONLY to abort any new accesses to the lock
1011
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
1064
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
1013
1066
THR_LOCK_DATA *data;
1067
DBUG_ENTER("thr_abort_locks");
1014
1068
pthread_mutex_lock(&lock->mutex);
1016
1070
for (data=lock->read_wait.data; data ; data=data->next)
1042
1096
This is used to abort all locks for a specific thread
1045
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)
1047
1101
THR_LOCK_DATA *data;
1102
my_bool found= FALSE;
1103
DBUG_ENTER("thr_abort_locks_for_thread");
1050
1105
pthread_mutex_lock(&lock->mutex);
1051
1106
for (data= lock->read_wait.data; data ; data= data->next)
1053
1108
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1110
DBUG_PRINT("info",("Aborting read-wait lock"));
1055
1111
data->type= TL_UNLOCK; /* Mark killed */
1056
1112
/* It's safe to signal the cond first: we're still holding the mutex. */
1058
1114
pthread_cond_signal(data->cond);
1059
1115
data->cond= 0; /* Removed from list */
1119
1176
enum thr_lock_type new_lock_type)
1121
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");
1123
1184
pthread_mutex_lock(&lock->mutex);
1185
DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
1186
DBUG_ASSERT(old_lock_type > new_lock_type);
1124
1187
in_data->type= new_lock_type;
1125
1188
check_locks(lock,"after downgrading lock",0);
1127
1190
pthread_mutex_unlock(&lock->mutex);
1131
1194
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1133
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1196
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1135
1198
THR_LOCK *lock=data->lock;
1199
DBUG_ENTER("thr_upgrade_write_delay_lock");
1137
1201
pthread_mutex_lock(&lock->mutex);
1138
1202
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1140
1204
pthread_mutex_unlock(&lock->mutex);
1141
return(data->type == TL_UNLOCK); /* Test if Aborted */
1205
DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */
1143
1207
check_locks(lock,"before upgrading lock",0);
1144
1208
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1152
1216
if (data->lock->get_status)
1153
1217
(*data->lock->get_status)(data->status_param, 0);
1154
1218
pthread_mutex_unlock(&lock->mutex);
1158
1222
if (((*data->prev)=data->next)) /* remove from lock-list */
1173
1237
check_locks(lock,"waiting for lock",0);
1175
return(wait_for_lock(&lock->write_wait,data,1));
1239
DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1179
1243
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1181
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1245
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1183
1247
THR_LOCK *lock=data->lock;
1248
DBUG_ENTER("thr_reschedule_write_lock");
1185
1250
pthread_mutex_lock(&lock->mutex);
1186
1251
if (!lock->read_wait.data) /* No waiting read locks */
1188
1253
pthread_mutex_unlock(&lock->mutex);
1192
1257
data->type=TL_WRITE_DELAYED;
1207
1272
free_all_read_locks(lock,0);
1209
1274
pthread_mutex_unlock(&lock->mutex);
1210
return(thr_upgrade_write_delay_lock(data));
1275
DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1214
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);
1216
1340
/*****************************************************************************
1217
1341
** Test of thread locks
1218
1342
****************************************************************************/
1342
1466
thr_print_locks();
1343
1467
pthread_mutex_lock(&LOCK_thread_count);
1344
1468
thread_count--;
1345
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
1469
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1346
1470
pthread_mutex_unlock(&LOCK_thread_count);
1347
free((unsigned char*) arg);