~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_lock.c

  • Committer: Brian Aker
  • Date: 2008-07-04 17:39:41 UTC
  • mfrom: (53.2.3 codestyle2)
  • Revision ID: brian@tangent.org-20080704173941-z0s9jhsl26i3ax1w
Merge from incomming patch from Monty covering warnings

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;
94
 
uint64_t table_lock_wait_timeout;
 
83
my_bool thr_lock_inited=0;
 
84
ulong locks_immediate = 0L, locks_waited = 0L;
 
85
ulong table_lock_wait_timeout;
95
86
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
96
87
 
 
88
/* The following constants are only for debug output */
 
89
#define MAX_THREADS 100
 
90
#define MAX_LOCKS   100
 
91
 
97
92
 
98
93
LIST *thr_lock_thread_list;                     /* List of threads in use */
99
 
uint64_t max_write_lock_count= ~(uint64_t) 0L;
 
94
ulong max_write_lock_count= ~(ulong) 0L;
100
95
 
101
96
static inline pthread_cond_t *get_cond(void)
102
97
{
107
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
108
103
*/
109
104
 
110
 
bool init_thr_lock()
 
105
my_bool init_thr_lock()
111
106
{
112
107
  thr_lock_inited=1;
113
108
  return 0;
114
109
}
115
110
 
116
 
static inline bool
 
111
static inline my_bool
117
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
118
113
{
119
114
  return rhs == lhs;
120
115
}
121
116
 
122
117
 
 
118
#ifdef EXTRA_DEBUG
 
119
#define MAX_FOUND_ERRORS        10              /* Report 10 first errors */
 
120
static uint found_errors=0;
 
121
 
 
122
static int check_lock(struct st_lock_list *list, const char* lock_type,
 
123
                      const char *where, my_bool same_owner, my_bool no_cond)
 
124
{
 
125
  THR_LOCK_DATA *data,**prev;
 
126
  uint count=0;
 
127
  THR_LOCK_OWNER *first_owner;
 
128
 
 
129
  prev= &list->data;
 
130
  if (list->data)
 
131
  {
 
132
    enum thr_lock_type last_lock_type=list->data->type;
 
133
 
 
134
    if (same_owner && list->data)
 
135
      first_owner= list->data->owner;
 
136
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
 
137
    {
 
138
      if (data->type != last_lock_type)
 
139
        last_lock_type=TL_IGNORE;
 
140
      if (data->prev != prev)
 
141
      {
 
142
        fprintf(stderr,
 
143
                "Warning: prev link %d didn't point at previous lock at %s: %s\n",
 
144
                count, lock_type, where);
 
145
        return 1;
 
146
      }
 
147
      if (same_owner &&
 
148
          !thr_lock_owner_equal(data->owner, first_owner) &&
 
149
          last_lock_type != TL_WRITE_ALLOW_WRITE)
 
150
      {
 
151
        fprintf(stderr,
 
152
                "Warning: Found locks from different threads in %s: %s\n",
 
153
                lock_type,where);
 
154
        return 1;
 
155
      }
 
156
      if (no_cond && data->cond)
 
157
      {
 
158
        fprintf(stderr,
 
159
                "Warning: Found active lock with not reset cond %s: %s\n",
 
160
                lock_type,where);
 
161
        return 1;
 
162
      }
 
163
      prev= &data->next;
 
164
    }
 
165
    if (data)
 
166
    {
 
167
      fprintf(stderr,"Warning: found too many locks at %s: %s\n",
 
168
              lock_type,where);
 
169
      return 1;
 
170
    }
 
171
  }
 
172
  if (prev != list->last)
 
173
  {
 
174
    fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
 
175
            lock_type, where);
 
176
    return 1;
 
177
  }
 
178
  return 0;
 
179
}
 
180
 
 
181
 
 
182
static void check_locks(THR_LOCK *lock, const char *where,
 
183
                        my_bool allow_no_locks)
 
