~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_lock.c

Removed SCCS references.

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
 
71
71
*/
72
72
 
 
73
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
 
74
#define FORCE_DBUG_OFF
 
75
#endif
 
76
 
73
77
#include "mysys_priv.h"
74
78
 
 
79
#ifdef THREAD
75
80
#include "thr_lock.h"
76
 
#include <mystrings/m_string.h>
 
81
#include <m_string.h>
77
82
#include <errno.h>
78
83
 
79
 
#if TIME_WITH_SYS_TIME
80
 
# include <sys/time.h>
81
 
# include <time.h>
82
 
#else
83
 
# if HAVE_SYS_TIME_H
84
 
#  include <sys/time.h>
85
 
# else
86
 
#  include <time.h>
87
 
# endif
88
 
#endif  
89
 
 
90
 
#include <drizzled/util/test.h>
91
 
 
92
 
bool thr_lock_inited=0;
93
 
uint32_t locks_immediate = 0L, locks_waited = 0L;
 
84
my_bool thr_lock_inited=0;
 
85
ulong locks_immediate = 0L, locks_waited = 0L;
94
86
ulong table_lock_wait_timeout;
95
87
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
96
88
 
111
103
** For the future (now the thread specific cond is alloced by my_pthread.c)
112
104
*/
113
105
 
114
 
bool init_thr_lock()
 
106
my_bool init_thr_lock()
115
107
{
116
108
  thr_lock_inited=1;
117
109
  return 0;
118
110
}
119
111
 
120
 
static inline bool
 
112
static inline my_bool
121
113
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
122
114
{
123
115
  return rhs == lhs;
124
116
}
125
117
 
 
118
 
126
119
#ifdef EXTRA_DEBUG
127
120
#define MAX_FOUND_ERRORS        10              /* Report 10 first errors */
128
 
static uint32_t found_errors=0;
 
121
static uint found_errors=0;
129
122
 
130
123
static int check_lock(struct st_lock_list *list, const char* lock_type,
131
 
                      const char *where, bool same_owner, bool no_cond)
 
124
                      const char *where, my_bool same_owner, my_bool no_cond)
132
125
{
133
126
  THR_LOCK_DATA *data,**prev;
134
 
  uint32_t count=0;
 
127
  uint count=0;
135
128
  THR_LOCK_OWNER *first_owner;
136
129
 
137
130
  prev= &list->data;
188
181
 
189
182
 
190
183
static void check_locks(THR_LOCK *lock, const char *where,
191
 
                        bool allow_no_locks)
 
184
                        my_bool allow_no_locks)
192
185
{
193
 
  uint32_t old_found_errors=found_errors;
 
186
  uint old_found_errors=found_errors;
 
187
  DBUG_ENTER("check_locks");
194
188
 
195
189
  if (found_errors < MAX_FOUND_ERRORS)
196
190
  {
202
196
 
203
197
    if (found_errors < MAX_FOUND_ERRORS)
204
198
    {
205
 
      uint32_t count=0;
 
199
      uint count=0;
206
200
      THR_LOCK_DATA *data;
207
201
      for (data=lock->read.data ; data ; data=data->next)
208
202
      {
209
203
        if ((int) data->type == (int) TL_READ_NO_INSERT)
210
204
          count++;
211
205
        /* Protect against infinite loop. */
212
 
        assert(count <= lock->read_no_write_count);
 
206
        DBUG_ASSERT(count <= lock->read_no_write_count);
213
207
      }
214
208
      if (count != lock->read_no_write_count)
215
209
      {
282
276
            fprintf(stderr,
283
277
                    "Warning at '%s': Found lock of type %d that is write and read locked\n",
284
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));
 
281
 
285
282
          }
286
283
        }
287
284
        if (lock->read_wait.data)
299
296
        }
300
297
      }
301
298
    }
 
299
    if (found_errors != old_found_errors)
 
300
    {
 
301
      DBUG_PRINT("error",("Found wrong lock"));
 
302
    }
302
303
  }
303
 
  return;
 
304
  DBUG_VOID_RETURN;
304
305
}
305
306
 
