~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_lock.c

  • Committer: Monty Taylor
  • Date: 2008-07-02 14:35:48 UTC
  • mto: This revision was merged to the branch mainline in revision 51.
  • Revision ID: monty@inaugust.com-20080702143548-onj30ry0sugr01uw
Removed all references to THREAD.

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
 
75
79
#include "thr_lock.h"
76
 
#include <mystrings/m_string.h>
 
80
#include <m_string.h>
77
81
#include <errno.h>
78
82
 
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;
 
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;
96
87
 
111
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
112
103
*/
113
104
 
114
 
bool init_thr_lock()
 
105
my_bool init_thr_lock()
115
106
{
116
107
  thr_lock_inited=1;
117
108
  return 0;
118
109
}
119
110
 
120
 
static inline bool
 
111
static inline my_bool
121
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
122
113
{
123
114
  return rhs == lhs;
124
115
}
125
116
 
 
117
 
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;
129
121
 
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)
132
124
{
133
125
  THR_LOCK_DATA *data,**prev;
134
 
  uint32_t count=0;
 
126
  uint count=0;
135
127
  THR_LOCK_OWNER *first_owner;
136
128
 
137
129
  prev= &list->data;
188
180
 
189
181
 
190
182
static void check_locks(THR_LOCK *lock, const char *where,
191
 
                        bool allow_no_locks)
 
183
                        my_bool allow_no_locks)
192
184
{
193
 
  uint32_t old_found_errors=found_errors;
 
185
  uint old_found_errors=found_errors;
 
186
  DBUG_ENTER("check_locks");
194
187
 
195
188
  if (found_errors < MAX_FOUND_ERRORS)
196
189
  {
202
195
 
203
196
    if (found_errors < MAX_FOUND_ERRORS)
204
197
    {
205
 
      uint32_t count=0;
 
198
      uint count=0;
206
199
      THR_LOCK_DATA *data;
207
200
      for (data=lock->read.data ; data ; data=data->next)
208
201
      {
209
202
        if ((int) data->type == (int) TL_READ_NO_INSERT)
210
203
          count++;
211
204
        /* Protect against infinite loop. */
212
 
        assert(count <= lock->read_no_write_count);
 
205
        DBUG_ASSERT(count <= lock->read_no_write_count);
213
206
      }
214
207
      if (count != lock->read_no_write_count)
215
208
      {
282
275
            fprintf(stderr,
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));
 
280
 
285
281
          }
286
282
        }
287
283
        if (lock->read_wait.data)
299
295
        }
300
296
      }
301
297
    }
 
298
    if (found_errors != old_found_errors)
 
299
    {
 
300
      DBUG_PRINT("error",("Found wrong lock"));
 
301
    }
302
302
  }
303
 
  return;
 
303
  DBUG_VOID_RETURN;
304
304
}
305
305
 
306
306
#else /* EXTRA_DEBUG */
312
312
 
313
313
void thr_lock_init(THR_LOCK *lock)
314
314
{
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);
326
 
  return;
 
327
  DBUG_VOID_RETURN;
327
328
}
328
329
 
329
330
 
330
331
void thr_lock_delete(THR_LOCK *lock)
331
332
{
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);
336
 
  return;
 
338
  DBUG_VOID_RETURN;
337
339
}
338
340
 
339
341
 
357
359
}
358
360
 
359
361
 
360
 
static inline bool
 
362
static inline my_bool
361
363
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
362
364
{
363
365
  for ( ; data ; data=data->next)
368
370
  return 0;
369
371
}
370
372
 
371
 
static inline bool have_specific_lock(THR_LOCK_DATA *data,
 
373
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
372
374
                                         enum thr_lock_type type)
373
375
{
374
376
  for ( ; data ; data=data->next)
385
387
 
386
388
static enum enum_thr_lock_result
387
389
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
388
 
              bool in_wait_list)
 
390
              my_bool in_wait_list)