184
{
 
185
  uint old_found_errors=found_errors;
 
186
  DBUG_ENTER("check_locks");
 
187
 
 
188
  if (found_errors < MAX_FOUND_ERRORS)
 
189
  {
 
190
    if (check_lock(&lock->write,"write",where,1,1) |
 
191
        check_lock(&lock->write_wait,"write_wait",where,0,0) |
 
192
        check_lock(&lock->read,"read",where,0,1) |
 
193
        check_lock(&lock->read_wait,"read_wait",where,0,0))
 
194
      found_errors++;
 
195
 
 
196
    if (found_errors < MAX_FOUND_ERRORS)
 
197
    {
 
198
      uint count=0;
 
199
      THR_LOCK_DATA *data;
 
200
      for (data=lock->read.data ; data ; data=data->next)
 
201
      {
 
202
        if ((int) data->type == (int) TL_READ_NO_INSERT)
 
203
          count++;
 
204
        /* Protect against infinite loop. */
 
205
        DBUG_ASSERT(count <= lock->read_no_write_count);
 
206
      }
 
207
      if (count != lock->read_no_write_count)
 
208
      {
 
209
        found_errors++;
 
210
        fprintf(stderr,
 
211
                "Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
 
212
      }      
 
213
 
 
214
      if (!lock->write.data)
 
215
      {
 
216
        if (!allow_no_locks && !lock->read.data &&
 
217
            (lock->write_wait.data || lock->read_wait.data))
 
218
        {
 
219
          found_errors++;
 
220
          fprintf(stderr,
 
221
                  "Warning at '%s': No locks in use but locks are in wait queue\n",
 
222
                  where);
 
223
        }
 
224
        if (!lock->write_wait.data)
 
225
        {
 
226
          if (!allow_no_locks && lock->read_wait.data)
 
227
          {
 
228
            found_errors++;
 
229
            fprintf(stderr,
 
230
                    "Warning at '%s': No write locks and waiting read locks\n",
 
231
                    where);
 
232
          }
 
233
        }
 
234
        else
 
235
        {
 
236
          if (!allow_no_locks &&
 
237
              (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
 
238
                 lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
 
239
                !lock->read_no_write_count) ||
 
240
               lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
 
241
               (lock->write_wait.data->type == TL_WRITE_DELAYED &&
 
242
                !lock->read.data)))
 
243
          {
 
244
            found_errors++;
 
245
            fprintf(stderr,
 
246
                    "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
 
247
          }
 
248
        }             
 
249
      }
 
250
      else
 
251
      {                                         /* Have write lock */
 
252
        if (lock->write_wait.data)
 
253
        {
 
254
          if (!allow_no_locks && 
 
255
              lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
 
256
              lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
 
257
          {
 
258
            found_errors++;
 
259
            fprintf(stderr,
 
260
                    "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
 
261
                    where);
 
262
          }
 
263
        }
 
264
        if (lock->read.data)
 
265
        {
 
266
          if (!thr_lock_owner_equal(lock->write.data->owner,
 
267
                                    lock->read.data->owner) &&
 
268
              ((lock->write.data->type > TL_WRITE_DELAYED &&
 
269
                lock->write.data->type != TL_WRITE_ONLY) ||
 
270
               ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
 
271
                 lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
 
272
                lock->read_no_write_count)))
 
273
          {
 
274
            found_errors++;
 
275
            fprintf(stderr,
 
276
                    "Warning at '%s': Found lock of type %d that is write and read locked\n",
 
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
 
 
281
          }
 
282
        }
 
283
        if (lock->read_wait.data)
 
284
        {
 
285
          if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
 
286
              lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
 
287
          {
 
288
            found_errors++;
 
289
            fprintf(stderr,
 
290
                    "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
 
291
                    where,
 
292
                    (int) lock->read_wait.data->type,
 
293
                    (int) lock->write.data->type);
 
294
          }
 
295
        }
 
296
      }
 
297
    }
 
298
    if (found_errors != old_found_errors)
 
299
    {
 
300
      DBUG_PRINT("error",("Found wrong lock"));
 
301
    }
 
302
  }
 
303
  DBUG_VOID_RETURN;
 
304
}
 
305
 
 
306
#else /* EXTRA_DEBUG */
 
307
#define check_locks(A,B,C)
 
308
#endif
 
309
 
 
310
 
123
311
        /* Initialize a lock */
124
312
 
125
313
void thr_lock_init(THR_LOCK *lock)
126
314
{
127
 
  memset(lock, 0, sizeof(*lock));
128
 
  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));
129
318
  lock->read.last= &lock->read.data;
130
319
  lock->read_wait.last= &lock->read_wait.data;
131
320
  lock->write_wait.last= &lock->write_wait.data;
135
324
  lock->list.data=(void*) lock;
136
325
  thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
137
326
  pthread_mutex_unlock(&THR_LOCK_lock);
138
 
  return;
 
327
  DBUG_VOID_RETURN;
139
328
}
140
329
 
141
330
 
142
331
void thr_lock_delete(THR_LOCK *lock)
143
332
{
144
 
  pthread_mutex_destroy(&lock->mutex);
 
333
  DBUG_ENTER("thr_lock_delete");
 
334
  VOID(pthread_mutex_destroy(&lock->mutex));
145
335
  pthread_mutex_lock(&THR_LOCK_lock);
146
336
  thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
147
337
  pthread_mutex_unlock(&THR_LOCK_lock);
148
 
  return;
 
338
  DBUG_VOID_RETURN;
149
339
}
150
340
 
151
341
 
169
359
}
170
360
 
171
361
 
172
 
static inline bool
 
362
static inline my_bool
173
363
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
174
364
{
175
365
  for ( ; data ; data=data->next)
180
370
  return 0;
181
371
}
182
372
 
183
 
static inline bool have_specific_lock(THR_LOCK_DATA *data,
 
373
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
184
374
                                         enum thr_lock_type type)
185
375
{
186
376
  for ( ; data ; data=data->next)
197
387
 
198
388
static enum enum_thr_lock_result
199
389
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
200
 
              bool in_wait_list)
 
390
              my_bool in_wait_list)