306
307
#else /* EXTRA_DEBUG */
312
313
 
313
314
void thr_lock_init(THR_LOCK *lock)
314
315
{
315
 
  memset(lock, 0, sizeof(*lock));
316
 
  pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST);
 
316
  DBUG_ENTER("thr_lock_init");
 
317
  bzero((char*) lock,sizeof(*lock));
 
318
  VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
317
319
  lock->read.last= &lock->read.data;
318
320
  lock->read_wait.last= &lock->read_wait.data;
319
321
  lock->write_wait.last= &lock->write_wait.data;
323
325
  lock->list.data=(void*) lock;
324
326
  thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
325
327
  pthread_mutex_unlock(&THR_LOCK_lock);
326
 
  return;
 
328
  DBUG_VOID_RETURN;
327
329
}
328
330
 
329
331
 
330
332
void thr_lock_delete(THR_LOCK *lock)
331
333
{
332
 
  pthread_mutex_destroy(&lock->mutex);
 
334
  DBUG_ENTER("thr_lock_delete");
 
335
  VOID(pthread_mutex_destroy(&lock->mutex));
333
336
  pthread_mutex_lock(&THR_LOCK_lock);
334
337
  thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
335
338
  pthread_mutex_unlock(&THR_LOCK_lock);
336
 
  return;
 
339
  DBUG_VOID_RETURN;
337
340
}
338
341
 
339
342
 
357
360
}
358
361
 
359
362
 
360
 
static inline bool
 
363
static inline my_bool
361
364
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
362
365
{
363
366
  for ( ; data ; data=data->next)
368
371
  return 0;
369
372
}
370
373
 
371
 
static inline bool have_specific_lock(THR_LOCK_DATA *data,
 
374
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
372
375
                                         enum thr_lock_type type)
373
376
{
374
377
  for ( ; data ; data=data->next)
385
388
 
386
389
static enum enum_thr_lock_result
387
390
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
388
 
              bool in_wait_list)
 
391
              my_bool in_wait_list)
389
392
{
390
393
  struct st_my_thread_var *thread_var= my_thread_var;
391
394
  pthread_cond_t *cond= &thread_var->suspend;
392
395
  struct timespec wait_timeout;
393
396
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
394
 
  bool can_deadlock= test(data->owner->info->n_cursors);
 
397
  my_bool can_deadlock= test(data->owner->info->n_cursors);
 
398
  DBUG_ENTER("wait_for_lock");
395
399
 
396
400
  if (!in_wait_list)
397
401
  {
430
434
    */
431
435
    if (data->cond == 0)
432
436
    {
 
437
      DBUG_PRINT("thr_lock", ("lock granted/aborted"));
433
438
      break;
434
439
    }
435
440
    if (rc == ETIMEDOUT || rc == ETIME)
436
441
    {
437
442
      /* purecov: begin inspected */
 
443
      DBUG_PRINT("thr_lock", ("lock timed out"));
438
444
      result= THR_LOCK_WAIT_TIMEOUT;
439
445
      break;
440
446
      /* purecov: end */
441
447
    }
442
448
  }
 
449
  DBUG_PRINT("thr_lock", ("aborted: %d  in_wait_list: %d",
 
450
                          thread_var->abort, in_wait_list));
 
451
 
443
452
  if (data->cond || data->type == TL_UNLOCK)
444
453
  {
445
454
    if (data->cond)                             /* aborted or timed out */
454
463
    }
455
464
    else
456
465
    {
 
466
      DBUG_PRINT("thr_lock", ("lock aborted"));
457
467
      check_locks(data->lock, "aborted wait_for_lock", 0);
458
468
    }
459
469
  }
471
481
  thread_var->current_mutex= 0;
472
482
  thread_var->current_cond=  0;
473
483
  pthread_mutex_unlock(&thread_var->mutex);
474
 
  return(result);
 
484
  DBUG_RETURN(result);
475
485
}
476
486
 
477
487
 
483
493
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
484
494
  struct st_lock_list *wait_queue;
485
495
  THR_LOCK_DATA *lock_owner;
 