389
391
{
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");
395
398
 
396
399
  if (!in_wait_list)
397
400
  {
430
433
    */
431
434
    if (data->cond == 0)
432
435
    {
 
436
      DBUG_PRINT("thr_lock", ("lock granted/aborted"));
433
437
      break;
434
438
    }
435
439
    if (rc == ETIMEDOUT || rc == ETIME)
436
440
    {
437
441
      /* purecov: begin inspected */
 
442
      DBUG_PRINT("thr_lock", ("lock timed out"));
438
443
      result= THR_LOCK_WAIT_TIMEOUT;
439
444
      break;
440
445
      /* purecov: end */
441
446
    }
442
447
  }
 
448
  DBUG_PRINT("thr_lock", ("aborted: %d  in_wait_list: %d",
 
449
                          thread_var->abort, in_wait_list));
 
450
 
443
451
  if (data->cond || data->type == TL_UNLOCK)
444
452
  {
445
453
    if (data->cond)                             /* aborted or timed out */
454
462
    }
455
463
    else
456
464
    {
 
465
      DBUG_PRINT("thr_lock", ("lock aborted"));
457
466
      check_locks(data->lock, "aborted wait_for_lock", 0);
458
467
    }
459
468
  }
471
480
  thread_var->current_mutex= 0;
472
481
  thread_var->current_cond=  0;
473
482
  pthread_mutex_unlock(&thread_var->mutex);
474
 
  return(result);
 
483
  DBUG_RETURN(result);
475
484
}
476
485
 
477
486
 
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");
486
496
 
487
497
  data->next=0;
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
506
519
      */
507
520
 
 
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
618
633
        */
 
634
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
 
635
                            (ulong) lock->write_wait.data,
 
636
                            lock->write.data->type));
619
637
 
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);
627
645
        goto end;
628
646
      }
 
647
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
 
648
                         lock->write.data->owner->info->thread_id));
629
649
    }
630
650
    else
631
651
    {
 
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)
636
658
        {
637
659
          concurrent_insert= 1;
658
680
          goto end;
659
681
        }
660
682
      }
 
683
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
 
684
                         lock->read.data->owner->info->thread_id, data->type));
661
685
    }
662
686
    wait_queue= &lock->write_wait;
663
687
  }
670
694
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
671
695
  if (lock_owner && lock_owner->owner->info == owner->info)
672
696
  {
 
697
    DBUG_PRINT("lock",("deadlock"));
673
698
    result= THR_LOCK_DEADLOCK;
674
699
    goto end;
675
700
  }
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));
678
703
end:
679
704
  pthread_mutex_unlock(&lock->mutex);
680
 
  return(result);
 
705
  DBUG_RETURN(result);
681
706
}
682
707
 
683
708
 
684
709
static inline void free_all_read_locks(THR_LOCK *lock,
685
 
                                       bool using_concurrent_insert)
 
710
                                       my_bool using_concurrent_insert)
686
711
{
687
712
  THR_LOCK_DATA *data=lock->read_wait.data;
688
713
 
718
743
      }
719
744
      lock->read_no_write_count++;
720
745
    }      
 
746
    /* purecov: begin inspected */
 
747
    DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
 
748
                       data->owner->info->thread_id));
 
749
    /* purecov: end */
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)
733
762
{
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);
738
770
 
766
798
  check_locks(lock,"after releasing lock",1);
767
799
  wake_up_waiters(lock);
768
800
  pthread_mutex_unlock(&lock->mutex);
769
 
  return;
 
801
  DBUG_VOID_RETURN;
770
802
}
771
803
 
772
804
 
783
815
  THR_LOCK_DATA *data;
784
816
  enum thr_lock_type lock_type;
785
817
 
 
818
  DBUG_ENTER("wake_up_waiters");
 
819
 
786
820
  if (!lock->write.data)                        /* If no active write locks */
787
821
  {
788
822
    data=lock->write_wait.data;
799
833
          lock->write_lock_count=0;
800
834
          if (lock->read_wait.data)
801
835
          {
 
836
            DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
802
837
            free_all_read_locks(lock,0);
803
838
            goto end;
804
839
          }
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));
 