201
391
{
202
392
  struct st_my_thread_var *thread_var= my_thread_var;
203
393
  pthread_cond_t *cond= &thread_var->suspend;
204
394
  struct timespec wait_timeout;
205
395
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
206
 
  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");
207
398
 
208
399
  if (!in_wait_list)
209
400
  {
242
433
    */
243
434
    if (data->cond == 0)
244
435
    {
 
436
      DBUG_PRINT("thr_lock", ("lock granted/aborted"));
245
437
      break;
246
438
    }
247
439
    if (rc == ETIMEDOUT || rc == ETIME)
248
440
    {
249
441
      /* purecov: begin inspected */
 
442
      DBUG_PRINT("thr_lock", ("lock timed out"));
250
443
      result= THR_LOCK_WAIT_TIMEOUT;
251
444
      break;
252
445
      /* purecov: end */
253
446
    }
254
447
  }
 
448
  DBUG_PRINT("thr_lock", ("aborted: %d  in_wait_list: %d",
 
449
                          thread_var->abort, in_wait_list));
 
450
 
255
451
  if (data->cond || data->type == TL_UNLOCK)
256
452
  {
257
453
    if (data->cond)                             /* aborted or timed out */
261
457
      else
262
458
        wait->last=data->prev;
263
459
      data->type= TL_UNLOCK;                    /* No lock */
 
460
      check_locks(data->lock, "killed or timed out wait_for_lock", 1);
264
461
      wake_up_waiters(data->lock);
265
462
    }
 
463
    else
 
464
    {
 
465
      DBUG_PRINT("thr_lock", ("lock aborted"));
 
466
      check_locks(data->lock, "aborted wait_for_lock", 0);
 
467
    }
266
468
  }
267
469
  else
268
470
  {
269
471
    result= THR_LOCK_SUCCESS;
270
472
    if (data->lock->get_status)
271
473
      (*data->lock->get_status)(data->status_param, 0);
 
474
    check_locks(data->lock,"got wait_for_lock",0);
272
475
  }
273
476
  pthread_mutex_unlock(&data->lock->mutex);
274
477
 
277
480
  thread_var->current_mutex= 0;
278
481
  thread_var->current_cond=  0;
279
482
  pthread_mutex_unlock(&thread_var->mutex);
280
 
  return(result);
 
483
  DBUG_RETURN(result);
281
484
}
282
485
 
283
486
 
289
492
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
290
493
  struct st_lock_list *wait_queue;
291
494
  THR_LOCK_DATA *lock_owner;
 
495
  DBUG_ENTER("thr_lock");
292
496
 
293
497
  data->next=0;
294
498
  data->cond=0;                                 /* safety */
295
499
  data->type=lock_type;
296
500
  data->owner= owner;                           /* Must be reset ! */
297
 
  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));
 
505
  check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
 
506
              "enter read_lock" : "enter write_lock",0);
298
507
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
299
508
  {
300
509
    /* Request for READ lock */
309
518
           and the read lock is not TL_READ_NO_INSERT
310
519
      */
311
520
 
 
521
      DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
 
522
                         lock->write.data->owner->info->thread_id));
312
523
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
313
524
          (lock->write.data->type <= TL_WRITE_DELAYED &&
314
525
           (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
320
531
        lock->read.last= &data->next;
321
532
        if (lock_type == TL_READ_NO_INSERT)
322
533
          lock->read_no_write_count++;
 
534
        check_locks(lock,"read lock with old write lock",0);
323
535
        if (lock->get_status)
324
536
          (*lock->get_status)(data->status_param, 0);
325
537
        statistic_increment(locks_immediate,&THR_LOCK_lock);
345
557
        (*lock->get_status)(data->status_param, 0);
346
558
      if (lock_type == TL_READ_NO_INSERT)
347
559
        lock->read_no_write_count++;
 
560
      check_locks(lock,"read lock with no write locks",0);
348
561
      statistic_increment(locks_immediate,&THR_LOCK_lock);
349
562
      goto end;
350
563
    }
418
631
          We have already got a write lock or all locks are
419
632
          TL_WRITE_ALLOW_WRITE
420
633
        */
 
634
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
 
635
                            (ulong) lock->write_wait.data,
 
636
                            lock->write.data->type));
421
637
 
422
638
        (*lock->write.last)=data;       /* Add to running fifo */
423
639
        data->prev=lock->write.last;
424
640
        lock->write.last= &data->next;
 
641
        check_locks(lock,"second write lock",0);
425
642
        if (data->lock->get_status)
426
643
          (*data->lock->get_status)(data->status_param, 0);
427
644
        statistic_increment(locks_immediate,&THR_LOCK_lock);
428
645
        goto end;
429
646
      }
 
647
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
 
648
                         lock->write.data->owner->info->thread_id));
430
649
    }
431
650
    else
432
651
    {
 
652
      DBUG_PRINT("info", ("write_wait.data: 0x%lx",
 
653
                          (ulong) lock->write_wait.data));
433
654
      if (!lock->write_wait.data)
434
655
      {                                         /* no scheduled write locks */
435
 
        bool concurrent_insert= 0;
 
656
        my_bool concurrent_insert= 0;
436
657
        if (lock_type == TL_WRITE_CONCURRENT_INSERT)
437
658
        {
438
659
          concurrent_insert= 1;
454
675
          lock->write.last= &data->next;
455
676
          if (data->lock->get_status)
456
677
            (*data->lock->get_status)(data->status_param, concurrent_insert);
 
678
          check_locks(lock,"only write lock",0);
457
679
          statistic_increment(locks_immediate,&THR_LOCK_lock);
458
680
          goto end;
459
681
        }
460
682
      }
 
683
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
 
684
                         lock->read.data->owner->info->thread_id, data->type));