496
  DBUG_ENTER("thr_lock");
486
497
 
487
498
  data->next=0;
488
499
  data->cond=0;                                 /* safety */
489
500
  data->type=lock_type;
490
501
  data->owner= owner;                           /* Must be reset ! */
491
 
  pthread_mutex_lock(&lock->mutex);
 
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));
492
506
  check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
493
507
              "enter read_lock" : "enter write_lock",0);
494
508
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
505
519
           and the read lock is not TL_READ_NO_INSERT
506
520
      */
507
521
 
 
522
      DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
 
523
                         lock->write.data->owner->info->thread_id));
508
524
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
509
525
          (lock->write.data->type <= TL_WRITE_DELAYED &&
510
526
           (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
616
632
          We have already got a write lock or all locks are
617
633
          TL_WRITE_ALLOW_WRITE
618
634
        */
 
635
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
 
636
                            (ulong) lock->write_wait.data,
 
637
                            lock->write.data->type));
619
638
 
620
639
        (*lock->write.last)=data;       /* Add to running fifo */
621
640
        data->prev=lock->write.last;
626
645
        statistic_increment(locks_immediate,&THR_LOCK_lock);
627
646
        goto end;
628
647
      }
 
648
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
 
649
                         lock->write.data->owner->info->thread_id));
629
650
    }
630
651
    else
631
652
    {
 
653
      DBUG_PRINT("info", ("write_wait.data: 0x%lx",
 
654
                          (ulong) lock->write_wait.data));
632
655
      if (!lock->write_wait.data)
633
656
      {                                         /* no scheduled write locks */
634
 
        bool concurrent_insert= 0;
 
657
        my_bool concurrent_insert= 0;
635
658
        if (lock_type == TL_WRITE_CONCURRENT_INSERT)
636
659
        {
637
660
          concurrent_insert= 1;
658
681
          goto end;
659
682
        }
660
683
      }
 
684
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
 
685
                         lock->read.data->owner->info->thread_id, data->type));
661
686
    }
662
687
    wait_queue= &lock->write_wait;
663
688
  }
670
695
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
671
696
  if (lock_owner && lock_owner->owner->info == owner->info)
672
697
  {
 
698
    DBUG_PRINT("lock",("deadlock"));
673
699
    result= THR_LOCK_DEADLOCK;
674
700
    goto end;
675
701
  }
676
702
  /* Can't get lock yet;  Wait for it */
677
 
  return(wait_for_lock(wait_queue, data, 0));
 
703
  DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
678
704
end:
679
705
  pthread_mutex_unlock(&lock->mutex);
680
 
  return(result);
 
706
  DBUG_RETURN(result);
681
707
}
682
708
 
683
709
 
684
710
static inline void free_all_read_locks(THR_LOCK *lock,
685
 
                                       bool using_concurrent_insert)
 
711
                                       my_bool using_concurrent_insert)
686
712
{
687
713
  THR_LOCK_DATA *data=lock->read_wait.data;
688
714
 
718
744
      }
719
745
      lock->read_no_write_count++;
720
746
    }      
 
747
    /* purecov: begin inspected */
 
748
    DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
 
749
                       data->owner->info->thread_id));
 
750
    /* purecov: end */
721
751
    data->cond=0;                               /* Mark thread free */
722
 
    pthread_cond_signal(cond);
 
752
    VOID(pthread_cond_signal(cond));
723
753
  } while ((data=data->next));
724
754
  *lock->read_wait.last=0;
725
755
  if (!lock->read_wait.data)
733
763
{
734
764
  THR_LOCK *lock=data->lock;
735
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));
736
769
  pthread_mutex_lock(&lock->mutex);
737
770
  check_locks(lock,"start of release lock",0);
738
771
 
766
799
  check_locks(lock,"after releasing lock",1);
767
800
  wake_up_waiters(lock);
768
801
  pthread_mutex_unlock(&lock->mutex);
769
 
  return;
 
802
  DBUG_VOID_RETURN;
770
803
}
771
804
 
772
805
 
783
816
  THR_LOCK_DATA *data;
784
817
  enum thr_lock_type lock_type;
