71 #if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
72 #define FORCE_DBUG_OFF
75 #include "mysys_priv.h"
82 my_bool thr_lock_inited=0;
83 ulong locks_immediate = 0L, locks_waited = 0L;
84 enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
87 #define MAX_THREADS 100
91 LIST *thr_lock_thread_list;
92 ulong max_write_lock_count= ~(ulong) 0L;
94 static void (*before_lock_wait)(void)= 0;
95 static void (*after_lock_wait)(void)= 0;
97 void thr_set_lock_wait_callback(
void (*before_wait)(
void),
98 void (*after_wait)(
void))
100 before_lock_wait= before_wait;
101 after_lock_wait= after_wait;
106 return &my_thread_var->suspend;
113 my_bool init_thr_lock()
119 static inline my_bool
127 #define MAX_FOUND_ERRORS 10
128 static uint found_errors=0;
130 static int check_lock(
struct st_lock_list *list,
const char* lock_type,
131 const char *where, my_bool same_owner, my_bool no_cond)
140 enum thr_lock_type last_lock_type=list->data->type;
142 if (same_owner && list->data)
143 first_owner= list->data->owner;
144 for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
146 if (data->type != last_lock_type)
147 last_lock_type=TL_IGNORE;
148 if (data->prev != prev)
151 "Warning: prev link %d didn't point at previous lock at %s: %s\n",
152 count, lock_type, where);
156 !thr_lock_owner_equal(data->owner, first_owner) &&
157 last_lock_type != TL_WRITE_ALLOW_WRITE)
160 "Warning: Found locks from different threads in %s: %s\n",
164 if (no_cond && data->cond)
167 "Warning: Found active lock with not reset cond %s: %s\n",
175 fprintf(stderr,
"Warning: found too many locks at %s: %s\n",
180 if (prev != list->last)
182 fprintf(stderr,
"Warning: last didn't point at last lock at %s: %s\n",
190 static void check_locks(
THR_LOCK *lock,
const char *where,
191 my_bool allow_no_locks)
193 uint old_found_errors=found_errors;
194 DBUG_ENTER(
"check_locks");
196 if (found_errors < MAX_FOUND_ERRORS)
198 if (check_lock(&lock->write,
"write",where,1,1) |
199 check_lock(&lock->write_wait,
"write_wait",where,0,0) |
200 check_lock(&lock->read,
"read",where,0,1) |
201 check_lock(&lock->read_wait,
"read_wait",where,0,0))
204 if (found_errors < MAX_FOUND_ERRORS)
208 for (data=lock->read.data ; data ; data=data->next)
210 if ((
int) data->type == (
int) TL_READ_NO_INSERT)
213 DBUG_ASSERT(count <= lock->read_no_write_count);
215 if (count != lock->read_no_write_count)
219 "Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
222 if (!lock->write.data)
224 if (!allow_no_locks && !lock->read.data &&
225 (lock->write_wait.data || lock->read_wait.data))
229 "Warning at '%s': No locks in use but locks are in wait queue\n",
232 if (!lock->write_wait.data)
234 if (!allow_no_locks && lock->read_wait.data)
238 "Warning at '%s': No write locks and waiting read locks\n",
244 if (!allow_no_locks &&
245 (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
246 lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
247 !lock->read_no_write_count) ||
248 (lock->write_wait.data->type == TL_WRITE_DELAYED &&
253 "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(
int) lock->write_wait.data->type);
259 if (lock->write_wait.data)
261 if (!allow_no_locks &&
262 lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
263 lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
267 "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
273 if (!thr_lock_owner_equal(lock->write.data->owner,
274 lock->read.data->owner) &&
275 ((lock->write.data->type > TL_WRITE_DELAYED &&
276 lock->write.data->type != TL_WRITE_ONLY) ||
277 ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
278 lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
279 lock->read_no_write_count)))
283 "Warning at '%s': Found lock of type %d that is write and read locked\n",
284 where, lock->write.data->type);
285 DBUG_PRINT(
"warning",(
"At '%s': Found lock of type %d that is write and read locked\n",
286 where, lock->write.data->type));
290 if (lock->read_wait.data)
292 if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
293 lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
297 "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
299 (
int) lock->read_wait.data->type,
300 (
int) lock->write.data->type);
305 if (found_errors != old_found_errors)
307 DBUG_PRINT(
"error",(
"Found wrong lock"));
314 #define check_locks(A,B,C)
322 DBUG_ENTER(
"thr_lock_init");
323 memset(lock, 0,
sizeof(*lock));
326 lock->read.last= &lock->read.data;
327 lock->read_wait.last= &lock->read_wait.data;
328 lock->write_wait.last= &lock->write_wait.data;
329 lock->write.last= &lock->write.data;
332 lock->list.data=(
void*) lock;
333 thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
339 void thr_lock_delete(
THR_LOCK *lock)
341 DBUG_ENTER(
"thr_lock_delete");
343 thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
353 info->thread= tmp->pthread_self;
354 info->thread_id= tmp->id;
362 data->type=TL_UNLOCK;
364 data->status_param=param;
369 static inline my_bool
372 for ( ; data ; data=data->next)
374 if (thr_lock_owner_equal(data->owner, owner))
380 static inline my_bool have_specific_lock(
THR_LOCK_DATA *data,
381 enum thr_lock_type
type)
383 for ( ; data ; data=data->next)
385 if (data->type == type)
392 static void wake_up_waiters(
THR_LOCK *lock);
395 static enum enum_thr_lock_result
397 my_bool in_wait_list, ulong lock_wait_timeout)
402 enum enum_thr_lock_result result= THR_LOCK_ABORTED;
404 DBUG_ENTER(
"wait_for_lock");
426 DEBUG_SYNC_C(
"wait_for_lock");
431 data->prev= wait->last;
432 wait->last= &data->next;
435 statistic_increment(locks_waited, &THR_LOCK_lock);
438 thread_var->current_mutex= &data->lock->mutex;
439 thread_var->current_cond= cond;
442 proc_info_hook(NULL, &stage_waiting_for_table_level_lock,
444 __func__, __FILE__, __LINE__);
456 if ((!thread_var->abort || in_wait_list) && before_lock_wait)
457 (*before_lock_wait)();
459 set_timespec(wait_timeout, lock_wait_timeout);
460 while (!thread_var->abort || in_wait_list)
478 DBUG_PRINT(
"thr_lock", (
"lock granted/aborted"));
481 if (rc == ETIMEDOUT || rc == ETIME)
484 DBUG_PRINT(
"thr_lock", (
"lock timed out"));
485 result= THR_LOCK_WAIT_TIMEOUT;
496 (*after_lock_wait)();
498 DBUG_PRINT(
"thr_lock", (
"aborted: %d in_wait_list: %d",
499 thread_var->abort, in_wait_list));
501 if (data->cond || data->type == TL_UNLOCK)
505 if (((*data->prev)=data->next))
506 data->next->prev= data->prev;
508 wait->last=data->prev;
509 data->type= TL_UNLOCK;
510 check_locks(data->lock,
"killed or timed out wait_for_lock", 1);
511 wake_up_waiters(data->lock);
515 DBUG_PRINT(
"thr_lock", (
"lock aborted"));
516 check_locks(data->lock,
"aborted wait_for_lock", 0);
521 result= THR_LOCK_SUCCESS;
522 if (data->lock->get_status)
523 (*data->lock->get_status)(data->status_param, 0);
524 check_locks(data->lock,
"got wait_for_lock",0);
530 thread_var->current_mutex= 0;
531 thread_var->current_cond= 0;
534 proc_info_hook(NULL, &old_stage, NULL, __func__, __FILE__, __LINE__);
540 enum enum_thr_lock_result
542 enum thr_lock_type lock_type, ulong lock_wait_timeout)
545 enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
548 DBUG_ENTER("thr_lock");
552 data->type=lock_type;
556 PSI_TABLE_LOCK, lock_type);
559 DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
560 (
long) data, data->owner->thread_id,
561 (
long) lock, (
int) lock_type));
562 check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
563 "enter read_lock" : "enter write_lock",0);
564 if ((
int) lock_type <= (
int) TL_READ_NO_INSERT)
567 if (lock->write.data)
596 DBUG_PRINT(
"lock",(
"write locked 1 by thread: 0x%lx",
597 lock->write.data->owner->thread_id));
598 if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
599 (lock->write.data->type <= TL_WRITE_DELAYED &&
600 (((
int) lock_type <= (
int) TL_READ_HIGH_PRIORITY) ||
601 (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT))))
603 (*lock->read.last)=data;
604 data->prev=lock->read.last;
605 lock->read.last= &data->next;
606 if (lock_type == TL_READ_NO_INSERT)
607 lock->read_no_write_count++;
608 check_locks(lock,
"read lock with old write lock",0);
609 if (lock->get_status)
610 (*lock->get_status)(data->status_param, 0);
611 statistic_increment(locks_immediate,&THR_LOCK_lock);
614 if (lock->write.data->type == TL_WRITE_ONLY)
617 data->type=TL_UNLOCK;
618 result= THR_LOCK_ABORTED;
622 else if (!lock->write_wait.data ||
623 lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
624 lock_type == TL_READ_HIGH_PRIORITY ||
625 has_old_lock(lock->read.data, data->owner))
627 (*lock->read.last)=data;
628 data->prev=lock->read.last;
629 lock->read.last= &data->next;
630 if (lock->get_status)
631 (*lock->get_status)(data->status_param, 0);
632 if (lock_type == TL_READ_NO_INSERT)
633 lock->read_no_write_count++;
634 check_locks(lock,
"read lock with no write locks",0);
635 statistic_increment(locks_immediate,&THR_LOCK_lock);
643 wait_queue= &lock->read_wait;
647 if (lock_type == TL_WRITE_DELAYED)
649 if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
651 data->type=TL_UNLOCK;
652 result= THR_LOCK_ABORTED;
655 if (lock->write.data || lock->read.data)
658 (*lock->write_wait.last)=data;
659 data->prev=lock->write_wait.last;
660 lock->write_wait.last= &data->next;
661 data->cond=get_cond();
666 statistic_increment(locks_immediate,&THR_LOCK_lock);
670 else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
671 data->type=lock_type= thr_upgraded_concurrent_insert_lock;
673 if (lock->write.data)
675 if (lock->write.data->type == TL_WRITE_ONLY)
679 if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
682 data->type=TL_UNLOCK;
683 result= THR_LOCK_ABORTED;
717 DBUG_ASSERT(! has_old_lock(lock->write.data, data->owner) ||
718 ((lock_type <= lock->write.data->type ||
719 (lock_type == TL_WRITE &&
720 lock->write.data->type == TL_WRITE_LOW_PRIORITY)) &&
721 lock->write.data->type != TL_WRITE_DELAYED));
723 if ((lock_type == TL_WRITE_ALLOW_WRITE &&
724 ! lock->write_wait.data &&
725 lock->write.data->type == TL_WRITE_ALLOW_WRITE) ||
726 has_old_lock(lock->write.data, data->owner))
732 DBUG_PRINT(
"info", (
"write_wait.data: 0x%lx old_type: %d",
733 (ulong) lock->write_wait.data,
734 lock->write.data->type));
736 (*lock->write.last)=data;
737 data->prev=lock->write.last;
738 lock->write.last= &data->next;
739 check_locks(lock,
"second write lock",0);
740 if (data->lock->get_status)
741 (*data->lock->get_status)(data->status_param, 0);
742 statistic_increment(locks_immediate,&THR_LOCK_lock);
745 DBUG_PRINT(
"lock",(
"write locked 2 by thread: 0x%lx",
746 lock->write.data->owner->thread_id));
750 DBUG_PRINT(
"info", (
"write_wait.data: 0x%lx",
751 (ulong) lock->write_wait.data));
752 if (!lock->write_wait.data)
754 my_bool concurrent_insert= 0;
755 if (lock_type == TL_WRITE_CONCURRENT_INSERT)
757 concurrent_insert= 1;
758 if ((*lock->check_status)(data->status_param))
760 concurrent_insert= 0;
761 data->type=lock_type= thr_upgraded_concurrent_insert_lock;
765 if (!lock->read.data ||
766 (lock_type <= TL_WRITE_DELAYED &&
767 ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
768 lock_type != TL_WRITE_ALLOW_WRITE) ||
769 !lock->read_no_write_count)))
771 (*lock->write.last)=data;
772 data->prev=lock->write.last;
773 lock->write.last= &data->next;
774 if (data->lock->get_status)
775 (*data->lock->get_status)(data->status_param, concurrent_insert);
776 check_locks(lock,
"only write lock",0);
777 statistic_increment(locks_immediate,&THR_LOCK_lock);
781 DBUG_PRINT(
"lock",(
"write locked 3 by thread: 0x%lx type: %d",
782 lock->read.data->owner->thread_id, data->type));
784 wait_queue= &lock->write_wait;
787 result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout);
797 static inline void free_all_read_locks(
THR_LOCK *lock,
798 my_bool using_concurrent_insert)
802 check_locks(lock,
"before freeing read locks",1);
805 (*lock->read.last)=data;
806 data->prev=lock->read.last;
807 lock->read.last=lock->read_wait.last;
810 lock->read_wait.last= &lock->read_wait.data;
815 if ((
int) data->type == (int) TL_READ_NO_INSERT)
817 if (using_concurrent_insert)
823 if (((*data->prev)=data->next))
824 data->next->prev=data->prev;
826 lock->read.last=data->prev;
827 *lock->read_wait.last= data;
828 data->prev= lock->read_wait.last;
829 lock->read_wait.last= &data->next;
832 lock->read_no_write_count++;
835 DBUG_PRINT(
"lock",(
"giving read lock to thread: 0x%lx",
836 data->owner->thread_id));
840 }
while ((data=data->next));
841 *lock->read_wait.last=0;
842 if (!lock->read_wait.data)
843 lock->write_lock_count=0;
844 check_locks(lock,
"after giving read locks",0);
852 enum thr_lock_type lock_type=data->type;
853 DBUG_ENTER(
"thr_unlock");
854 DBUG_PRINT(
"lock",(
"data: 0x%lx thread: 0x%lx lock: 0x%lx",
855 (
long) data, data->owner->thread_id, (
long) lock));
857 check_locks(lock,
"start of release lock",0);
859 if (((*data->prev)=data->next))
860 data->next->prev= data->prev;
861 else if (lock_type <= TL_READ_NO_INSERT)
862 lock->read.last=data->prev;
863 else if (lock_type == TL_WRITE_DELAYED && data->cond)
869 lock->write_wait.last=data->prev;
872 lock->write.last=data->prev;
873 if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
875 if (lock->update_status)
876 (*lock->update_status)(data->status_param);
880 if (lock->restore_status)
881 (*lock->restore_status)(data->status_param);
883 if (lock_type == TL_READ_NO_INSERT)
884 lock->read_no_write_count--;
885 data->type=TL_UNLOCK;
886 check_locks(lock,
"after releasing lock",1);
887 wake_up_waiters(lock);
901 static void wake_up_waiters(
THR_LOCK *lock)
904 enum thr_lock_type lock_type;
906 DBUG_ENTER(
"wake_up_waiters");
908 if (!lock->write.data)
910 data=lock->write_wait.data;
911 if (!lock->read.data)
915 (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
916 lock->read_wait.data->type < TL_READ_HIGH_PRIORITY))
918 if (lock->write_lock_count++ > max_write_lock_count)
921 lock->write_lock_count=0;
922 if (lock->read_wait.data)
924 DBUG_PRINT(
"info",(
"Freeing all read_locks because of max_write_lock_count"));
925 free_all_read_locks(lock,0);
931 if (((*data->prev)=data->next))
932 data->next->prev= data->prev;
934 lock->write_wait.last=data->prev;
935 (*lock->write.last)=data;
936 data->prev=lock->write.last;
938 lock->write.last= &data->next;
939 if (data->type == TL_WRITE_CONCURRENT_INSERT &&
940 (*lock->check_status)(data->status_param))
943 DBUG_PRINT(
"lock",(
"giving write lock of type %d to thread: 0x%lx",
944 data->type, data->owner->thread_id));
951 if (data->type != TL_WRITE_ALLOW_WRITE ||
952 !lock->write_wait.data ||
953 lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
955 data=lock->write_wait.data;
957 if (data->type >= TL_WRITE_LOW_PRIORITY)
961 if (lock->read_wait.data)
962 free_all_read_locks(lock,
964 (data->type == TL_WRITE_CONCURRENT_INSERT ||
965 data->type == TL_WRITE_ALLOW_WRITE));
968 DBUG_PRINT(
"lock",(
"No waiting read locks to free"));
972 (lock_type=data->type) <= TL_WRITE_DELAYED &&
973 ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
974 lock_type != TL_WRITE_ALLOW_WRITE) ||
975 !lock->read_no_write_count))
981 if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
982 (*lock->check_status)(data->status_param))
985 if (lock->read_wait.data)
986 free_all_read_locks(lock,0);
991 if (((*data->prev)=data->next))
992 data->next->prev= data->prev;
994 lock->write_wait.last=data->prev;
995 (*lock->write.last)=data;
996 data->prev=lock->write.last;
997 lock->write.last= &data->next;
1001 }
while (lock_type == TL_WRITE_ALLOW_WRITE &&
1002 (data=lock->write_wait.data) &&
1003 data->type == TL_WRITE_ALLOW_WRITE);
1004 if (lock->read_wait.data)
1005 free_all_read_locks(lock,
1006 (lock_type == TL_WRITE_CONCURRENT_INSERT ||
1007 lock_type == TL_WRITE_ALLOW_WRITE));
1009 else if (!data && lock->read_wait.data)
1010 free_all_read_locks(lock,0);
1013 check_locks(lock,
"after waking up waiters", 0);
1025 #define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
1033 for (pos=data+1,end=data+count; pos < end ; pos++)
1036 if (LOCK_CMP(tmp,pos[-1]))
1041 }
while (--prev != data && LOCK_CMP(tmp,prev[-1]));
1048 enum enum_thr_lock_result
1050 ulong lock_wait_timeout)
1053 DBUG_ENTER(
"thr_multi_lock");
1054 DBUG_PRINT(
"lock",(
"data: 0x%lx count: %d", (
long) data, count));
1056 sort_locks(data,count);
1058 for (pos=data,end=data+count; pos < end ; pos++)
1060 enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type,
1062 if (result != THR_LOCK_SUCCESS)
1064 thr_multi_unlock(data,(uint) (pos-data));
1065 DBUG_RETURN(result);
1067 DEBUG_SYNC_C(
"thr_multi_lock_after_thr_lock");
1069 printf(
"Thread: %s Got lock: 0x%lx type: %d\n",my_thread_name(),
1070 (
long) pos[0]->lock, pos[0]->type); fflush(stdout);
1073 thr_lock_merge_status(data, count);
1074 DBUG_RETURN(THR_LOCK_SUCCESS);
1107 #if !defined(DONT_USE_RW_LOCKS)
1117 if (last_lock->lock == (*pos)->lock &&
1118 last_lock->lock->copy_status)
1120 if (last_lock->type <= TL_READ_NO_INSERT)
1129 (*pos)->type <= TL_READ_NO_INSERT &&
1131 pos[-1]->lock == (*pos)->lock ;
1137 (last_lock->lock->copy_status)((*read_lock)->status_param,
1138 (*pos)->status_param);
1139 }
while (*(read_lock++) != last_lock);
1143 (*last_lock->lock->copy_status)((*pos)->status_param,
1144 last_lock->status_param);
1148 }
while (pos != data);
1158 DBUG_ENTER(
"thr_multi_unlock");
1159 DBUG_PRINT(
"lock",(
"data: 0x%lx count: %d", (
long) data, count));
1161 for (pos=data,end=data+count; pos < end ; pos++)
1164 printf(
"Thread: %s Rel lock: 0x%lx type: %d\n",
1165 my_thread_name(), (
long) pos[0]->lock, pos[0]->type);
1168 if ((*pos)->type != TL_UNLOCK)
1172 DBUG_PRINT(
"lock",(
"Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
1173 (
long) *pos, (*pos)->owner->thread_id,
1174 (
long) (*pos)->lock));
1185 void thr_abort_locks(
THR_LOCK *lock, my_bool upgrade_lock)
1188 DBUG_ENTER(
"thr_abort_locks");
1191 for (data=lock->read_wait.data; data ; data=data->next)
1193 data->type=TL_UNLOCK;
1198 for (data=lock->write_wait.data; data ; data=data->next)
1200 data->type=TL_UNLOCK;
1204 lock->read_wait.last= &lock->read_wait.data;
1205 lock->write_wait.last= &lock->write_wait.data;
1206 lock->read_wait.data=lock->write_wait.data=0;
1207 if (upgrade_lock && lock->write.data)
1208 lock->write.data->type=TL_WRITE_ONLY;
1220 my_bool thr_abort_locks_for_thread(
THR_LOCK *lock, my_thread_id thread_id)
1223 my_bool found= FALSE;
1224 DBUG_ENTER(
"thr_abort_locks_for_thread");
1227 for (data= lock->read_wait.data; data ; data= data->next)
1229 if (data->owner->thread_id == thread_id)
1231 DBUG_PRINT(
"info",(
"Aborting read-wait lock"));
1232 data->type= TL_UNLOCK;
1238 if (((*data->prev)= data->next))
1239 data->next->prev= data->prev;
1241 lock->read_wait.last= data->prev;
1244 for (data= lock->write_wait.data; data ; data= data->next)
1246 if (data->owner->thread_id == thread_id)
1248 DBUG_PRINT(
"info",(
"Aborting write-wait lock"));
1249 data->type= TL_UNLOCK;
1254 if (((*data->prev)= data->next))
1255 data->next->prev= data->prev;
1257 lock->write_wait.last= data->prev;
1260 wake_up_waiters(lock);
1294 enum thr_lock_type new_lock_type)
1298 enum thr_lock_type old_lock_type= in_data->type;
1300 DBUG_ENTER(
"thr_downgrade_write_only_lock");
1303 DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
1304 DBUG_ASSERT(old_lock_type > new_lock_type);
1305 in_data->type= new_lock_type;
1306 check_locks(lock,
"after downgrading lock",0);
1315 enum thr_lock_type new_lock_type,
1316 ulong lock_wait_timeout)
1319 DBUG_ENTER(
"thr_upgrade_write_delay_lock");
1322 if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1325 DBUG_RETURN(data->type == TL_UNLOCK);
1327 check_locks(lock,
"before upgrading lock",0);
1329 data->type= new_lock_type;
1334 if (!lock->read.data)
1336 if (data->lock->get_status)
1337 (*data->lock->get_status)(data->status_param, 0);
1342 if (((*data->prev)=data->next))
1343 data->next->prev= data->prev;
1345 lock->write.last=data->prev;
1347 if ((data->next=lock->write_wait.data))
1348 data->next->prev= &data->next;
1350 lock->write_wait.last= &data->next;
1351 data->prev= &lock->write_wait.data;
1352 lock->write_wait.data=data;
1353 check_locks(lock,
"upgrading lock",0);
1357 check_locks(lock,
"waiting for lock",0);
1359 DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1, lock_wait_timeout));
1366 ulong lock_wait_timeout)
1369 enum thr_lock_type write_lock_type;
1370 DBUG_ENTER(
"thr_reschedule_write_lock");
1373 if (!lock->read_wait.data)
1379 write_lock_type= data->type;
1380 data->type=TL_WRITE_DELAYED;
1381 if (lock->update_status)
1382 (*lock->update_status)(data->status_param);
1383 if (((*data->prev)=data->next))
1384 data->next->prev= data->prev;
1386 lock->write.last=data->prev;
1388 if ((data->next=lock->write_wait.data))
1389 data->next->prev= &data->next;
1391 lock->write_wait.last= &data->next;
1392 data->prev= &lock->write_wait.data;
1393 data->cond=get_cond();
1394 lock->write_wait.data=data;
1395 free_all_read_locks(lock,0);
1398 DBUG_RETURN(thr_upgrade_write_delay_lock(data, write_lock_type,
1399 lock_wait_timeout));
1412 printf(
"%-10s: ",name);
1414 for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
1416 printf(
"0x%lx (%lu:%d); ", (ulong) data, data->owner->thread_id,
1418 if (data->prev != prev)
1419 printf(
"\nWarning: prev didn't point at previous lock\n");
1423 if (prev != list->last)
1424 printf(
"Warning: last didn't point at last lock\n");
1428 void thr_print_locks(
void)
1434 puts(
"Current locks:");
1435 for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
1436 list= list_rest(list))
1440 printf(
"lock: 0x%lx:",(ulong) lock);
1441 if ((lock->write_wait.data || lock->read_wait.data) &&
1442 (! lock->read.data && ! lock->write.data))
1443 printf(
" WARNING: ");
1444 if (lock->write.data)
1446 if (lock->write_wait.data)
1447 printf(
" write_wait");
1448 if (lock->read.data)
1450 if (lock->read_wait.data)
1451 printf(
" read_wait");
1453 thr_print_lock(
"write",&lock->write);
1454 thr_print_lock(
"write_wait",&lock->write_wait);
1455 thr_print_lock(
"read",&lock->read);
1456 thr_print_lock(
"read_wait",&lock->read_wait);
1473 enum thr_lock_type lock_type;
1478 struct st_test test_0[] = {{0,TL_READ}};
1479 struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}};
1480 struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
1481 struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}};
1482 struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
1483 struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}};
1484 struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}};
1485 struct st_test test_7[] = {{3,TL_READ}};
1486 struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}};
1487 struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
1488 struct st_test test_10[] ={{4,TL_WRITE}};
1489 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}};
1490 struct st_test test_12[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_WRITE_CONCURRENT_INSERT},{2,TL_WRITE_CONCURRENT_INSERT},{3,TL_WRITE_CONCURRENT_INSERT}};
1491 struct st_test test_13[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
1492 struct st_test test_14[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
1493 struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
1495 struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
1496 test_7,test_8,test_9,test_10,test_11,test_12,
1497 test_13,test_14,test_15};
1498 int lock_counts[]= {
sizeof(test_0)/
sizeof(
struct st_test),
1499 sizeof(test_1)/
sizeof(
struct st_test),
1500 sizeof(test_2)/
sizeof(
struct st_test),
1501 sizeof(test_3)/
sizeof(
struct st_test),
1502 sizeof(test_4)/
sizeof(
struct st_test),
1503 sizeof(test_5)/
sizeof(
struct st_test),
1504 sizeof(test_6)/
sizeof(
struct st_test),
1505 sizeof(test_7)/
sizeof(
struct st_test),
1506 sizeof(test_8)/
sizeof(
struct st_test),
1507 sizeof(test_9)/
sizeof(
struct st_test),
1508 sizeof(test_10)/
sizeof(
struct st_test),
1509 sizeof(test_11)/
sizeof(
struct st_test),
1510 sizeof(test_12)/
sizeof(
struct st_test),
1511 sizeof(test_13)/
sizeof(
struct st_test),
1512 sizeof(test_14)/
sizeof(
struct st_test),
1513 sizeof(test_15)/
sizeof(
struct st_test)
1519 static uint thread_count;
1522 #define MAX_LOCK_COUNT 8
1523 #define TEST_TIMEOUT 100000
1527 static void test_get_status(
void* param __attribute__((unused)),
1528 int concurrent_insert __attribute__((unused)))
1532 static void test_update_status(
void* param __attribute__((unused)))
1536 static void test_copy_status(
void*
to __attribute__((unused)) ,
1537 void *from __attribute__((unused)))
1541 static my_bool test_check_status(
void* param __attribute__((unused)))
1547 static void *test_thread(
void *arg)
1549 int i,j,param=*((
int*) arg);
1555 printf(
"Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
1558 thr_lock_info_init(&lock_info);
1559 for (i=0; i < lock_counts[param] ; i++)
1560 thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
1561 for (j=1 ; j < 10 ; j++)
1563 for (i=0; i < lock_counts[param] ; i++)
1565 multi_locks[
i]= &data[
i];
1566 data[
i].type= tests[param][
i].lock_type;
1568 thr_multi_lock(multi_locks, lock_counts[param], &lock_info, TEST_TIMEOUT);
1579 for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
1584 thr_multi_unlock(multi_locks,lock_counts[param]);
1587 printf(
"Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
1598 int main(
int argc __attribute__((unused)),
char **argv __attribute__((unused)))
1601 pthread_attr_t thr_attr;
1604 if (argc > 1 && argv[1][0] ==
'-' && argv[1][1] ==
'#')
1605 DBUG_PUSH(argv[1]+2);
1607 printf(
"Main thread: %s\n",my_thread_name());
1611 fprintf(stderr,
"Got error: %d from mysql_cond_init (errno: %d)",
1617 fprintf(stderr,
"Got error: %d from mysql_cond_init (errno: %d)",
1622 for (i=0 ; i < (int) array_elements(locks) ; i++)
1624 thr_lock_init(locks+i);
1625 locks[
i].check_status= test_check_status;
1626 locks[
i].update_status=test_update_status;
1627 locks[
i].copy_status= test_copy_status;
1628 locks[
i].get_status= test_get_status;
1630 if ((error=pthread_attr_init(&thr_attr)))
1632 fprintf(stderr,
"Got error: %d from pthread_attr_init (errno: %d)",
1636 if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
1639 "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
1643 #ifndef pthread_attr_setstacksize
1644 if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
1646 fprintf(stderr,
"Got error: %d from pthread_attr_setstacksize (errno: %d)",
1651 #ifdef HAVE_THR_SETCONCURRENCY
1652 (void) thr_setconcurrency(2);
1654 for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1656 param=(
int*) malloc(
sizeof(
int));
1661 fprintf(stderr,
"Got error: %d from mysql_mutex_lock (errno: %d)",
1666 &tid, &thr_attr, test_thread,
1669 fprintf(stderr,
"Got error: %d from mysql_thread_create (errno: %d)\n",
1678 pthread_attr_destroy(&thr_attr);
1680 fprintf(stderr,
"Got error: %d from mysql_mutex_lock\n", error);
1681 while (thread_count)
1684 fprintf(stderr,
"Got error: %d from mysql_cond_wait\n", error);
1687 fprintf(stderr,
"Got error: %d from mysql_mutex_unlock\n", error);
1688 for (i=0 ; i < (int) array_elements(locks) ; i++)
1689 thr_lock_delete(locks+i);
1692 printf(
"Got %d warnings\n",found_errors);
1695 printf(
"Test succeeded\n");