461
685
    }
462
686
    wait_queue= &lock->write_wait;
463
687
  }
470
694
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
471
695
  if (lock_owner && lock_owner->owner->info == owner->info)
472
696
  {
 
697
    DBUG_PRINT("lock",("deadlock"));
473
698
    result= THR_LOCK_DEADLOCK;
474
699
    goto end;
475
700
  }
476
701
  /* Can't get lock yet;  Wait for it */
477
 
  return(wait_for_lock(wait_queue, data, 0));
 
702
  DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
478
703
end:
479
704
  pthread_mutex_unlock(&lock->mutex);
480
 
  return(result);
 
705
  DBUG_RETURN(result);
481
706
}
482
707
 
483
708
 
484
709
static inline void free_all_read_locks(THR_LOCK *lock,
485
 
                                       bool using_concurrent_insert)
 
710
                                       my_bool using_concurrent_insert)
486
711
{
487
712
  THR_LOCK_DATA *data=lock->read_wait.data;
488
713
 
 
714
  check_locks(lock,"before freeing read locks",1);
 
715
 
489
716
  /* move all locks from read_wait list to read list */
490
717
  (*lock->read.last)=data;
491
718
  data->prev=lock->read.last;
502
729
      if (using_concurrent_insert)
503
730
      {
504
731
        /*
505
 
          We can't free this lock;
 
732
          We can't free this lock; 
506
733
          Link lock away from read chain back into read_wait chain
507
734
        */
508
735
        if (((*data->prev)=data->next))
515
742
        continue;
516
743
      }
517
744
      lock->read_no_write_count++;
518
 
    }
 
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 */
519
750
    data->cond=0;                               /* Mark thread free */
520
 
    pthread_cond_signal(cond);
 
751
    VOID(pthread_cond_signal(cond));
521
752
  } while ((data=data->next));
522
753
  *lock->read_wait.last=0;
523
754
  if (!lock->read_wait.data)
524
755
    lock->write_lock_count=0;
 
756
  check_locks(lock,"after giving read locks",0);
525
757
}
526
758
 
527
759
        /* Unlock lock and free next thread on same lock */
530
762
{
531
763
  THR_LOCK *lock=data->lock;
532
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));
533
768
  pthread_mutex_lock(&lock->mutex);
 
769
  check_locks(lock,"start of release lock",0);
534
770
 
535
771
  if (((*data->prev)=data->next))               /* remove from lock-list */
536
772
    data->next->prev= data->prev;
539
775
  else if (lock_type == TL_WRITE_DELAYED && data->cond)
540
776
  {
541
777
    /*
542
 
      This only happens in extreme circumstances when a
 
778
      This only happens in extreme circumstances when a 
543
779
      write delayed lock that is waiting for a lock
544
780
    */
545
781
    lock->write_wait.last=data->prev;           /* Put it on wait queue */
559
795
  if (lock_type == TL_READ_NO_INSERT)
560
796
    lock->read_no_write_count--;
561
797
  data->type=TL_UNLOCK;                         /* Mark unlocked */
 
798
  check_locks(lock,"after releasing lock",1);
562
799
  wake_up_waiters(lock);
563
800
  pthread_mutex_unlock(&lock->mutex);
564
 
  return;
 
801
  DBUG_VOID_RETURN;
565
802
}
566
803
 
567
804
 
578
815
  THR_LOCK_DATA *data;
579
816
  enum thr_lock_type lock_type;
580
817
 
 
818
  DBUG_ENTER("wake_up_waiters");
 
819
 
581
820
  if (!lock->write.data)                        /* If no active write locks */
582
821
  {
583
822
    data=lock->write_wait.data;
594
833
          lock->write_lock_count=0;
595
834
          if (lock->read_wait.data)
596
835
          {
 
836
            DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
597
837
            free_all_read_locks(lock,0);
598
838
            goto end;
599
839
          }
611
851
          if (data->type == TL_WRITE_CONCURRENT_INSERT &&
612
852
              (*lock->check_status)(data->status_param))
613
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 */
614
858
          {
615
859
            pthread_cond_t *cond=data->cond;
616
860
            data->cond=0;                               /* Mark thread free */
617
 
            pthread_cond_signal(cond);  /* Start waiting thread */
 
861
            VOID(pthread_cond_signal(cond));    /* Start waiting thread */
618
862
          }
619
863
          if (data->type != TL_WRITE_ALLOW_WRITE ||
620
864
              !lock->write_wait.data ||
631
875
                            data &&
632
876
                            (data->type == TL_WRITE_CONCURRENT_INSERT ||
633
877
                             data->type == TL_WRITE_ALLOW_WRITE));
 
878
      else
 
879
      {
 
880
        DBUG_PRINT("lock",("No waiting read locks to free"));
 
881
      }
634
882
    }