785
818
 
 
819
  DBUG_ENTER("wake_up_waiters");
 
820
 
786
821
  if (!lock->write.data)                        /* If no active write locks */
787
822
  {
788
823
    data=lock->write_wait.data;
799
834
          lock->write_lock_count=0;
800
835
          if (lock->read_wait.data)
801
836
          {
 
837
            DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
802
838
            free_all_read_locks(lock,0);
803
839
            goto end;
804
840
          }
816
852
          if (data->type == TL_WRITE_CONCURRENT_INSERT &&
817
853
              (*lock->check_status)(data->status_param))
818
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));
 
858
          /* purecov: end */
819
859
          {
820
860
            pthread_cond_t *cond=data->cond;
821
861
            data->cond=0;                               /* Mark thread free */
822
 
            pthread_cond_signal(cond);  /* Start waiting thread */
 
862
            VOID(pthread_cond_signal(cond));    /* Start waiting thread */
823
863
          }
824
864
          if (data->type != TL_WRITE_ALLOW_WRITE ||
825
865
              !lock->write_wait.data ||
836
876
                            data &&
837
877
                            (data->type == TL_WRITE_CONCURRENT_INSERT ||
838
878
                             data->type == TL_WRITE_ALLOW_WRITE));
 
879
      else
 
880
      {
 
881
        DBUG_PRINT("lock",("No waiting read locks to free"));
 
882
      }
839
883
    }
840
884
    else if (data &&
841
885
             (lock_type=data->type) <= TL_WRITE_DELAYED &&
866
910
        lock->write.last= &data->next;
867
911
        data->next=0;                           /* Only one write lock */
868
912
        data->cond=0;                           /* Mark thread free */
869
 
        pthread_cond_signal(cond);      /* Start waiting thread */
 
913
        VOID(pthread_cond_signal(cond));        /* Start waiting thread */
870
914
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
871
915
               (data=lock->write_wait.data) &&
872
916
               data->type == TL_WRITE_ALLOW_WRITE);
880
924
  }
881
925
end:
882
926
  check_locks(lock, "after waking up waiters", 0);
883
 
  return;
 
927
  DBUG_VOID_RETURN;
884
928
}
885
929
 
886
930
 
891
935
*/
892
936
 
893
937
 
894
 
#define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint) ((A)->type) < (unsigned char*) (B->lock)- (uint) ((B)->type))
 
938
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
895
939
 
896
 
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
 
940
static void sort_locks(THR_LOCK_DATA **data,uint count)
897
941
{
898
942
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
899
943
 
915
959
 
916
960
 
917
961
enum enum_thr_lock_result
918
 
thr_multi_lock(THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
 
962
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
919
963
{
920
964
  THR_LOCK_DATA **pos,**end;
 
965
  DBUG_ENTER("thr_multi_lock");
 
966
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
921
967
  if (count > 1)
922
968
    sort_locks(data,count);
923
969
  /* lock everything */
927
973
    if (result != THR_LOCK_SUCCESS)
928
974
    {                                           /* Aborted */
929
975
      thr_multi_unlock(data,(uint) (pos-data));
930
 
      return(result);
 
976
      DBUG_RETURN(result);
931
977
    }
932
978
#ifdef MAIN
933
979
    printf("Thread: %s  Got lock: 0x%lx  type: %d\n",my_thread_name(),
981
1027
    } while (pos != data);
982
1028
  }
983
1029
#endif
984
 
  return(THR_LOCK_SUCCESS);
 
1030
  DBUG_RETURN(THR_LOCK_SUCCESS);
985
1031
}
986
1032
 
987
1033
  /* free all locks */
988
1034
 
989
 
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
 
1035
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
990
1036
{
991
1037
  THR_LOCK_DATA **pos,**end;
 
1038
  DBUG_ENTER("thr_multi_unlock");
 
1039
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
992
1040
 
993
1041
  for (pos=data,end=data+count; pos < end ; pos++)
994
1042
  {
999
1047
#endif
1000
1048
    if ((*pos)->type != TL_UNLOCK)
1001
1049
      thr_unlock(*pos);
 
1050
    else
 
1051
    {
 
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));
 
1055
    }
1002
1056
  }