857
          /* purecov: end */
819
858
          {
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 */
823
862
          }
824
863
          if (data->type != TL_WRITE_ALLOW_WRITE ||
825
864
              !lock->write_wait.data ||
836
875
                            data &&
837
876
                            (data->type == TL_WRITE_CONCURRENT_INSERT ||
838
877
                             data->type == TL_WRITE_ALLOW_WRITE));
 
878
      else
 
879
      {
 
880
        DBUG_PRINT("lock",("No waiting read locks to free"));
 
881
      }
839
882
    }
840
883
    else if (data &&
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);
880
923
  }
881
924
end:
882
925
  check_locks(lock, "after waking up waiters", 0);
883
 
  return;
 
926
  DBUG_VOID_RETURN;
884
927
}
885
928
 
886
929
 
891
934
*/
892
935
 
893
936
 
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))
895
938
 
896
 
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
 
939
static void sort_locks(THR_LOCK_DATA **data,uint count)
897
940
{
898
941
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
899
942
 
915
958
 
916
959
 
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)
919
962
{
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));
921
966
  if (count > 1)
922
967
    sort_locks(data,count);
923
968
  /* lock everything */
927
972
    if (result != THR_LOCK_SUCCESS)
928
973
    {                                           /* Aborted */
929
974
      thr_multi_unlock(data,(uint) (pos-data));
930
 
      return(result);
 
975
      DBUG_RETURN(result);
931
976
    }
932
977
#ifdef MAIN
933
978
    printf("Thread: %s  Got lock: 0x%lx  type: %d\n",my_thread_name(),
981
1026
    } while (pos != data);
982
1027
  }
983
1028
#endif
984
 
  return(THR_LOCK_SUCCESS);
 
1029
  DBUG_RETURN(THR_LOCK_SUCCESS);
985
1030
}
986
1031
 
987
1032
  /* free all locks */
988
1033
 
989
 
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
 
1034
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
990
1035
{
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));
992
1039
 
993
1040
  for (pos=data,end=data+count; pos < end ; pos++)
994
1041
  {
999
1046
#endif
1000
1047
    if ((*pos)->type != TL_UNLOCK)
1001
1048
      thr_unlock(*pos);
 
1049
    else
 
1050
    {
 
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));
 
1054
    }
1002
1055
  }
1003
 
  return;
 
1056
  DBUG_VOID_RETURN;
1004
1057
}
1005
1058
 
1006
1059
/*
1008
1061
  TL_WRITE_ONLY to abort any new accesses to the lock
1009
1062
*/
1010
1063
 
1011
 
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
 
1064
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
1012
1065
{
1013
1066
  THR_LOCK_DATA *data;
 
1067
  DBUG_ENTER("thr_abort_locks");
1014
1068
  pthread_mutex_lock(&lock->mutex);
1015
1069
 
1016
1070
  for (data=lock->read_wait.data; data ; data=data->next)
1032
1086
  if (upgrade_lock && lock->write.data)
1033
1087
    lock->write.data->type=TL_WRITE_ONLY;
1034
1088
  pthread_mutex_unlock(&lock->mutex);
1035
 
  return;
 
1089
  DBUG_VOID_RETURN;
1036
1090
}
1037
1091
 
1038
1092
 
1042
1096
  This is used to abort all locks for a specific thread