635
883
    else if (data &&
636
884
             (lock_type=data->type) <= TL_WRITE_DELAYED &&
661
909
        lock->write.last= &data->next;
662
910
        data->next=0;                           /* Only one write lock */
663
911
        data->cond=0;                           /* Mark thread free */
664
 
        pthread_cond_signal(cond);      /* Start waiting thread */
 
912
        VOID(pthread_cond_signal(cond));        /* Start waiting thread */
665
913
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
666
914
               (data=lock->write_wait.data) &&
667
915
               data->type == TL_WRITE_ALLOW_WRITE);
674
922
      free_all_read_locks(lock,0);
675
923
  }
676
924
end:
677
 
  return;
 
925
  check_locks(lock, "after waking up waiters", 0);
 
926
  DBUG_VOID_RETURN;
678
927
}
679
928
 
680
929
 
685
934
*/
686
935
 
687
936
 
688
 
#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))
689
938
 
690
 
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
 
939
static void sort_locks(THR_LOCK_DATA **data,uint count)
691
940
{
692
941
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
693
942
 
709
958
 
710
959
 
711
960
enum enum_thr_lock_result
712
 
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)
713
962
{
714
963
  THR_LOCK_DATA **pos,**end;
 
964
  DBUG_ENTER("thr_multi_lock");
 
965
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
715
966
  if (count > 1)
716
967
    sort_locks(data,count);
717
968
  /* lock everything */
721
972
    if (result != THR_LOCK_SUCCESS)
722
973
    {                                           /* Aborted */
723
974
      thr_multi_unlock(data,(uint) (pos-data));
724
 
      return(result);
 
975
      DBUG_RETURN(result);
725
976
    }
 
977
#ifdef MAIN
 
978
    printf("Thread: %s  Got lock: 0x%lx  type: %d\n",my_thread_name(),
 
979
           (long) pos[0]->lock, pos[0]->type); fflush(stdout);
 
980
#endif
726
981
  }
727
982
  /*
728
983
    Ensure that all get_locks() have the same status
771
1026
    } while (pos != data);
772
1027
  }
773
1028
#endif
774
 
  return(THR_LOCK_SUCCESS);
 
1029
  DBUG_RETURN(THR_LOCK_SUCCESS);
775
1030
}
776
1031
 
777
1032
  /* free all locks */
778
1033
 
779
 
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
 
1034
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
780
1035
{
781
1036
  THR_LOCK_DATA **pos,**end;
 
1037
  DBUG_ENTER("thr_multi_unlock");
 
1038
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
782
1039
 
783
1040
  for (pos=data,end=data+count; pos < end ; pos++)
784
1041
  {
 
1042
#ifdef MAIN
 
1043
    printf("Thread: %s  Rel lock: 0x%lx  type: %d\n",
 
1044
           my_thread_name(), (long) pos[0]->lock, pos[0]->type);
 
1045
    fflush(stdout);
 
1046
#endif
785
1047
    if ((*pos)->type != TL_UNLOCK)
786
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
    }
787
1055
  }
788
 
  return;
 
1056
  DBUG_VOID_RETURN;
789
1057
}
790
1058
 
791
1059
/*
793
1061
  TL_WRITE_ONLY to abort any new accesses to the lock
794
1062
*/
795
1063
 
796
 
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
 
1064
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
797
1065
{
798
1066
  THR_LOCK_DATA *data;
 
1067
  DBUG_ENTER("thr_abort_locks");
799
1068
  pthread_mutex_lock(&lock->mutex);
800
1069
 
801
1070
  for (data=lock->read_wait.data; data ; data=data->next)
817
1086
  if (upgrade_lock && lock->write.data)
818
1087
    lock->write.data->type=TL_WRITE_ONLY;
819
1088
  pthread_mutex_unlock(&lock->mutex);
820
 
  return;
 
1089
  DBUG_VOID_RETURN;
821
1090
}
822
1091
 
823
1092
 
827
1096
  This is used to abort all locks for a specific thread
828
1097
*/
829
1098
 