1003
 
  return;
 
1057
  DBUG_VOID_RETURN;
1004
1058
}
1005
1059
 
1006
1060
/*
1008
1062
  TL_WRITE_ONLY to abort any new accesses to the lock
1009
1063
*/
1010
1064
 
1011
 
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
 
1065
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
1012
1066
{
1013
1067
  THR_LOCK_DATA *data;
 
1068
  DBUG_ENTER("thr_abort_locks");
1014
1069
  pthread_mutex_lock(&lock->mutex);
1015
1070
 
1016
1071
  for (data=lock->read_wait.data; data ; data=data->next)
1032
1087
  if (upgrade_lock && lock->write.data)
1033
1088
    lock->write.data->type=TL_WRITE_ONLY;
1034
1089
  pthread_mutex_unlock(&lock->mutex);
1035
 
  return;
 
1090
  DBUG_VOID_RETURN;
1036
1091
}
1037
1092
 
1038
1093
 
1042
1097
  This is used to abort all locks for a specific thread
1043
1098
*/
1044
1099
 
1045
 
bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
 
1100
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
1046
1101
{
1047
1102
  THR_LOCK_DATA *data;
1048
 
  bool found= false;
 
1103
  my_bool found= FALSE;
 
1104
  DBUG_ENTER("thr_abort_locks_for_thread");
1049
1105
 
1050
1106
  pthread_mutex_lock(&lock->mutex);
1051
1107
  for (data= lock->read_wait.data; data ; data= data->next)
1052
1108
  {
1053
1109
    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
1054
1110
    {
 
1111
      DBUG_PRINT("info",("Aborting read-wait lock"));
1055
1112
      data->type= TL_UNLOCK;                    /* Mark killed */
1056
1113
      /* It's safe to signal the cond first: we're still holding the mutex. */
1057
 
      found= true;
 
1114
      found= TRUE;
1058
1115
      pthread_cond_signal(data->cond);
1059
1116
      data->cond= 0;                            /* Removed from list */
1060
1117
 
1068
1125
  {
1069
1126
    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1070
1127
    {
 
1128
      DBUG_PRINT("info",("Aborting write-wait lock"));
1071
1129
      data->type= TL_UNLOCK;
1072
 
      found= true;
 
1130
      found= TRUE;
1073
1131
      pthread_cond_signal(data->cond);
1074
1132
      data->cond= 0;
1075
1133
 
1081
1139
  }
1082
1140
  wake_up_waiters(lock);
1083
1141
  pthread_mutex_unlock(&lock->mutex);
1084
 
  return(found);
 
1142
  DBUG_RETURN(found);
1085
1143
}
1086
1144
 
1087
1145
 
1119
1177
                              enum thr_lock_type new_lock_type)
1120
1178
{
1121
1179
  THR_LOCK *lock=in_data->lock;
 
1180
#ifndef DBUG_OFF
 
1181
  enum thr_lock_type old_lock_type= in_data->type;
 
1182
#endif
 
1183
#ifdef TO_BE_REMOVED
 
1184
  THR_LOCK_DATA *data, *next;
 
1185
  bool start_writers= FALSE;
 
1186
  bool start_readers= FALSE;
 
1187
#endif
 
1188
  DBUG_ENTER("thr_downgrade_write_only_lock");
1122
1189
 
1123
1190
  pthread_mutex_lock(&lock->mutex);
 
1191
  DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
 
1192
  DBUG_ASSERT(old_lock_type > new_lock_type);
1124
1193
  in_data->type= new_lock_type;
1125
1194
  check_locks(lock,"after downgrading lock",0);
1126
1195
 
 
1196
#if TO_BE_REMOVED
 
1197
  switch (old_lock_type)
 
1198
  {
 
1199
    case TL_WRITE_ONLY:
 
1200
    case TL_WRITE:
 
1201
    case TL_WRITE_LOW_PRIORITY:
 
1202
    /*
 
1203
      Previous lock was exclusive we are now ready to start up most waiting
 
1204
      threads.
 
1205
    */
 
1206
      switch (new_lock_type)
 
1207
      {
 
1208
        case TL_WRITE_ALLOW_READ:
 
1209
        /* Still cannot start WRITE operations. Can only start readers.  */
 
1210
          start_readers= TRUE;
 
1211
          break;
 
1212
        case TL_WRITE:
 
1213
        case TL_WRITE_LOW_PRIORITY:
 
1214
        /*
 
1215
           Still cannot start anything, but new requests are no longer
 
1216
           aborted.
 
1217
        */
 
1218
          break;
 
1219
        case TL_WRITE_ALLOW_WRITE:
 
1220
        /*
 
1221
          We can start both writers and readers.
 
1222
        */
 
1223
          start_writers= TRUE;
 
1224
          start_readers= TRUE;
 
1225
          break;
 
1226
        case TL_WRITE_CONCURRENT_INSERT:
 
1227
        case TL_WRITE_DELAYED:
 
1228
        /*
 
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.
 
1232
        */
 
1233
          break;
 
1234
        default:
 
1235
          DBUG_ASSERT(0);
 
1236
      }
 
1237
      break;
 
1238
    case TL_WRITE_DELAYED:
 
1239
    case TL_WRITE_CONCURRENT_INSERT:
 
1240
    /*
 
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.
 
1244
    */
 
1245
      break;
 
1246
    case TL_WRITE_ALLOW_READ:
 
1247
      DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
 
1248
      /*
 
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
 
1251
        handle them.
 
1252
      */
 
1253
      start_writers= TRUE;
 
1254
      break;
 
1255
    default:
 
1256
      DBUG_ASSERT(0);
 
1257
      break;
 
1258
  }
 
1259
  if (start_writers)
 
1260
  {
 
1261
    /*
 
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
 
1265
      waiting operations.
 
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.
 
1271
    */
 
1272
    DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
 
1273
    for (data=lock->write_wait.data; data ; data= next)
 
1274
    {
 
1275
      /*
 
1276
        All WRITE requests compatible with new lock type are also
 
1277
        started
 
1278
      */
 
1279
      next= data->next;
 
1280
      if (start_writers && data->type == new_lock_type)
 
1281
      {
 
1282
        pthread_cond_t *cond= data->cond;
 
1283
        /*
 
1284
          It is ok to start this waiter.
 
1285
          Move from being first in wait queue to be last in write queue.
 
1286
        */
 
1287
        if (((*data->prev)= data->next))
 
1288
          data->next->prev= data->prev;
 
1289
        else
 
1290
          lock->write_wait.last= data->prev;
 
1291
        data->prev= lock->write.last;
 
1292
        lock->write.last= &data->next;
 
1293
        data->next= 0;
 
1294
        check_locks(lock, "Started write lock after downgrade",0);
 
1295
        data->cond= 0;
 
1296
        pthread_cond_signal(cond);
 
1297
      }
 
1298
      else
 
1299
      {
 
1300
        /*
 
1301
          We found an incompatible lock, we won't start any more write
 
1302
          requests to avoid letting writers pass other writers in the
 
1303
          queue.
 
1304
        */
 
1305
        start_writers= FALSE;
 
1306
        if (data->type >= TL_WRITE_LOW_PRIORITY)
 
1307
        {
 
1308
          /*
 
1309
            We have an exclusive writer in the queue so we won't start
 
1310
            readers either.
 
1311
          */
 
1312
          start_readers= FALSE;
 
1313
        }
 
1314
      }
 
1315
    }
 
1316
  }
 
1317
  if (start_readers)
 
1318
  {
 
1319
    DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE ||
 
1320
                new_lock_type == TL_WRITE_ALLOW_READ);
 
1321
    /*
 
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
 
1324
      are ok
 
1325
    */
 
1326
    for (data=lock->read_wait.data; data ; data=next)
 
1327
    {
 
1328
      next= data->next;
 
1329
      /*
 
1330
        All reads are ok to start now except TL_READ_NO_INSERT when
 
1331
        write lock is TL_WRITE_ALLOW_READ.
 
1332
      */
 
1333
      if (new_lock_type != TL_WRITE_ALLOW_READ ||
 
1334
          data->type != TL_READ_NO_INSERT)
 
1335
      {
 
1336
        pthread_cond_t *cond= data->cond;
 
1337
        if (((*data->prev)= data->next))
 
1338
          data->next->prev= data->prev;
 
1339
        else
 
1340
          lock->read_wait.last= data->prev;
 
1341
        data->prev= lock->read.last;
 
1342
        lock->read.last= &data->next;
 
1343
        data->next= 0;
 
1344
 
 
1345
        if (data->type == TL_READ_NO_INSERT)
 
1346
          lock->read_no_write_count++;
 
1347
        check_locks(lock, "Started read lock after downgrade",0);
 
1348
        data->cond= 0;
 
1349
        pthread_cond_signal(cond);
 
1350
      }
 
1351
    }
 
1352
  }
 
1353
  check_locks(lock,"after starting waiters after downgrading lock",0);
 
1354
#endif
1127
1355
  pthread_mutex_unlock(&lock->mutex);
1128
 
  return;
 
1356
  DBUG_VOID_RETURN;
1129
1357
}
1130
1358
 
1131
1359
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1132
1360
 
1133
 
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
 
1361
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1134
1362
{
1135
1363
  THR_LOCK *lock=data->lock;
 
1364
  DBUG_ENTER("thr_upgrade_write_delay_lock");
1136
1365
 
1137
1366
  pthread_mutex_lock(&lock->mutex);
1138
1367
  if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1139
1368
  {
1140
1369
    pthread_mutex_unlock(&lock->mutex);
1141
 
    return(data->type == TL_UNLOCK);    /* Test if Aborted */
 
1370
    DBUG_RETURN(data->type == TL_UNLOCK);       /* Test if Aborted */
1142
1371
  }
1143
1372
  check_locks(lock,"before upgrading lock",0);
1144
1373
  /* TODO:  Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1152
1381
      if (data->lock->get_status)
1153
1382
        (*data->lock->get_status)(data->status_param, 0);
1154
1383
      pthread_mutex_unlock(&lock->mutex);
1155
 
      return(0);
 
1384
      DBUG_RETURN(0);
1156
1385
    }
1157
1386
 
1158
1387
    if (((*data->prev)=data->next))             /* remove from lock-list */
1172
1401
  {
1173
1402
    check_locks(lock,"waiting for lock",0);
1174
1403
  }
1175
 
  return(wait_for_lock(&lock->write_wait,data,1));
 
1404
  DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1176
1405
}
1177
1406
 
1178
1407
 
1179
1408
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1180
1409
 
1181
 
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
 
1410
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1182
1411
{
1183
1412
  THR_LOCK *lock=data->lock;
 
1413
  DBUG_ENTER("thr_reschedule_write_lock");
1184
1414
 
1185
1415
  pthread_mutex_lock(&lock->mutex);
1186
1416
  if (!lock->read_wait.data)                    /* No waiting read locks */
1187
1417
  {
1188
1418
    pthread_mutex_unlock(&lock->mutex);
1189
 
    return(0);
 
1419
    DBUG_RETURN(0);
1190
1420
  }
1191
1421
 
1192
1422
  data->type=TL_WRITE_DELAYED;
1207
1437
  free_all_read_locks(lock,0);
1208
1438
 
1209
1439
  pthread_mutex_unlock(&lock->mutex);
1210
 
  return(thr_upgrade_write_delay_lock(data));
 
1440
  DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1211
1441
}
1212
1442
 
1213
1443
 
1214
1444
#include <my_sys.h>
1215
1445
 
 
1446
static void thr_print_lock(const char* name,struct st_lock_list *list)
 
1447
{
 
1448
  THR_LOCK_DATA *data,**prev;
 
1449
  uint count=0;
 
1450
 
 
1451
  if (list->data)
 
1452
  {
 
1453
    printf("%-10s: ",name);
 
1454
    prev= &list->data;
 
1455
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
 
1456
    {
 
1457
      printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
 
1458
             (int) data->type);
 
1459
      if (data->prev != prev)
 
1460
        printf("\nWarning: prev didn't point at previous lock\n");
 
1461
      prev= &data->next;
 
1462
    }
 
1463
    puts("");
 
1464
    if (prev != list->last)
 
1465
      printf("Warning: last didn't point at last lock\n");
 
1466
  }
 
1467
}
 