1043
1097
*/
1044
1098
 
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)
1046
1100
{
1047
1101
  THR_LOCK_DATA *data;
1048
 
  bool found= false;
 
1102
  my_bool found= FALSE;
 
1103
  DBUG_ENTER("thr_abort_locks_for_thread");
1049
1104
 
1050
1105
  pthread_mutex_lock(&lock->mutex);
1051
1106
  for (data= lock->read_wait.data; data ; data= data->next)
1052
1107
  {
1053
1108
    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
1054
1109
    {
 
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. */
1057
 
      found= true;
 
1113
      found= TRUE;
1058
1114
      pthread_cond_signal(data->cond);
1059
1115
      data->cond= 0;                            /* Removed from list */
1060
1116
 
1068
1124
  {
1069
1125
    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1070
1126
    {
 
1127
      DBUG_PRINT("info",("Aborting write-wait lock"));
1071
1128
      data->type= TL_UNLOCK;
1072
 
      found= true;
 
1129
      found= TRUE;
1073
1130
      pthread_cond_signal(data->cond);
1074
1131
      data->cond= 0;
1075
1132
 
1081
1138
  }
1082
1139
  wake_up_waiters(lock);
1083
1140
  pthread_mutex_unlock(&lock->mutex);
1084
 
  return(found);
 
1141
  DBUG_RETURN(found);
1085
1142
}
1086
1143
 
1087
1144
 
1119
1176
                              enum thr_lock_type new_lock_type)
1120
1177
{
1121
1178
  THR_LOCK *lock=in_data->lock;
 
1179
#ifndef DBUG_OFF
 
1180
  enum thr_lock_type old_lock_type= in_data->type;
 
1181
#endif
 
1182
#ifdef TO_BE_REMOVED
 
1183
  THR_LOCK_DATA *data, *next;
 
1184
  bool start_writers= FALSE;
 
1185
  bool start_readers= FALSE;
 
1186
#endif
 
1187
  DBUG_ENTER("thr_downgrade_write_only_lock");
1122
1188
 
1123
1189
  pthread_mutex_lock(&lock->mutex);
 
1190
  DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
 
1191
  DBUG_ASSERT(old_lock_type > new_lock_type);
1124
1192
  in_data->type= new_lock_type;
1125
1193
  check_locks(lock,"after downgrading lock",0);
1126
1194
 
 
1195
#if TO_BE_REMOVED
 
1196
  switch (old_lock_type)
 
1197
  {
 
1198
    case TL_WRITE_ONLY:
 
1199
    case TL_WRITE:
 
1200
    case TL_WRITE_LOW_PRIORITY:
 
1201
    /*
 
1202
      Previous lock was exclusive we are now ready to start up most waiting
 
1203
      threads.
 
1204
    */
 
1205
      switch (new_lock_type)
 
1206
      {
 
1207
        case TL_WRITE_ALLOW_READ:
 
1208
        /* Still cannot start WRITE operations. Can only start readers.  */
 
1209
          start_readers= TRUE;
 
1210
          break;
 
1211
        case TL_WRITE:
 
1212
        case TL_WRITE_LOW_PRIORITY:
 
1213
        /*
 
1214
           Still cannot start anything, but new requests are no longer
 
1215
           aborted.
 
1216
        */
 
1217
          break;
 
1218
        case TL_WRITE_ALLOW_WRITE:
 
1219
        /*
 
1220
          We can start both writers and readers.
 
1221
        */
 
1222
          start_writers= TRUE;
 
1223
          start_readers= TRUE;
 
1224
          break;
 
1225
        case TL_WRITE_CONCURRENT_INSERT:
 
1226
        case TL_WRITE_DELAYED:
 
1227
        /*
 
1228
          This routine is not designed for those. Lock will be downgraded
 
1229
          but no start of waiters will occur. This is not the optimal but
 
1230
          should be a correct behaviour.
 
1231
        */
 
1232
          break;
 
1233
        default:
 
1234
          DBUG_ASSERT(0);
 
1235
      }
 
1236
      break;
 
1237
    case TL_WRITE_DELAYED:
 
1238
    case TL_WRITE_CONCURRENT_INSERT:
 
1239
    /*
 
1240
      This routine is not designed for those. Lock will be downgraded
 
1241
      but no start of waiters will occur. This is not the optimal but
 
1242
      should be a correct behaviour.
 
1243
    */
 
1244
      break;
 
1245
    case TL_WRITE_ALLOW_READ:
 
1246
      DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
 
1247
      /*
 
1248
        Previously writers were not allowed to start, now it is ok to
 
1249
        start them again. Readers are already allowed so no reason to
 
1250
        handle them.
 
1251
      */
 
1252
      start_writers= TRUE;
 
1253
      break;
 
1254
    default:
 
1255
      DBUG_ASSERT(0);
 
1256
      break;
 
1257
  }
 
1258
  if (start_writers)
 
1259
  {
 
1260
    /*
 
1261
      At this time the only active writer can be ourselves. Thus we need
 
1262
      not worry about that there are other concurrent write operations
 
1263
      active on the table. Thus we only need to worry about starting
 
1264
      waiting operations.
 
1265
      We also only come here with TL_WRITE_ALLOW_WRITE as the new
 
1266
      lock type, thus we can start other writers also of the same type.
 
1267
      If we find a lock at exclusive level >= TL_WRITE_LOW_PRIORITY we
 
1268
      don't start any more operations that would be mean those operations
 
1269
      will have to wait for things started afterwards.
 
1270
    */
 
1271
    DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
 
1272
    for (data=lock->write_wait.data; data ; data= next)
 
1273
    {
 
1274
      /*
 
1275
        All WRITE requests compatible with new lock type are also
 
1276
        started
 
1277
      */
 
1278
      next= data->next;
 
1279
      if (start_writers && data->type == new_lock_type)
 
1280
      {
 
1281
        pthread_cond_t *cond= data->cond;
 
1282
        /*
 
1283
          It is ok to start this waiter.
 
1284
          Move from being first in wait queue to be last in write queue.
 
1285
        */
 
1286
        if (((*data->prev)= data->next))
 
1287
          data->next->prev= data->prev;
 
1288
        else
 
1289
          lock->write_wait.last= data->prev;
 
1290
        data->prev= lock->write.last;
 
1291
        lock->write.last= &data->next;
 
1292
        data->next= 0;
 
1293
        check_locks(lock, "Started write lock after downgrade",0);
 
1294
        data->cond= 0;
 
1295
        pthread_cond_signal(cond);
 
1296
      }
 
1297
      else
 
1298
      {
 
1299
        /*
 
1300
          We found an incompatible lock, we won't start any more write
 
1301
          requests to avoid letting writers pass other writers in the
 
1302
          queue.
 
1303
        */
 
1304
        start_writers= FALSE;
 
1305
        if (data->type >= TL_WRITE_LOW_PRIORITY)
 
1306
        {
 
1307
          /*
 
1308
            We have an exclusive writer in the queue so we won't start
 
1309
            readers either.
 
1310
          */
 
1311
          start_readers= FALSE;
 
1312
        }
 
1313
      }
 
1314
    }
 
1315
  }
 
1316
  if (start_readers)
 
1317
  {
 
1318
    DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE ||
 
1319
                new_lock_type == TL_WRITE_ALLOW_READ);
 
1320
    /*
 
1321
      When we come here we know that the write locks are
 
1322
      TL_WRITE_ALLOW_WRITE or TL_WRITE_ALLOW_READ. This means that reads
 
1323
      are ok
 
1324
    */
 
1325
    for (data=lock->read_wait.data; data ; data=next)
 
1326
    {
 
1327
      next= data->next;
 
1328
      /*
 
1329
        All reads are ok to start now except TL_READ_NO_INSERT when
 
1330
        write lock is TL_WRITE_ALLOW_READ.
 
1331
      */
 
1332
      if (new_lock_type != TL_WRITE_ALLOW_READ ||
 
1333
          data->type != TL_READ_NO_INSERT)
 
1334
      {
 
1335
        pthread_cond_t *cond= data->cond;
 
1336
        if (((*data->prev)= data->next))
 
1337
          data->next->prev= data->prev;
 
1338
        else
 
1339
          lock->read_wait.last= data->prev;
 
1340
        data->prev= lock->read.last;
 
1341
        lock->read.last= &data->next;
 
1342
        data->next= 0;
 
1343
 
 
1344
        if (data->type == TL_READ_NO_INSERT)
 
1345
          lock->read_no_write_count++;
 
1346
        check_locks(lock, "Started read lock after downgrade",0);
 
1347
        data->cond= 0;
 
1348
        pthread_cond_signal(cond);
 
1349
      }
 
1350
    }
 
1351
  }
 
1352
  check_locks(lock,"after starting waiters after downgrading lock",0);
 
1353
#endif
1127
1354
  pthread_mutex_unlock(&lock->mutex);
1128
 
  return;
 
1355
  DBUG_VOID_RETURN;
1129
1356
}
1130
1357
 
1131
1358
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1132
1359
 
1133
 
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
 
1360
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1134
1361
{
1135
1362
  THR_LOCK *lock=data->lock;
 
1363
  DBUG_ENTER("thr_upgrade_write_delay_lock");
1136
1364
 
1137
1365
  pthread_mutex_lock(&lock->mutex);
1138
1366
  if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1139
1367
  {
1140
1368
    pthread_mutex_unlock(&lock->mutex);
1141
 
    return(data->type == TL_UNLOCK);    /* Test if Aborted */
 
1369
    DBUG_RETURN(data->type == TL_UNLOCK);       /* Test if Aborted */
1142
1370
  }
1143
1371
  check_locks(lock,"before upgrading lock",0);
1144
1372
  /* TODO:  Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1152
1380
      if (data->lock->get_status)
1153
1381
        (*data->lock->get_status)(data->status_param, 0);
1154
1382
      pthread_mutex_unlock(&lock->mutex);
1155
 
      return(0);
 
1383
      DBUG_RETURN(0);
1156
1384
    }
1157
1385
 
1158
1386
    if (((*data->prev)=data->next))             /* remove from lock-list */
1172
1400
  {
1173
1401
    check_locks(lock,"waiting for lock",0);
1174
1402
  }
1175
 
  return(wait_for_lock(&lock->write_wait,data,1));
 
1403
  DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1176
1404
}
1177
1405
 
1178
1406
 
1179
1407
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1180
1408
 
1181
 
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
 
1409
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1182
1410
{
1183
1411
  THR_LOCK *lock=data->lock;
 
1412
  DBUG_ENTER("thr_reschedule_write_lock");
1184
1413
 
1185
1414
  pthread_mutex_lock(&lock->mutex);
1186
1415
  if (!lock->read_wait.data)                    /* No waiting read locks */
1187
1416
  {
1188
1417
    pthread_mutex_unlock(&lock->mutex);
1189
 
    return(0);
 
1418
    DBUG_RETURN(0);
1190
1419
  }
1191
1420
 
1192
1421
  data->type=TL_WRITE_DELAYED;
1207
1436
  free_all_read_locks(lock,0);
1208
1437
 
1209
1438
  pthread_mutex_unlock(&lock->mutex);
1210
 
  return(thr_upgrade_write_delay_lock(data));
 
1439
  DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1211
1440
}
1212
1441
 
1213
1442
 
1214
1443
#include <my_sys.h>
1215
1444
 
 
1445
static void thr_print_lock(const char* name,struct st_lock_list *list)
 
1446
{
 
1447
  THR_LOCK_DATA *data,**prev;
 
1448
  uint count=0;
 
1449
 
 
1450
  if (list->data)
 
1451
  {
 
1452
    printf("%-10s: ",name);
 
1453
    prev= &list->data;
 
1454
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
 
1455
    {
 
1456
      printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
 
1457
             (int) data->type);
 
1458
      if (data->prev != prev)
 
1459
        printf("\nWarning: prev didn't point at previous lock\n");
 
1460
      prev= &data->next;
 
1461
    }
 
1462
    puts("");
 
1463
    if (prev != list->last)
 
1464
      printf("Warning: last didn't point at last lock\n");
 
1465
  }
 
1466
}
 