830
 
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)
831
1100
{
832
1101
  THR_LOCK_DATA *data;
833
 
  bool found= false;
 
1102
  my_bool found= FALSE;
 
1103
  DBUG_ENTER("thr_abort_locks_for_thread");
834
1104
 
835
1105
  pthread_mutex_lock(&lock->mutex);
836
1106
  for (data= lock->read_wait.data; data ; data= data->next)
837
1107
  {
838
1108
    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
839
1109
    {
 
1110
      DBUG_PRINT("info",("Aborting read-wait lock"));
840
1111
      data->type= TL_UNLOCK;                    /* Mark killed */
841
1112
      /* It's safe to signal the cond first: we're still holding the mutex. */
842
 
      found= true;
 
1113
      found= TRUE;
843
1114
      pthread_cond_signal(data->cond);
844
1115
      data->cond= 0;                            /* Removed from list */
845
1116
 
853
1124
  {
854
1125
    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
855
1126
    {
 
1127
      DBUG_PRINT("info",("Aborting write-wait lock"));
856
1128
      data->type= TL_UNLOCK;
857
 
      found= true;
 
1129
      found= TRUE;
858
1130
      pthread_cond_signal(data->cond);
859
1131
      data->cond= 0;
860
1132
 
866
1138
  }
867
1139
  wake_up_waiters(lock);
868
1140
  pthread_mutex_unlock(&lock->mutex);
869
 
  return(found);
 
1141
  DBUG_RETURN(found);
870
1142
}
871
1143
 
872
1144
 
904
1176
                              enum thr_lock_type new_lock_type)
905
1177
{
906
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
  DBUG_ENTER("thr_downgrade_write_only_lock");
907
1183
 
908
1184
  pthread_mutex_lock(&lock->mutex);
 
1185
  DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
 
1186
  DBUG_ASSERT(old_lock_type > new_lock_type);
909
1187
  in_data->type= new_lock_type;
 
1188
  check_locks(lock,"after downgrading lock",0);
910
1189
 
911
1190
  pthread_mutex_unlock(&lock->mutex);
912
 
  return;
 
1191
  DBUG_VOID_RETURN;
913
1192
}
914
1193
 
915
1194
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
916
1195
 
917
 
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
 
1196
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
918
1197
{
919
1198
  THR_LOCK *lock=data->lock;
 
1199
  DBUG_ENTER("thr_upgrade_write_delay_lock");
920
1200
 
921
1201
  pthread_mutex_lock(&lock->mutex);
922
1202
  if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
923
1203
  {
924
1204
    pthread_mutex_unlock(&lock->mutex);
925
 
    return(data->type == TL_UNLOCK);    /* Test if Aborted */
 
1205
    DBUG_RETURN(data->type == TL_UNLOCK);       /* Test if Aborted */
926
1206
  }
 
1207
  check_locks(lock,"before upgrading lock",0);
927
1208
  /* TODO:  Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
928
1209
  data->type=TL_WRITE;                          /* Upgrade lock */
929
1210
 
935
1216
      if (data->lock->get_status)
936
1217
        (*data->lock->get_status)(data->status_param, 0);
937
1218
      pthread_mutex_unlock(&lock->mutex);
938
 
      return(0);
 
1219
      DBUG_RETURN(0);
939
1220
    }
940
1221
 
941
1222
    if (((*data->prev)=data->next))             /* remove from lock-list */
949
1230
      lock->write_wait.last= &data->next;
950
1231
    data->prev= &lock->write_wait.data;
951
1232
    lock->write_wait.data=data;
952
 
  }
953
 
 
954
 
  return(wait_for_lock(&lock->write_wait,data,1));
 
1233
    check_locks(lock,"upgrading lock",0);
 
1234
  }
 
1235
  else
 
1236
  {
 
1237
    check_locks(lock,"waiting for lock",0);
 
1238
  }
 
1239
  DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
955
1240
}
956
1241
 
957
1242
 
958
1243
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
959
1244
 
960
 
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
 
1245
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
961
1246
{
962
1247
  THR_LOCK *lock=data->lock;
 
1248
  DBUG_ENTER("thr_reschedule_write_lock");
963
1249
 
964
1250
  pthread_mutex_lock(&lock->mutex);
965
1251
  if (!lock->read_wait.data)                    /* No waiting read locks */
966
1252
  {
967
1253
    pthread_mutex_unlock(&lock->mutex);
968
 
    return(0);
 
1254
    DBUG_RETURN(0);
969
1255
  }
970
1256
 
971
1257
  data->type=TL_WRITE_DELAYED;
986
1272
  free_all_read_locks(lock,0);
987
1273
 
988
1274
  pthread_mutex_unlock(&lock->mutex);
989
 
  return(thr_upgrade_write_delay_lock(data));
990
 
}
 
1275
  DBUG_RETURN(thr_upgrade_write_delay_lock(data));
 
1276
}
 
1277
 
 
1278
 
 
1279
#include <my_sys.h>
 
1280
 
 
1281
static void thr_print_lock(const char* name,struct st_lock_list *list)
 
1282
{
 
1283
  THR_LOCK_DATA *data,**prev;
 
1284
  uint count=0;
 
1285
 
 
1286
  if (list->data)
 
1287
  {
 
1288
    printf("%-10s: ",name);
 
1289
    prev= &list->data;
 
1290
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
 
1291
    {
 
1292
      printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
 
1293
             (int) data->type);
 
1294
      if (data->prev != prev)
 
1295
        printf("\nWarning: prev didn't point at previous lock\n");
 
1296
      prev= &data->next;
 
1297
    }
 
1298
    puts("");
 
1299
    if (prev != list->last)
 
1300
      printf("Warning: last didn't point at last lock\n");
 
1301
  }
 
1302
}
 
1303
 
 
1304
void thr_print_locks(void)
 
1305
{
 
1306
  LIST *list;
 
1307
  uint count=0;
 
1308
 
 
1309
  pthread_mutex_lock(&THR_LOCK_lock);
 
1310
  puts("Current locks:");
 
1311
  for (list= thr_lock_thread_list; list && count++ < MAX_THREADS;
 
1312
       list= list_rest(list))
 
1313
  {
 
1314
    THR_LOCK *lock=(THR_LOCK*) list->data;
 
1315
    VOID(pthread_mutex_lock(&lock->mutex));
 
1316
    printf("lock: 0x%lx:",(ulong) lock);
 
1317
    if ((lock->write_wait.data || lock->read_wait.data) &&
 
1318
        (! lock->read.data && ! lock->write.data))
 
1319
      printf(" WARNING: ");
 
1320
    if (lock->write.data)
 
1321
      printf(" write");
 
1322
    if (lock->write_wait.data)
 
1323
      printf(" write_wait");
 
1324
    if (lock->read.data)
 
1325
      printf(" read");
 
1326
    if (lock->read_wait.data)
 
1327
      printf(" read_wait");
 
1328
    puts("");
 
1329
    thr_print_lock("write",&lock->write);
 
1330
    thr_print_lock("write_wait",&lock->write_wait);
 
1331
    thr_print_lock("read",&lock->read);
 
1332
    thr_print_lock("read_wait",&lock->read_wait);
 
1333
    VOID(pthread_mutex_unlock(&lock->mutex));
 
1334
    puts("");
 
1335
  }
 
1336
  fflush(stdout);
 
1337
  pthread_mutex_unlock(&THR_LOCK_lock);
 
1338
}
 