1468
 
 
1469
void thr_print_locks(void)
 
1470
{
 
1471
  LIST *list;
 
1472
  uint count=0;
 
1473
 
 
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))
 
1478
  {
 
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)
 
1486
      printf(" write");
 
1487
    if (lock->write_wait.data)
 
1488
      printf(" write_wait");
 
1489
    if (lock->read.data)
 
1490
      printf(" read");
 
1491
    if (lock->read_wait.data)
 
1492
      printf(" read_wait");
 
1493
    puts("");
 
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));
 
1499
    puts("");
 
1500
  }
 
1501
  fflush(stdout);
 
1502
  pthread_mutex_unlock(&THR_LOCK_lock);
 
1503
}
 
1504
 
 
1505
#endif /* THREAD */
 
1506
 
1216
1507
/*****************************************************************************
1217
1508
** Test of thread locks
1218
1509
****************************************************************************/
1219
1510
 
1220
1511
#ifdef MAIN
1221
1512
 
 
1513
#ifdef THREAD
 
1514
 
1222
1515
struct st_test {
1223
 
  uint32_t lock_nr;
 
1516
  uint lock_nr;
1224
1517
  enum thr_lock_type lock_type;
1225
1518
};
1226
1519
 
1269
1562
 
1270
1563
static pthread_cond_t COND_thread_count;
1271
1564
static pthread_mutex_t LOCK_thread_count;
1272
 