1467
 
 
1468
void thr_print_locks(void)
 
1469
{
 
1470
  LIST *list;
 
1471
  uint count=0;
 
1472
 
 
1473
  pthread_mutex_lock(&THR_LOCK_lock);
 
1474
  puts("Current locks:");
 
1475
  for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
 
1476
       list= list_rest(list))
 
1477
  {
 
1478
    THR_LOCK *lock=(THR_LOCK*) list->data;
 
1479
    VOID(pthread_mutex_lock(&lock->mutex));
 
1480
    printf("lock: 0x%lx:",(ulong) lock);
 
1481
    if ((lock->write_wait.data || lock->read_wait.data) &&
 
1482
        (! lock->read.data && ! lock->write.data))
 
1483
      printf(" WARNING: ");
 
1484
    if (lock->write.data)
 
1485
      printf(" write");
 
1486
    if (lock->write_wait.data)
 
1487
      printf(" write_wait");
 
1488
    if (lock->read.data)
 
1489
      printf(" read");
 
1490
    if (lock->read_wait.data)
 
1491
      printf(" read_wait");
 
1492
    puts("");
 
1493
    thr_print_lock("write",&lock->write);
 
1494
    thr_print_lock("write_wait",&lock->write_wait);
 
1495
    thr_print_lock("read",&lock->read);
 
1496
    thr_print_lock("read_wait",&lock->read_wait);
 
1497
    VOID(pthread_mutex_unlock(&lock->mutex));
 
1498
    puts("");
 
1499
  }
 