1339
 
 
1340
/*****************************************************************************
 
1341
** Test of thread locks
 
1342
****************************************************************************/
 
1343
 
 
1344
#ifdef MAIN
 
1345
 
 
1346
struct st_test {
 
1347
  uint lock_nr;
 
1348
  enum thr_lock_type lock_type;
 
1349
};
 
1350
 
 
1351
THR_LOCK locks[5];                      /* 4 locks */
 
1352
 
 
1353
struct st_test test_0[] = {{0,TL_READ}};        /* One lock */
 
1354
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
 
1355
struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
 
1356
struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
 
1357
struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
 
1358
struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
 
1359
struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
 
1360
struct st_test test_7[] = {{3,TL_READ}};
 
1361
struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}};  /* Should be quick */
 
1362
struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
 
1363
struct st_test test_10[] ={{4,TL_WRITE}};
 
1364
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}}; /* Many writes */
 
1365
struct st_test test_12[] = {{0,TL_WRITE_ALLOW_READ},{1,TL_WRITE_ALLOW_READ},{2,TL_WRITE_ALLOW_READ},{3,TL_WRITE_ALLOW_READ}}; /* Many writes */
 
1366
struct st_test test_13[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_WRITE_CONCURRENT_INSERT},{2,TL_WRITE_CONCURRENT_INSERT},{3,TL_WRITE_CONCURRENT_INSERT}};
 
1367
struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
 
1368
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
 
1369
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
 
1370
 
 
1371
struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
 
1372
                           test_7,test_8,test_9,test_10,test_11,test_12,
 
1373
                           test_13,test_14,test_15,test_16};
 
1374
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
 
1375
                    sizeof(test_1)/sizeof(struct st_test),
 
1376
                    sizeof(test_2)/sizeof(struct st_test),
 
1377
                    sizeof(test_3)/sizeof(struct st_test),
 
1378
                    sizeof(test_4)/sizeof(struct st_test),
 
1379
                    sizeof(test_5)/sizeof(struct st_test),
 
1380
                    sizeof(test_6)/sizeof(struct st_test),
 
1381
                    sizeof(test_7)/sizeof(struct st_test),
 
1382
                    sizeof(test_8)/sizeof(struct st_test),
 
1383
                    sizeof(test_9)/sizeof(struct st_test),
 
1384
                    sizeof(test_10)/sizeof(struct st_test),
 
1385
                    sizeof(test_11)/sizeof(struct st_test),
 
1386
                    sizeof(test_12)/sizeof(struct st_test),
 
1387
                    sizeof(test_13)/sizeof(struct st_test),
 
1388
                    sizeof(test_14)/sizeof(struct st_test),
 
1389
                    sizeof(test_15)/sizeof(struct st_test),
 
1390
                    sizeof(test_16)/sizeof(struct st_test)
 
1391
};
 
1392
 
 
1393
 
 
1394
static pthread_cond_t COND_thread_count;
 
1395
static pthread_mutex_t LOCK_thread_count;
 
1396
static uint thread_count;
 
1397
static ulong sum=0;
 
1398
 
 
1399
#define MAX_LOCK_COUNT 8
 
1400
 
 
1401
/* The following functions is for WRITE_CONCURRENT_INSERT */
 
1402
 
 
1403
static void test_get_status(void* param __attribute__((unused)),
 
1404
                            int concurrent_insert __attribute__((unused)))
 
1405
{
 
1406
}
 
1407
 
 
1408
static void test_update_status(void* param __attribute__((unused)))
 
1409
{
 
1410
}
 
1411
 
 
1412
static void test_copy_status(void* to __attribute__((unused)) ,
 
1413
                             void *from __attribute__((unused)))
 
1414
{
 
1415
}
 
1416
 
 
1417
static my_bool test_check_status(void* param __attribute__((unused)))
 
1418
{
 
1419
  return 0;
 
1420
}
 
1421
 
 
1422
 
 
1423
static void *test_thread(void *arg)
 