static uint32_t thread_count;
1273
 
static uint32_t sum=0;
 
1565
static uint thread_count;
 
1566
static ulong sum=0;
1274
1567
 
1275
1568
#define MAX_LOCK_COUNT 8
1276
1569
 
1290
1583
{
1291
1584
}
1292
1585
 
1293
 
static bool test_check_status(void* param __attribute__((unused)))
 
1586
static my_bool test_check_status(void* param __attribute__((unused)))
1294
1587
{
1295
1588
  return 0;
1296
1589
}
1329
1622
        sleep(2);
1330
1623
      else
1331
1624
      {
1332
 
        uint32_t k;
1333
 
        for (k=0 ; k < (uint32_t) (tmp-2)*100000L ; k++)
 
1625
        ulong k;
 
1626
        for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
1334
1627
          sum+=k;
1335
1628
      }
1336
1629
    }
1342
1635
  thr_print_locks();
1343
1636
  pthread_mutex_lock(&LOCK_thread_count);
1344
1637
  thread_count--;
1345
 
  pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
 
1638
  VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1346
1639
  pthread_mutex_unlock(&LOCK_thread_count);
1347
 
  free((unsigned char*) arg);
 
1640
  free((uchar*) arg);
1348
1641
  return 0;
1349
1642
}
1350
1643
 
1355
1648
  pthread_attr_t thr_attr;
1356
1649
  int i,*param,error;
1357
1650
  MY_INIT(argv[0]);
 
1651
  if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
 
1652
    DBUG_PUSH(argv[1]+2);
1358
1653
 
1359
1654
  printf("Main thread: %s\n",my_thread_name());
1360
1655
 
1401
1696
  }
1402
1697
#endif
1403
1698
#ifdef HAVE_THR_SETCONCURRENCY
1404
 
  thr_setconcurrency(2);
 
1699
  VOID(thr_setconcurrency(2));
1405
1700
#endif
1406
1701
  for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1407
1702
  {
1446
1741
  return 0;
1447
1742
}
1448
1743
 
 
1744
#else /* THREAD */
 
1745
 
 
1746
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
 
1747
{
 
1748
  printf("thr_lock disabled because we are not using threads\n");
 
1749
  exit(1);
 
1750
}
 
1751
 
 
1752
#endif /* THREAD */
1449
1753
#endif /* MAIN */