1500
  fflush(stdout);
 
1501
  pthread_mutex_unlock(&THR_LOCK_lock);
 
1502
}
 
1503
 
1216
1504
/*****************************************************************************
1217
1505
** Test of thread locks
1218
1506
****************************************************************************/
1220
1508
#ifdef MAIN
1221
1509
 
1222
1510
struct st_test {
1223
 
  uint32_t lock_nr;
 
1511
  uint lock_nr;
1224
1512
  enum thr_lock_type lock_type;
1225
1513
};
1226
1514
 
1269
1557
 
1270
1558
static pthread_cond_t COND_thread_count;
1271
1559
static pthread_mutex_t LOCK_thread_count;
1272
 
static uint32_t thread_count;
1273
 
static uint32_t sum=0;
 
1560
static uint thread_count;
 
1561
static ulong sum=0;
1274
1562
 
1275
1563
#define MAX_LOCK_COUNT 8
1276
1564
 
1290
1578
{
1291
1579
}
1292
1580
 
1293
 
static bool test_check_status(void* param __attribute__((unused)))
 
1581
static my_bool test_check_status(void* param __attribute__((unused)))
1294
1582
{
1295
1583
  return 0;
1296
1584
}
1329
1617
        sleep(2);
1330
1618
      else
1331
1619
      {
1332
 
        uint32_t k;
1333
 
        for (k=0 ; k < (uint32_t) (tmp-2)*100000L ; k++)
 
1620
        ulong k;
 
1621
        for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
1334
1622
          sum+=k;
1335
1623
      }
1336
1624
    }
1342
1630
  thr_print_locks();
1343
1631
  pthread_mutex_lock(&LOCK_thread_count);
1344
1632
  thread_count--;
1345
 
  pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
 
1633
  VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1346
1634
  pthread_mutex_unlock(&LOCK_thread_count);
1347
 
  free((unsigned char*) arg);
 
1635
  free((uchar*) arg);
1348
1636
  return 0;
1349
1637
}
1350
1638
 
1355
1643
  pthread_attr_t thr_attr;
1356
1644
  int i,*param,error;
1357
1645
  MY_INIT(argv[0]);
 
1646
  if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
 
1647
    DBUG_PUSH(argv[1]+2);
1358
1648
 
1359
1649
  printf("Main thread: %s\n",my_thread_name());
1360
1650
 
1401
1691
  }
1402
1692
#endif
1403
1693
#ifdef HAVE_THR_SETCONCURRENCY
1404
 
  thr_setconcurrency(2);
 
1694
  VOID(thr_setconcurrency(2));
1405
1695
#endif
1406
1696
  for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1407
1697
  {