1424
{
 
1425
  int i,j,param=*((int*) arg);
 
1426
  THR_LOCK_DATA data[MAX_LOCK_COUNT];
 
1427
  THR_LOCK_OWNER owner;
 
1428
  THR_LOCK_INFO lock_info;
 
1429
  THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
 
1430
  my_thread_init();
 
1431
 
 
1432
  printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
 
1433
 
 
1434
 
 
1435
  thr_lock_info_init(&lock_info);
 
1436
  thr_lock_owner_init(&owner, &lock_info);
 
1437
  for (i=0; i < lock_counts[param] ; i++)
 
1438
    thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
 
1439
  for (j=1 ; j < 10 ; j++)              /* try locking 10 times */
 
1440
  {
 
1441
    for (i=0; i < lock_counts[param] ; i++)
 
1442
    {                                   /* Init multi locks */
 
1443
      multi_locks[i]= &data[i];
 
1444
      data[i].type= tests[param][i].lock_type;
 
1445
    }
 
1446
    thr_multi_lock(multi_locks, lock_counts[param], &owner);
 
1447
    pthread_mutex_lock(&LOCK_thread_count);
 
1448
    {
 
1449
      int tmp=rand() & 7;                       /* Do something from 0-2 sec */
 
1450
      if (tmp == 0)
 
1451
        sleep(1);
 
1452
      else if (tmp == 1)
 
1453
        sleep(2);
 
1454
      else
 
1455
      {
 
1456
        ulong k;
 
1457
        for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
 
1458
          sum+=k;
 
1459
      }
 
1460
    }
 
1461
    pthread_mutex_unlock(&LOCK_thread_count);
 
1462
    thr_multi_unlock(multi_locks,lock_counts[param]);
 
1463
  }
 
1464
 
 
1465
  printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
 
1466
  thr_print_locks();
 
1467
  pthread_mutex_lock(&LOCK_thread_count);
 
1468
  thread_count--;
 
1469
  VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
 
1470
  pthread_mutex_unlock(&LOCK_thread_count);
 
1471
  free((uchar*) arg);
 
1472
  return 0;
 
1473
}
 
1474
 
 
1475
 
 
1476
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
 
1477
{
 
1478
  pthread_t tid;
 
1479
  pthread_attr_t thr_attr;
 
1480
  int i,*param,error;
 
1481
  MY_INIT(argv[0]);
 
1482
  if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
 
1483
    DBUG_PUSH(argv[1]+2);
 
1484
 
 
1485
  printf("Main thread: %s\n",my_thread_name());
 
1486
 
 
1487
  if ((error=pthread_cond_init(&COND_thread_count,NULL)))
 
1488
  {
 
1489
    fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
 
1490
            error,errno);
 
1491
    exit(1);
 
1492
  }
 
1493
  if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST)))
 
1494
  {
 
1495
    fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
 
1496
            error,errno);
 
1497
    exit(1);
 
1498
  }
 
1499
 
 
1500
  for (i=0 ; i < (int) array_elements(locks) ; i++)
 
1501
  {
 
1502
    thr_lock_init(locks+i);
 
1503
    locks[i].check_status= test_check_status;
 
1504
    locks[i].update_status=test_update_status;
 
1505
    locks[i].copy_status=  test_copy_status;
 
1506
    locks[i].get_status=   test_get_status;
 
1507
  }
 
1508
  if ((error=pthread_attr_init(&thr_attr)))
 
1509
  {
 
1510
    fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
 
1511
            error,errno);
 
1512
    exit(1);
 
1513
  }
 
1514
  if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
 
1515
  {
 
1516
    fprintf(stderr,
 
1517
            "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
 
1518
            error,errno);
 
1519
    exit(1);
 
1520
  }
 
1521
#ifndef pthread_attr_setstacksize               /* void return value */
 
1522
  if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
 
1523
  {
 
1524
    fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
 
1525
            error,errno);
 
1526
    exit(1);
 
1527
  }
 
1528
#endif
 
1529
#ifdef HAVE_THR_SETCONCURRENCY
 
1530
  VOID(thr_setconcurrency(2));
 
1531
#endif
 
1532
  for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
 
1533
  {
 
1534
    param=(int*) malloc(sizeof(int));
 
1535
    *param=i;
 
1536
 
 
1537
    if ((error=pthread_mutex_lock(&LOCK_thread_count)))
 
1538
    {
 
1539
      fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
 
1540
              error,errno);
 
1541
      exit(1);
 
1542
    }
 
1543
    if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
 
1544
    {
 
1545
      fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
 
1546
              error,errno);
 
1547
      pthread_mutex_unlock(&LOCK_thread_count);
 
1548
      exit(1);
 
1549
    }
 
1550
    thread_count++;
 
1551
    pthread_mutex_unlock(&LOCK_thread_count);
 
1552
  }
 
1553
 
 
1554
  pthread_attr_destroy(&thr_attr);
 
1555
  if ((error=pthread_mutex_lock(&LOCK_thread_count)))
 
1556
    fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
 
1557
  while (thread_count)
 
1558
  {
 
1559
    if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
 
1560
      fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
 
1561
  }
 
1562
  if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
 
1563
    fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
 
1564
  for (i=0 ; i < (int) array_elements(locks) ; i++)
 
1565
    thr_lock_delete(locks+i);
 
1566
#ifdef EXTRA_DEBUG
 
1567
  if (found_errors)
 
1568
    printf("Got %d warnings\n",found_errors);
 
1569
  else
 
1570
#endif
 
1571
    printf("Test succeeded\n");
 
1572
  return 0;
 
1573
}
 
1574
 
 
1575
#endif /* MAIN */