~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to mysys/thr_lock.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/*
 
17
Read and write locks for Posix threads. All tread must acquire
 
18
all locks it needs through thr_multi_lock() to avoid dead-locks.
 
19
A lock consists of a master lock (THR_LOCK), and lock instances
 
20
(THR_LOCK_DATA).
 
21
Any thread can have any number of lock instances (read and write:s) on
 
22
any lock. All lock instances must be freed.
 
23
Locks are prioritized according to:
 
24
 
 
25
The current lock types are:
 
26
 
 
27
TL_READ                 # Low priority read
 
28
TL_READ_WITH_SHARED_LOCKS
 
29
TL_READ_HIGH_PRIORITY   # High priority read
 
30
TL_READ_NO_INSERT       # Read without concurrent inserts
 
31
TL_WRITE_ALLOW_WRITE    # Write lock that allows other writers
 
32
TL_WRITE_ALLOW_READ     # Write lock, but allow reading
 
33
TL_WRITE_CONCURRENT_INSERT
 
34
                        # Insert that can be mixed when selects
 
35
TL_WRITE_DELAYED        # Used by delayed insert
 
36
                        # Allows lower locks to take over
 
37
TL_WRITE_LOW_PRIORITY   # Low priority write
 
38
TL_WRITE                # High priority write
 
39
TL_WRITE_ONLY           # High priority write
 
40
                        # Abort all new lock request with an error
 
41
 
 
42
Locks are prioritized according to:
 
43
 
 
44
WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
 
45
WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
 
46
 
 
47
Locks in the same privilege level are scheduled in first-in-first-out order.
 
48
 
 
49
To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
 
50
should put a pointer to the following functions in the lock structure:
 
51
(If the pointer is zero (default), the function is not called)
 
52
 
 
53
check_status:
 
54
         Before giving a lock of type TL_WRITE_CONCURRENT_INSERT,
 
55
         we check if this function exists and returns 0.
 
56
         If not, then the lock is upgraded to TL_WRITE_LOCK
 
57
         In MyISAM this is a simple check if the insert can be done
 
58
         at the end of the datafile.
 
59
update_status:
 
60
        Before a write lock is released, this function is called.
 
61
        In MyISAM this functions updates the count and length of the datafile
 
62
get_status:
 
63
        When one gets a lock this functions is called.
 
64
        In MyISAM this stores the number of rows and size of the datafile
 
65
        for concurrent reads.
 
66
 
 
67
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
 
68
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
 
69
multiple read locks.
 
70
 
 
71
*/
 
72
 
 
73
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
 
74
#define FORCE_DBUG_OFF
 
75
#endif
 
76
 
 
77
#include "mysys_priv.h"
 
78
 
 
79
#ifdef THREAD
 
80
#include "thr_lock.h"
 
81
#include <m_string.h>
 
82
#include <errno.h>
 
83
 
 
84
my_bool thr_lock_inited=0;
 
85
ulong locks_immediate = 0L, locks_waited = 0L;
 
86
ulong table_lock_wait_timeout;
 
87
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
 
88
 
 
89
/* The following constants are only for debug output */
 
90
#define MAX_THREADS 100
 
91
#define MAX_LOCKS   100
 
92
 
 
93
 
 
94
LIST *thr_lock_thread_list;                     /* List of threads in use */
 
95
ulong max_write_lock_count= ~(ulong) 0L;
 
96
 
 
97
static inline pthread_cond_t *get_cond(void)
 
98
{
 
99
  return &my_thread_var->suspend;
 
100
}
 
101
 
 
102
/*
 
103
** For the future (now the thread specific cond is alloced by my_pthread.c)
 
104
*/
 
105
 
 
106
my_bool init_thr_lock()
 
107
{
 
108
  thr_lock_inited=1;
 
109
  return 0;
 
110
}
 
111
 
 
112
static inline my_bool
 
113
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
 
114
{
 
115
  return rhs == lhs;
 
116
}
 
117
 
 
118
 
 
119
#ifdef EXTRA_DEBUG
 
120
#define MAX_FOUND_ERRORS        10              /* Report 10 first errors */
 
121
static uint found_errors=0;
 
122
 
 
123
static int check_lock(struct st_lock_list *list, const char* lock_type,
 
124
                      const char *where, my_bool same_owner, my_bool no_cond)
 
125
{
 
126
  THR_LOCK_DATA *data,**prev;
 
127
  uint count=0;
 
128
  THR_LOCK_OWNER *first_owner;
 
129
 
 
130
  prev= &list->data;
 
131
  if (list->data)
 
132
  {
 
133
    enum thr_lock_type last_lock_type=list->data->type;
 
134
 
 
135
    if (same_owner && list->data)
 
136
      first_owner= list->data->owner;
 
137
    for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
 
138
    {
 
139
      if (data->type != last_lock_type)
 
140
        last_lock_type=TL_IGNORE;
 
141
      if (data->prev != prev)
 
142
      {
 
143
        fprintf(stderr,
 
144
                "Warning: prev link %d didn't point at previous lock at %s: %s\n",
 
145
                count, lock_type, where);
 
146
        return 1;
 
147
      }
 
148
      if (same_owner &&
 
149
          !thr_lock_owner_equal(data->owner, first_owner) &&
 
150
          last_lock_type != TL_WRITE_ALLOW_WRITE)
 
151
      {
 
152
        fprintf(stderr,
 
153
                "Warning: Found locks from different threads in %s: %s\n",
 
154
                lock_type,where);
 
155
        return 1;
 
156
      }
 
157
      if (no_cond && data->cond)
 
158
      {
 
159
        fprintf(stderr,
 
160
                "Warning: Found active lock with not reset cond %s: %s\n",
 
161
                lock_type,where);
 
162
        return 1;
 
163
      }
 
164
      prev= &data->next;
 
165
    }
 
166
    if (data)
 
167
    {
 
168
      fprintf(stderr,"Warning: found too many locks at %s: %s\n",
 
169
              lock_type,where);
 
170
      return 1;
 
171
    }
 
172
  }
 
173
  if (prev != list->last)
 
174
  {
 
175
    fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
 
176
            lock_type, where);
 
177
    return 1;
 
178
  }
 
179
  return 0;
 
180
}
 
181
 
 
182
 
 
183
static void check_locks(THR_LOCK *lock, const char *where,
 
184
                        my_bool allow_no_locks)
 
185
{
 
186
  uint old_found_errors=found_errors;
 
187
  DBUG_ENTER("check_locks");
 
188
 
 
189
  if (found_errors < MAX_FOUND_ERRORS)
 
190
  {
 
191
    if (check_lock(&lock->write,"write",where,1,1) |
 
192
        check_lock(&lock->write_wait,"write_wait",where,0,0) |
 
193
        check_lock(&lock->read,"read",where,0,1) |
 
194
        check_lock(&lock->read_wait,"read_wait",where,0,0))
 
195
      found_errors++;
 
196
 
 
197
    if (found_errors < MAX_FOUND_ERRORS)
 
198
    {
 
199
      uint count=0;
 
200
      THR_LOCK_DATA *data;
 
201
      for (data=lock->read.data ; data ; data=data->next)
 
202
      {
 
203
        if ((int) data->type == (int) TL_READ_NO_INSERT)
 
204
          count++;
 
205
        /* Protect against infinite loop. */
 
206
        DBUG_ASSERT(count <= lock->read_no_write_count);
 
207
      }
 
208
      if (count != lock->read_no_write_count)
 
209
      {
 
210
        found_errors++;
 
211
        fprintf(stderr,
 
212
                "Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
 
213
      }      
 
214
 
 
215
      if (!lock->write.data)
 
216
      {
 
217
        if (!allow_no_locks && !lock->read.data &&
 
218
            (lock->write_wait.data || lock->read_wait.data))
 
219
        {
 
220
          found_errors++;
 
221
          fprintf(stderr,
 
222
                  "Warning at '%s': No locks in use but locks are in wait queue\n",
 
223
                  where);
 
224
        }
 
225
        if (!lock->write_wait.data)
 
226
        {
 
227
          if (!allow_no_locks && lock->read_wait.data)
 
228
          {
 
229
            found_errors++;
 
230
            fprintf(stderr,
 
231
                    "Warning at '%s': No write locks and waiting read locks\n",
 
232
                    where);
 
233
          }
 
234
        }
 
235
        else
 
236
        {
 
237
          if (!allow_no_locks &&
 
238
              (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
 
239
                 lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
 
240
                !lock->read_no_write_count) ||
 
241
               lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
 
242
               (lock->write_wait.data->type == TL_WRITE_DELAYED &&
 
243
                !lock->read.data)))
 
244
          {
 
245
            found_errors++;
 
246
            fprintf(stderr,
 
247
                    "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
 
248
          }
 
249
        }             
 
250
      }
 
251
      else
 
252
      {                                         /* Have write lock */
 
253
        if (lock->write_wait.data)
 
254
        {
 
255
          if (!allow_no_locks && 
 
256
              lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
 
257
              lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
 
258
          {
 
259
            found_errors++;
 
260
            fprintf(stderr,
 
261
                    "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
 
262
                    where);
 
263
          }
 
264
        }
 
265
        if (lock->read.data)
 
266
        {
 
267
          if (!thr_lock_owner_equal(lock->write.data->owner,
 
268
                                    lock->read.data->owner) &&
 
269
              ((lock->write.data->type > TL_WRITE_DELAYED &&
 
270
                lock->write.data->type != TL_WRITE_ONLY) ||
 
271
               ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
 
272
                 lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
 
273
                lock->read_no_write_count)))
 
274
          {
 
275
            found_errors++;
 
276
            fprintf(stderr,
 
277
                    "Warning at '%s': Found lock of type %d that is write and read locked\n",
 
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
 
 
282
          }
 
283
        }
 
284
        if (lock->read_wait.data)
 
285
        {
 
286
          if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
 
287
              lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
 
288
          {
 
289
            found_errors++;
 
290
            fprintf(stderr,
 
291
                    "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
 
292
                    where,
 
293
                    (int) lock->read_wait.data->type,
 
294
                    (int) lock->write.data->type);
 
295
          }
 
296
        }
 
297
      }
 
298
    }
 
299
    if (found_errors != old_found_errors)
 
300
    {
 
301
      DBUG_PRINT("error",("Found wrong lock"));
 
302
    }
 
303
  }
 
304
  DBUG_VOID_RETURN;
 
305
}
 
306
 
 
307
#else /* EXTRA_DEBUG */
 
308
#define check_locks(A,B,C)
 
309
#endif
 
310
 
 
311
 
 
312
        /* Initialize a lock */
 
313
 
 
314
void thr_lock_init(THR_LOCK *lock)
 
315
{
 
316
  DBUG_ENTER("thr_lock_init");
 
317
  bzero((char*) lock,sizeof(*lock));
 
318
  VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
 
319
  lock->read.last= &lock->read.data;
 
320
  lock->read_wait.last= &lock->read_wait.data;
 
321
  lock->write_wait.last= &lock->write_wait.data;
 
322
  lock->write.last= &lock->write.data;
 
323
 
 
324
  pthread_mutex_lock(&THR_LOCK_lock);           /* Add to locks in use */
 
325
  lock->list.data=(void*) lock;
 
326
  thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
 
327
  pthread_mutex_unlock(&THR_LOCK_lock);
 
328
  DBUG_VOID_RETURN;
 
329
}
 
330
 
 
331
 
 
332
void thr_lock_delete(THR_LOCK *lock)
 
333
{
 
334
  DBUG_ENTER("thr_lock_delete");
 
335
  VOID(pthread_mutex_destroy(&lock->mutex));
 
336
  pthread_mutex_lock(&THR_LOCK_lock);
 
337
  thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
 
338
  pthread_mutex_unlock(&THR_LOCK_lock);
 
339
  DBUG_VOID_RETURN;
 
340
}
 
341
 
 
342
 
 
343
void thr_lock_info_init(THR_LOCK_INFO *info)
 
344
{
 
345
  struct st_my_thread_var *tmp= my_thread_var;
 
346
  info->thread=    tmp->pthread_self;
 
347
  info->thread_id= tmp->id;
 
348
  info->n_cursors= 0;
 
349
}
 
350
 
 
351
        /* Initialize a lock instance */
 
352
 
 
353
void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
 
354
{
 
355
  data->lock=lock;
 
356
  data->type=TL_UNLOCK;
 
357
  data->owner= 0;                               /* no owner yet */
 
358
  data->status_param=param;
 
359
  data->cond=0;
 
360
}
 
361
 
 
362
 
 
363
static inline my_bool
 
364
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
 
365
{
 
366
  for ( ; data ; data=data->next)
 
367
  {
 
368
    if (thr_lock_owner_equal(data->owner, owner))
 
369
      return 1;                                 /* Already locked by thread */
 
370
  }
 
371
  return 0;
 
372
}
 
373
 
 
374
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
 
375
                                         enum thr_lock_type type)
 
376
{
 
377
  for ( ; data ; data=data->next)
 
378
  {
 
379
    if (data->type == type)
 
380
      return 1;
 
381
  }
 
382
  return 0;
 
383
}
 
384
 
 
385
 
 
386
static void wake_up_waiters(THR_LOCK *lock);
 
387
 
 
388
 
 
389
static enum enum_thr_lock_result
 
390
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
 
391
              my_bool in_wait_list)
 
392
{
 
393
  struct st_my_thread_var *thread_var= my_thread_var;
 
394
  pthread_cond_t *cond= &thread_var->suspend;
 
395
  struct timespec wait_timeout;
 
396
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
 
397
  my_bool can_deadlock= test(data->owner->info->n_cursors);
 
398
  DBUG_ENTER("wait_for_lock");
 
399
 
 
400
  if (!in_wait_list)
 
401
  {
 
402
    (*wait->last)=data;                         /* Wait for lock */
 
403
    data->prev= wait->last;
 
404
    wait->last= &data->next;
 
405
  }
 
406
 
 
407
  statistic_increment(locks_waited, &THR_LOCK_lock);
 
408
 
 
409
  /* Set up control struct to allow others to abort locks */
 
410
  thread_var->current_mutex= &data->lock->mutex;
 
411
  thread_var->current_cond=  cond;
 
412
  data->cond= cond;
 
413
 
 
414
  if (can_deadlock)
 
415
    set_timespec(wait_timeout, table_lock_wait_timeout);
 
416
  while (!thread_var->abort || in_wait_list)
 
417
  {
 
418
    int rc= (can_deadlock ?
 
419
             pthread_cond_timedwait(cond, &data->lock->mutex,
 
420
                                    &wait_timeout) :
 
421
             pthread_cond_wait(cond, &data->lock->mutex));
 
422
    /*
 
423
      We must break the wait if one of the following occurs:
 
424
      - the connection has been aborted (!thread_var->abort), but
 
425
        this is not a delayed insert thread (in_wait_list). For a delayed
 
426
        insert thread the proper action at shutdown is, apparently, to
 
427
        acquire the lock and complete the insert.
 
428
      - the lock has been granted (data->cond is set to NULL by the granter),
 
429
        or the waiting has been aborted (additionally data->type is set to
 
430
        TL_UNLOCK).
 
431
      - the wait has timed out (rc == ETIMEDOUT)
 
432
      Order of checks below is important to not report about timeout
 
433
      if the predicate is true.
 
434
    */
 
435
    if (data->cond == 0)
 
436
    {
 
437
      DBUG_PRINT("thr_lock", ("lock granted/aborted"));
 
438
      break;
 
439
    }
 
440
    if (rc == ETIMEDOUT || rc == ETIME)
 
441
    {
 
442
      /* purecov: begin inspected */
 
443
      DBUG_PRINT("thr_lock", ("lock timed out"));
 
444
      result= THR_LOCK_WAIT_TIMEOUT;
 
445
      break;
 
446
      /* purecov: end */
 
447
    }
 
448
  }
 
449
  DBUG_PRINT("thr_lock", ("aborted: %d  in_wait_list: %d",
 
450
                          thread_var->abort, in_wait_list));
 
451
 
 
452
  if (data->cond || data->type == TL_UNLOCK)
 
453
  {
 
454
    if (data->cond)                             /* aborted or timed out */
 
455
    {
 
456
      if (((*data->prev)=data->next))           /* remove from wait-list */
 
457
        data->next->prev= data->prev;
 
458
      else
 
459
        wait->last=data->prev;
 
460
      data->type= TL_UNLOCK;                    /* No lock */
 
461
      check_locks(data->lock, "killed or timed out wait_for_lock", 1);
 
462
      wake_up_waiters(data->lock);
 
463
    }
 
464
    else
 
465
    {
 
466
      DBUG_PRINT("thr_lock", ("lock aborted"));
 
467
      check_locks(data->lock, "aborted wait_for_lock", 0);
 
468
    }
 
469
  }
 
470
  else
 
471
  {
 
472
    result= THR_LOCK_SUCCESS;
 
473
    if (data->lock->get_status)
 
474
      (*data->lock->get_status)(data->status_param, 0);
 
475
    check_locks(data->lock,"got wait_for_lock",0);
 
476
  }
 
477
  pthread_mutex_unlock(&data->lock->mutex);
 
478
 
 
479
  /* The following must be done after unlock of lock->mutex */
 
480
  pthread_mutex_lock(&thread_var->mutex);
 
481
  thread_var->current_mutex= 0;
 
482
  thread_var->current_cond=  0;
 
483
  pthread_mutex_unlock(&thread_var->mutex);
 
484
  DBUG_RETURN(result);
 
485
}
 
486
 
 
487
 
 
488
enum enum_thr_lock_result
 
489
thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
 
490
         enum thr_lock_type lock_type)
 
491
{
 
492
  THR_LOCK *lock=data->lock;
 
493
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
 
494
  struct st_lock_list *wait_queue;
 
495
  THR_LOCK_DATA *lock_owner;
 
496
  DBUG_ENTER("thr_lock");
 
497
 
 
498
  data->next=0;
 
499
  data->cond=0;                                 /* safety */
 
500
  data->type=lock_type;
 
501
  data->owner= owner;                           /* Must be reset ! */
 
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));
 
506
  check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
 
507
              "enter read_lock" : "enter write_lock",0);
 
508
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
 
509
  {
 
510
    /* Request for READ lock */
 
511
    if (lock->write.data)
 
512
    {
 
513
      /* We can allow a read lock even if there is already a write lock
 
514
         on the table in one the following cases:
 
515
         - This thread alread have a write lock on the table
 
516
         - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
 
517
           and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
 
518
         - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
 
519
           and the read lock is not TL_READ_NO_INSERT
 
520
      */
 
521
 
 
522
      DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
 
523
                         lock->write.data->owner->info->thread_id));
 
524
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
 
525
          (lock->write.data->type <= TL_WRITE_DELAYED &&
 
526
           (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
 
527
            (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
 
528
             lock->write.data->type != TL_WRITE_ALLOW_READ))))
 
529
      {                                         /* Already got a write lock */
 
530
        (*lock->read.last)=data;                /* Add to running FIFO */
 
531
        data->prev=lock->read.last;
 
532
        lock->read.last= &data->next;
 
533
        if (lock_type == TL_READ_NO_INSERT)
 
534
          lock->read_no_write_count++;
 
535
        check_locks(lock,"read lock with old write lock",0);
 
536
        if (lock->get_status)
 
537
          (*lock->get_status)(data->status_param, 0);
 
538
        statistic_increment(locks_immediate,&THR_LOCK_lock);
 
539
        goto end;
 
540
      }
 
541
      if (lock->write.data->type == TL_WRITE_ONLY)
 
542
      {
 
543
        /* We are not allowed to get a READ lock in this case */
 
544
        data->type=TL_UNLOCK;
 
545
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
 
546
        goto end;
 
547
      }
 
548
    }
 
549
    else if (!lock->write_wait.data ||
 
550
             lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
 
551
             lock_type == TL_READ_HIGH_PRIORITY ||
 
552
             have_old_read_lock(lock->read.data, data->owner))
 
553
    {                                           /* No important write-locks */
 
554
      (*lock->read.last)=data;                  /* Add to running FIFO */
 
555
      data->prev=lock->read.last;
 
556
      lock->read.last= &data->next;
 
557
      if (lock->get_status)
 
558
        (*lock->get_status)(data->status_param, 0);
 
559
      if (lock_type == TL_READ_NO_INSERT)
 
560
        lock->read_no_write_count++;
 
561
      check_locks(lock,"read lock with no write locks",0);
 
562
      statistic_increment(locks_immediate,&THR_LOCK_lock);
 
563
      goto end;
 
564
    }
 
565
    /*
 
566
      We're here if there is an active write lock or no write
 
567
      lock but a high priority write waiting in the write_wait queue.
 
568
      In the latter case we should yield the lock to the writer.
 
569
    */
 
570
    wait_queue= &lock->read_wait;
 
571
  }
 
572
  else                                          /* Request for WRITE lock */
 
573
  {
 
574
    if (lock_type == TL_WRITE_DELAYED)
 
575
    {
 
576
      if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
 
577
      {
 
578
        data->type=TL_UNLOCK;
 
579
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
 
580
        goto end;
 
581
      }
 
582
      /*
 
583
        if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
 
584
        (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
 
585
      */
 
586
      if ((!lock->write.data ||
 
587
           lock->write.data->type != TL_WRITE_ALLOW_READ) &&
 
588
          !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
 
589
          (lock->write.data || lock->read.data))
 
590
      {
 
591
        /* Add delayed write lock to write_wait queue, and return at once */
 
592
        (*lock->write_wait.last)=data;
 
593
        data->prev=lock->write_wait.last;
 
594
        lock->write_wait.last= &data->next;
 
595
        data->cond=get_cond();
 
596
        /*
 
597
          We don't have to do get_status here as we will do it when we change
 
598
          the delayed lock to a real write lock
 
599
        */
 
600
        statistic_increment(locks_immediate,&THR_LOCK_lock);
 
601
        goto end;
 
602
      }
 
603
    }
 
604
    else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
 
605
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;
 
606
 
 
607
    if (lock->write.data)                       /* If there is a write lock */
 
608
    {
 
609
      if (lock->write.data->type == TL_WRITE_ONLY)
 
610
      {
 
611
        /* Allow lock owner to bypass TL_WRITE_ONLY. */
 
612
        if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
 
613
        {
 
614
          /* We are not allowed to get a lock in this case */
 
615
          data->type=TL_UNLOCK;
 
616
          result= THR_LOCK_ABORTED;               /* Can't wait for this one */
 
617
          goto end;
 
618
        }
 
619
      }
 
620
 
 
621
      /*
 
622
        The following test will not work if the old lock was a
 
623
        TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
 
624
        the same thread, but this will never happen within MySQL.
 
625
      */
 
626
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
 
627
          (lock_type == TL_WRITE_ALLOW_WRITE &&
 
628
           !lock->write_wait.data &&
 
629
           lock->write.data->type == TL_WRITE_ALLOW_WRITE))
 
630
      {
 
631
        /*
 
632
          We have already got a write lock or all locks are
 
633
          TL_WRITE_ALLOW_WRITE
 
634
        */
 
635
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
 
636
                            (ulong) lock->write_wait.data,
 
637
                            lock->write.data->type));
 
638
 
 
639
        (*lock->write.last)=data;       /* Add to running fifo */
 
640
        data->prev=lock->write.last;
 
641
        lock->write.last= &data->next;
 
642
        check_locks(lock,"second write lock",0);
 
643
        if (data->lock->get_status)
 
644
          (*data->lock->get_status)(data->status_param, 0);
 
645
        statistic_increment(locks_immediate,&THR_LOCK_lock);
 
646
        goto end;
 
647
      }
 
648
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
 
649
                         lock->write.data->owner->info->thread_id));
 
650
    }
 
651
    else
 
652
    {
 
653
      DBUG_PRINT("info", ("write_wait.data: 0x%lx",
 
654
                          (ulong) lock->write_wait.data));
 
655
      if (!lock->write_wait.data)
 
656
      {                                         /* no scheduled write locks */
 
657
        my_bool concurrent_insert= 0;
 
658
        if (lock_type == TL_WRITE_CONCURRENT_INSERT)
 
659
        {
 
660
          concurrent_insert= 1;
 
661
          if ((*lock->check_status)(data->status_param))
 
662
          {
 
663
            concurrent_insert= 0;
 
664
            data->type=lock_type= thr_upgraded_concurrent_insert_lock;
 
665
          }
 
666
        }
 
667
 
 
668
        if (!lock->read.data ||
 
669
            (lock_type <= TL_WRITE_DELAYED &&
 
670
             ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
 
671
               lock_type != TL_WRITE_ALLOW_WRITE) ||
 
672
              !lock->read_no_write_count)))
 
673
        {
 
674
          (*lock->write.last)=data;             /* Add as current write lock */
 
675
          data->prev=lock->write.last;
 
676
          lock->write.last= &data->next;
 
677
          if (data->lock->get_status)
 
678
            (*data->lock->get_status)(data->status_param, concurrent_insert);
 
679
          check_locks(lock,"only write lock",0);
 
680
          statistic_increment(locks_immediate,&THR_LOCK_lock);
 
681
          goto end;
 
682
        }
 
683
      }
 
684
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
 
685
                         lock->read.data->owner->info->thread_id, data->type));
 
686
    }
 
687
    wait_queue= &lock->write_wait;
 
688
  }
 
689
  /*
 
690
    Try to detect a trivial deadlock when using cursors: attempt to
 
691
    lock a table that is already locked by an open cursor within the
 
692
    same connection. lock_owner can be zero if we succumbed to a high
 
693
    priority writer in the write_wait queue.
 
694
  */
 
695
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
 
696
  if (lock_owner && lock_owner->owner->info == owner->info)
 
697
  {
 
698
    DBUG_PRINT("lock",("deadlock"));
 
699
    result= THR_LOCK_DEADLOCK;
 
700
    goto end;
 
701
  }
 
702
  /* Can't get lock yet;  Wait for it */
 
703
  DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
 
704
end:
 
705
  pthread_mutex_unlock(&lock->mutex);
 
706
  DBUG_RETURN(result);
 
707
}
 
708
 
 
709
 
 
710
static inline void free_all_read_locks(THR_LOCK *lock,
 
711
                                       my_bool using_concurrent_insert)
 
712
{
 
713
  THR_LOCK_DATA *data=lock->read_wait.data;
 
714
 
 
715
  check_locks(lock,"before freeing read locks",1);
 
716
 
 
717
  /* move all locks from read_wait list to read list */
 
718
  (*lock->read.last)=data;
 
719
  data->prev=lock->read.last;
 
720
  lock->read.last=lock->read_wait.last;
 
721
 
 
722
  /* Clear read_wait list */
 
723
  lock->read_wait.last= &lock->read_wait.data;
 
724
 
 
725
  do
 
726
  {
 
727
    pthread_cond_t *cond=data->cond;
 
728
    if ((int) data->type == (int) TL_READ_NO_INSERT)
 
729
    {
 
730
      if (using_concurrent_insert)
 
731
      {
 
732
        /*
 
733
          We can't free this lock; 
 
734
          Link lock away from read chain back into read_wait chain
 
735
        */
 
736
        if (((*data->prev)=data->next))
 
737
          data->next->prev=data->prev;
 
738
        else
 
739
          lock->read.last=data->prev;
 
740
        *lock->read_wait.last= data;
 
741
        data->prev= lock->read_wait.last;
 
742
        lock->read_wait.last= &data->next;
 
743
        continue;
 
744
      }
 
745
      lock->read_no_write_count++;
 
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 */
 
751
    data->cond=0;                               /* Mark thread free */
 
752
    VOID(pthread_cond_signal(cond));
 
753
  } while ((data=data->next));
 
754
  *lock->read_wait.last=0;
 
755
  if (!lock->read_wait.data)
 
756
    lock->write_lock_count=0;
 
757
  check_locks(lock,"after giving read locks",0);
 
758
}
 
759
 
 
760
        /* Unlock lock and free next thread on same lock */
 
761
 
 
762
void thr_unlock(THR_LOCK_DATA *data)
 
763
{
 
764
  THR_LOCK *lock=data->lock;
 
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));
 
769
  pthread_mutex_lock(&lock->mutex);
 
770
  check_locks(lock,"start of release lock",0);
 
771
 
 
772
  if (((*data->prev)=data->next))               /* remove from lock-list */
 
773
    data->next->prev= data->prev;
 
774
  else if (lock_type <= TL_READ_NO_INSERT)
 
775
    lock->read.last=data->prev;
 
776
  else if (lock_type == TL_WRITE_DELAYED && data->cond)
 
777
  {
 
778
    /*
 
779
      This only happens in extreme circumstances when a 
 
780
      write delayed lock that is waiting for a lock
 
781
    */
 
782
    lock->write_wait.last=data->prev;           /* Put it on wait queue */
 
783
  }
 
784
  else
 
785
    lock->write.last=data->prev;
 
786
  if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
 
787
  {
 
788
    if (lock->update_status)
 
789
      (*lock->update_status)(data->status_param);
 
790
  }
 
791
  else
 
792
  {
 
793
    if (lock->restore_status)
 
794
      (*lock->restore_status)(data->status_param);
 
795
  }
 
796
  if (lock_type == TL_READ_NO_INSERT)
 
797
    lock->read_no_write_count--;
 
798
  data->type=TL_UNLOCK;                         /* Mark unlocked */
 
799
  check_locks(lock,"after releasing lock",1);
 
800
  wake_up_waiters(lock);
 
801
  pthread_mutex_unlock(&lock->mutex);
 
802
  DBUG_VOID_RETURN;
 
803
}
 
804
 
 
805
 
 
806
/**
 
807
  @brief  Wake up all threads which pending requests for the lock
 
808
          can be satisfied.
 
809
 
 
810
  @param  lock  Lock for which threads should be woken up
 
811
 
 
812
*/
 
813
 
 
814
static void wake_up_waiters(THR_LOCK *lock)
 
815
{
 
816
  THR_LOCK_DATA *data;
 
817
  enum thr_lock_type lock_type;
 
818
 
 
819
  DBUG_ENTER("wake_up_waiters");
 
820
 
 
821
  if (!lock->write.data)                        /* If no active write locks */
 
822
  {
 
823
    data=lock->write_wait.data;
 
824
    if (!lock->read.data)                       /* If no more locks in use */
 
825
    {
 
826
      /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
 
827
      if (data &&
 
828
          (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
 
829
           lock->read_wait.data->type < TL_READ_HIGH_PRIORITY))
 
830
      {
 
831
        if (lock->write_lock_count++ > max_write_lock_count)
 
832
        {
 
833
          /* Too many write locks in a row;  Release all waiting read locks */
 
834
          lock->write_lock_count=0;
 
835
          if (lock->read_wait.data)
 
836
          {
 
837
            DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
 
838
            free_all_read_locks(lock,0);
 
839
            goto end;
 
840
          }
 
841
        }
 
842
        for (;;)
 
843
        {
 
844
          if (((*data->prev)=data->next))       /* remove from wait-list */
 
845
            data->next->prev= data->prev;
 
846
          else
 
847
            lock->write_wait.last=data->prev;
 
848
          (*lock->write.last)=data;             /* Put in execute list */
 
849
          data->prev=lock->write.last;
 
850
          data->next=0;
 
851
          lock->write.last= &data->next;
 
852
          if (data->type == TL_WRITE_CONCURRENT_INSERT &&
 
853
              (*lock->check_status)(data->status_param))
 
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 */
 
859
          {
 
860
            pthread_cond_t *cond=data->cond;
 
861
            data->cond=0;                               /* Mark thread free */
 
862
            VOID(pthread_cond_signal(cond));    /* Start waiting thread */
 
863
          }
 
864
          if (data->type != TL_WRITE_ALLOW_WRITE ||
 
865
              !lock->write_wait.data ||
 
866
              lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
 
867
            break;
 
868
          data=lock->write_wait.data;           /* Free this too */
 
869
        }
 
870
        if (data->type >= TL_WRITE_LOW_PRIORITY)
 
871
          goto end;
 
872
        /* Release possible read locks together with the write lock */
 
873
      }
 
874
      if (lock->read_wait.data)
 
875
        free_all_read_locks(lock,
 
876
                            data &&
 
877
                            (data->type == TL_WRITE_CONCURRENT_INSERT ||
 
878
                             data->type == TL_WRITE_ALLOW_WRITE));
 
879
      else
 
880
      {
 
881
        DBUG_PRINT("lock",("No waiting read locks to free"));
 
882
      }
 
883
    }
 
884
    else if (data &&
 
885
             (lock_type=data->type) <= TL_WRITE_DELAYED &&
 
886
             ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
 
887
               lock_type != TL_WRITE_ALLOW_WRITE) ||
 
888
              !lock->read_no_write_count))
 
889
    {
 
890
      /*
 
891
        For DELAYED, ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks
 
892
        start WRITE locks together with the READ locks
 
893
      */
 
894
      if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
 
895
          (*lock->check_status)(data->status_param))
 
896
      {
 
897
        data->type=TL_WRITE;                    /* Upgrade lock */
 
898
        if (lock->read_wait.data)
 
899
          free_all_read_locks(lock,0);
 
900
        goto end;
 
901
      }
 
902
      do {
 
903
        pthread_cond_t *cond=data->cond;
 
904
        if (((*data->prev)=data->next))         /* remove from wait-list */
 
905
          data->next->prev= data->prev;
 
906
        else
 
907
          lock->write_wait.last=data->prev;
 
908
        (*lock->write.last)=data;               /* Put in execute list */
 
909
        data->prev=lock->write.last;
 
910
        lock->write.last= &data->next;
 
911
        data->next=0;                           /* Only one write lock */
 
912
        data->cond=0;                           /* Mark thread free */
 
913
        VOID(pthread_cond_signal(cond));        /* Start waiting thread */
 
914
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
 
915
               (data=lock->write_wait.data) &&
 
916
               data->type == TL_WRITE_ALLOW_WRITE);
 
917
      if (lock->read_wait.data)
 
918
        free_all_read_locks(lock,
 
919
                            (lock_type == TL_WRITE_CONCURRENT_INSERT ||
 
920
                             lock_type == TL_WRITE_ALLOW_WRITE));
 
921
    }
 
922
    else if (!data && lock->read_wait.data)
 
923
      free_all_read_locks(lock,0);
 
924
  }
 
925
end:
 
926
  check_locks(lock, "after waking up waiters", 0);
 
927
  DBUG_VOID_RETURN;
 
928
}
 
929
 
 
930
 
 
931
/*
 
932
** Get all locks in a specific order to avoid dead-locks
 
933
** Sort acording to lock position and put write_locks before read_locks if
 
934
** lock on same lock.
 
935
*/
 
936
 
 
937
 
 
938
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
 
939
 
 
940
static void sort_locks(THR_LOCK_DATA **data,uint count)
 
941
{
 
942
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
 
943
 
 
944
  /* Sort locks with insertion sort (fast because almost always few locks) */
 
945
 
 
946
  for (pos=data+1,end=data+count; pos < end ; pos++)
 
947
  {
 
948
    tmp= *pos;
 
949
    if (LOCK_CMP(tmp,pos[-1]))
 
950
    {
 
951
      prev=pos;
 
952
      do {
 
953
        prev[0]=prev[-1];
 
954
      } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
 
955
      prev[0]=tmp;
 
956
    }
 
957
  }
 
958
}
 
959
 
 
960
 
 
961
enum enum_thr_lock_result
 
962
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
 
963
{
 
964
  THR_LOCK_DATA **pos,**end;
 
965
  DBUG_ENTER("thr_multi_lock");
 
966
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
 
967
  if (count > 1)
 
968
    sort_locks(data,count);
 
969
  /* lock everything */
 
970
  for (pos=data,end=data+count; pos < end ; pos++)
 
971
  {
 
972
    enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
 
973
    if (result != THR_LOCK_SUCCESS)
 
974
    {                                           /* Aborted */
 
975
      thr_multi_unlock(data,(uint) (pos-data));
 
976
      DBUG_RETURN(result);
 
977
    }
 
978
#ifdef MAIN
 
979
    printf("Thread: %s  Got lock: 0x%lx  type: %d\n",my_thread_name(),
 
980
           (long) pos[0]->lock, pos[0]->type); fflush(stdout);
 
981
#endif
 
982
  }
 
983
  /*
 
984
    Ensure that all get_locks() have the same status
 
985
    If we lock the same table multiple times, we must use the same
 
986
    status_param!
 
987
  */
 
988
#if !defined(DONT_USE_RW_LOCKS)
 
989
  if (count > 1)
 
990
  {
 
991
    THR_LOCK_DATA *last_lock= end[-1];
 
992
    pos=end-1;
 
993
    do
 
994
    {
 
995
      pos--;
 
996
      if (last_lock->lock == (*pos)->lock &&
 
997
          last_lock->lock->copy_status)
 
998
      {
 
999
        if (last_lock->type <= TL_READ_NO_INSERT)
 
1000
        {
 
1001
          THR_LOCK_DATA **read_lock;
 
1002
          /*
 
1003
            If we are locking the same table with read locks we must ensure
 
1004
            that all tables share the status of the last write lock or
 
1005
            the same read lock.
 
1006
          */
 
1007
          for (;
 
1008
               (*pos)->type <= TL_READ_NO_INSERT &&
 
1009
                 pos != data &&
 
1010
                 pos[-1]->lock == (*pos)->lock ;
 
1011
               pos--) ;
 
1012
 
 
1013
          read_lock = pos+1;
 
1014
          do
 
1015
          {
 
1016
            (last_lock->lock->copy_status)((*read_lock)->status_param,
 
1017
                                           (*pos)->status_param);
 
1018
          } while (*(read_lock++) != last_lock);
 
1019
          last_lock= (*pos);                    /* Point at last write lock */
 
1020
        }
 
1021
        else
 
1022
          (*last_lock->lock->copy_status)((*pos)->status_param,
 
1023
                                          last_lock->status_param);
 
1024
      }
 
1025
      else
 
1026
        last_lock=(*pos);
 
1027
    } while (pos != data);
 
1028
  }
 
1029
#endif
 
1030
  DBUG_RETURN(THR_LOCK_SUCCESS);
 
1031
}
 
1032
 
 
1033
  /* free all locks */
 
1034
 
 
1035
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
 
1036
{
 
1037
  THR_LOCK_DATA **pos,**end;
 
1038
  DBUG_ENTER("thr_multi_unlock");
 
1039
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
 
1040
 
 
1041
  for (pos=data,end=data+count; pos < end ; pos++)
 
1042
  {
 
1043
#ifdef MAIN
 
1044
    printf("Thread: %s  Rel lock: 0x%lx  type: %d\n",
 
1045
           my_thread_name(), (long) pos[0]->lock, pos[0]->type);
 
1046
    fflush(stdout);
 
1047
#endif
 
1048
    if ((*pos)->type != TL_UNLOCK)
 
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
    }
 
1056
  }
 
1057
  DBUG_VOID_RETURN;
 
1058
}
 
1059
 
 
1060
/*
 
1061
  Abort all threads waiting for a lock. The lock will be upgraded to
 
1062
  TL_WRITE_ONLY to abort any new accesses to the lock
 
1063
*/
 
1064
 
 
1065
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
 
1066
{
 
1067
  THR_LOCK_DATA *data;
 
1068
  DBUG_ENTER("thr_abort_locks");
 
1069
  pthread_mutex_lock(&lock->mutex);
 
1070
 
 
1071
  for (data=lock->read_wait.data; data ; data=data->next)
 
1072
  {
 
1073
    data->type=TL_UNLOCK;                       /* Mark killed */
 
1074
    /* It's safe to signal the cond first: we're still holding the mutex. */
 
1075
    pthread_cond_signal(data->cond);
 
1076
    data->cond=0;                               /* Removed from list */
 
1077
  }
 
1078
  for (data=lock->write_wait.data; data ; data=data->next)
 
1079
  {
 
1080
    data->type=TL_UNLOCK;
 
1081
    pthread_cond_signal(data->cond);
 
1082
    data->cond=0;
 
1083
  }
 
1084
  lock->read_wait.last= &lock->read_wait.data;
 
1085
  lock->write_wait.last= &lock->write_wait.data;
 
1086
  lock->read_wait.data=lock->write_wait.data=0;
 
1087
  if (upgrade_lock && lock->write.data)
 
1088
    lock->write.data->type=TL_WRITE_ONLY;
 
1089
  pthread_mutex_unlock(&lock->mutex);
 
1090
  DBUG_VOID_RETURN;
 
1091
}
 
1092
 
 
1093
 
 
1094
/*
 
1095
  Abort all locks for specific table/thread combination
 
1096
 
 
1097
  This is used to abort all locks for a specific thread
 
1098
*/
 
1099
 
 
1100
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
 
1101
{
 
1102
  THR_LOCK_DATA *data;
 
1103
  my_bool found= FALSE;
 
1104
  DBUG_ENTER("thr_abort_locks_for_thread");
 
1105
 
 
1106
  pthread_mutex_lock(&lock->mutex);
 
1107
  for (data= lock->read_wait.data; data ; data= data->next)
 
1108
  {
 
1109
    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
 
1110
    {
 
1111
      DBUG_PRINT("info",("Aborting read-wait lock"));
 
1112
      data->type= TL_UNLOCK;                    /* Mark killed */
 
1113
      /* It's safe to signal the cond first: we're still holding the mutex. */
 
1114
      found= TRUE;
 
1115
      pthread_cond_signal(data->cond);
 
1116
      data->cond= 0;                            /* Removed from list */
 
1117
 
 
1118
      if (((*data->prev)= data->next))
 
1119
        data->next->prev= data->prev;
 
1120
      else
 
1121
        lock->read_wait.last= data->prev;
 
1122
    }
 
1123
  }
 
1124
  for (data= lock->write_wait.data; data ; data= data->next)
 
1125
  {
 
1126
    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
 
1127
    {
 
1128
      DBUG_PRINT("info",("Aborting write-wait lock"));
 
1129
      data->type= TL_UNLOCK;
 
1130
      found= TRUE;
 
1131
      pthread_cond_signal(data->cond);
 
1132
      data->cond= 0;
 
1133
 
 
1134
      if (((*data->prev)= data->next))
 
1135
        data->next->prev= data->prev;
 
1136
      else
 
1137
        lock->write_wait.last= data->prev;
 
1138
    }
 
1139
  }
 
1140
  wake_up_waiters(lock);
 
1141
  pthread_mutex_unlock(&lock->mutex);
 
1142
  DBUG_RETURN(found);
 
1143
}
 
1144
 
 
1145
 
 
1146
/*
 
1147
  Downgrade a WRITE_* to a lower WRITE level
 
1148
  SYNOPSIS
 
1149
    thr_downgrade_write_lock()
 
1150
    in_data                   Lock data of thread downgrading its lock
 
1151
    new_lock_type             New write lock type
 
1152
  RETURN VALUE
 
1153
    NONE
 
1154
  DESCRIPTION
 
1155
    This can be used to downgrade a lock already owned. When the downgrade
 
1156
    occurs also other waiters, both readers and writers can be allowed to
 
1157
    start.
 
1158
    The previous lock is often TL_WRITE_ONLY but can also be
 
1159
    TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
 
1160
    TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
 
1161
    TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
 
1162
    operation didn't need such a high lock.
 
1163
    TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
 
1164
    write table lock
 
1165
    TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
 
1166
    already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
 
1167
    The implementation is conservative and rather don't start rather than
 
1168
    go on unknown paths to start, the common cases are handled.
 
1169
 
 
1170
    NOTE:
 
1171
    In its current implementation it is only allowed to downgrade from
 
1172
    TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
 
1173
    logic is required.
 
1174
*/
 
1175
 
 
1176
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
 
1177
                              enum thr_lock_type new_lock_type)
 
1178
{
 
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");
 
1189
 
 
1190
  pthread_mutex_lock(&lock->mutex);
 
1191
  DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
 
1192
  DBUG_ASSERT(old_lock_type > new_lock_type);
 
1193
  in_data->type= new_lock_type;
 
1194
  check_locks(lock,"after downgrading lock",0);
 
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
 
1355
  pthread_mutex_unlock(&lock->mutex);
 
1356
  DBUG_VOID_RETURN;
 
1357
}
 
1358
 
 
1359
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
 
1360
 
 
1361
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
 
1362
{
 
1363
  THR_LOCK *lock=data->lock;
 
1364
  DBUG_ENTER("thr_upgrade_write_delay_lock");
 
1365
 
 
1366
  pthread_mutex_lock(&lock->mutex);
 
1367
  if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
 
1368
  {
 
1369
    pthread_mutex_unlock(&lock->mutex);
 
1370
    DBUG_RETURN(data->type == TL_UNLOCK);       /* Test if Aborted */
 
1371
  }
 
1372
  check_locks(lock,"before upgrading lock",0);
 
1373
  /* TODO:  Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
 
1374
  data->type=TL_WRITE;                          /* Upgrade lock */
 
1375
 
 
1376
  /* Check if someone has given us the lock */
 
1377
  if (!data->cond)
 
1378
  {
 
1379
    if (!lock->read.data)                       /* No read locks */
 
1380
    {                                           /* We have the lock */
 
1381
      if (data->lock->get_status)
 
1382
        (*data->lock->get_status)(data->status_param, 0);
 
1383
      pthread_mutex_unlock(&lock->mutex);
 
1384
      DBUG_RETURN(0);
 
1385
    }
 
1386
 
 
1387
    if (((*data->prev)=data->next))             /* remove from lock-list */
 
1388
      data->next->prev= data->prev;
 
1389
    else
 
1390
      lock->write.last=data->prev;
 
1391
 
 
1392
    if ((data->next=lock->write_wait.data))     /* Put first in lock_list */
 
1393
      data->next->prev= &data->next;
 
1394
    else
 
1395
      lock->write_wait.last= &data->next;
 
1396
    data->prev= &lock->write_wait.data;
 
1397
    lock->write_wait.data=data;
 
1398
    check_locks(lock,"upgrading lock",0);
 
1399
  }
 
1400
  else
 
1401
  {
 
1402
    check_locks(lock,"waiting for lock",0);
 
1403
  }
 
1404
  DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
 
1405
}
 
1406
 
 
1407
 
 
1408
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
 
1409
 
 
1410
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
 
1411
{
 
1412
  THR_LOCK *lock=data->lock;
 
1413
  DBUG_ENTER("thr_reschedule_write_lock");
 
1414
 
 
1415
  pthread_mutex_lock(&lock->mutex);
 
1416
  if (!lock->read_wait.data)                    /* No waiting read locks */
 
1417
  {
 
1418
    pthread_mutex_unlock(&lock->mutex);
 
1419
    DBUG_RETURN(0);
 
1420
  }
 
1421
 
 
1422
  data->type=TL_WRITE_DELAYED;
 
1423
  if (lock->update_status)
 
1424
    (*lock->update_status)(data->status_param);
 
1425
  if (((*data->prev)=data->next))               /* remove from lock-list */
 
1426
    data->next->prev= data->prev;
 
1427
  else
 
1428
    lock->write.last=data->prev;
 
1429
 
 
1430
  if ((data->next=lock->write_wait.data))       /* Put first in lock_list */
 
1431
    data->next->prev= &data->next;
 
1432
  else
 
1433
    lock->write_wait.last= &data->next;
 
1434
  data->prev= &lock->write_wait.data;
 
1435
  data->cond=get_cond();                        /* This was zero */
 
1436
  lock->write_wait.data=data;
 
1437
  free_all_read_locks(lock,0);
 
1438
 
 
1439
  pthread_mutex_unlock(&lock->mutex);
 
1440
  DBUG_RETURN(thr_upgrade_write_delay_lock(data));
 
1441
}
 
1442
 
 
1443
 
 
1444
#include <my_sys.h>
 
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
 
 
1507
/*****************************************************************************
 
1508
** Test of thread locks
 
1509
****************************************************************************/
 
1510
 
 
1511
#ifdef MAIN
 
1512
 
 
1513
#ifdef THREAD
 
1514
 
 
1515
struct st_test {
 
1516
  uint lock_nr;
 
1517
  enum thr_lock_type lock_type;
 
1518
};
 
1519
 
 
1520
THR_LOCK locks[5];                      /* 4 locks */
 
1521
 
 
1522
struct st_test test_0[] = {{0,TL_READ}};        /* One lock */
 
1523
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
 
1524
struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
 
1525
struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
 
1526
struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
 
1527
struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
 
1528
struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
 
1529
struct st_test test_7[] = {{3,TL_READ}};
 
1530
struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}};  /* Should be quick */
 
1531
struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
 
1532
struct st_test test_10[] ={{4,TL_WRITE}};
 
1533
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 */
 
1534
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 */
 
1535
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}};
 
1536
struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
 
1537
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
 
1538
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
 
1539
 
 
1540
struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
 
1541
                           test_7,test_8,test_9,test_10,test_11,test_12,
 
1542
                           test_13,test_14,test_15,test_16};
 
1543
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
 
1544
                    sizeof(test_1)/sizeof(struct st_test),
 
1545
                    sizeof(test_2)/sizeof(struct st_test),
 
1546
                    sizeof(test_3)/sizeof(struct st_test),
 
1547
                    sizeof(test_4)/sizeof(struct st_test),
 
1548
                    sizeof(test_5)/sizeof(struct st_test),
 
1549
                    sizeof(test_6)/sizeof(struct st_test),
 
1550
                    sizeof(test_7)/sizeof(struct st_test),
 
1551
                    sizeof(test_8)/sizeof(struct st_test),
 
1552
                    sizeof(test_9)/sizeof(struct st_test),
 
1553
                    sizeof(test_10)/sizeof(struct st_test),
 
1554
                    sizeof(test_11)/sizeof(struct st_test),
 
1555
                    sizeof(test_12)/sizeof(struct st_test),
 
1556
                    sizeof(test_13)/sizeof(struct st_test),
 
1557
                    sizeof(test_14)/sizeof(struct st_test),
 
1558
                    sizeof(test_15)/sizeof(struct st_test),
 
1559
                    sizeof(test_16)/sizeof(struct st_test)
 
1560
};
 
1561
 
 
1562
 
 
1563
static pthread_cond_t COND_thread_count;
 
1564
static pthread_mutex_t LOCK_thread_count;
 
1565
static uint thread_count;
 
1566
static ulong sum=0;
 
1567
 
 
1568
#define MAX_LOCK_COUNT 8
 
1569
 
 
1570
/* The following functions is for WRITE_CONCURRENT_INSERT */
 
1571
 
 
1572
static void test_get_status(void* param __attribute__((unused)),
 
1573
                            int concurrent_insert __attribute__((unused)))
 
1574
{
 
1575
}
 
1576
 
 
1577
static void test_update_status(void* param __attribute__((unused)))
 
1578
{
 
1579
}
 
1580
 
 
1581
static void test_copy_status(void* to __attribute__((unused)) ,
 
1582
                             void *from __attribute__((unused)))
 
1583
{
 
1584
}
 
1585
 
 
1586
static my_bool test_check_status(void* param __attribute__((unused)))
 
1587
{
 
1588
  return 0;
 
1589
}
 
1590
 
 
1591
 
 
1592
static void *test_thread(void *arg)
 
1593
{
 
1594
  int i,j,param=*((int*) arg);
 
1595
  THR_LOCK_DATA data[MAX_LOCK_COUNT];
 
1596
  THR_LOCK_OWNER owner;
 
1597
  THR_LOCK_INFO lock_info;
 
1598
  THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
 
1599
  my_thread_init();
 
1600
 
 
1601
  printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
 
1602
 
 
1603
 
 
1604
  thr_lock_info_init(&lock_info);
 
1605
  thr_lock_owner_init(&owner, &lock_info);
 
1606
  for (i=0; i < lock_counts[param] ; i++)
 
1607
    thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
 
1608
  for (j=1 ; j < 10 ; j++)              /* try locking 10 times */
 
1609
  {
 
1610
    for (i=0; i < lock_counts[param] ; i++)
 
1611
    {                                   /* Init multi locks */
 
1612
      multi_locks[i]= &data[i];
 
1613
      data[i].type= tests[param][i].lock_type;
 
1614
    }
 
1615
    thr_multi_lock(multi_locks, lock_counts[param], &owner);
 
1616
    pthread_mutex_lock(&LOCK_thread_count);
 
1617
    {
 
1618
      int tmp=rand() & 7;                       /* Do something from 0-2 sec */
 
1619
      if (tmp == 0)
 
1620
        sleep(1);
 
1621
      else if (tmp == 1)
 
1622
        sleep(2);
 
1623
      else
 
1624
      {
 
1625
        ulong k;
 
1626
        for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
 
1627
          sum+=k;
 
1628
      }
 
1629
    }
 
1630
    pthread_mutex_unlock(&LOCK_thread_count);
 
1631
    thr_multi_unlock(multi_locks,lock_counts[param]);
 
1632
  }
 
1633
 
 
1634
  printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
 
1635
  thr_print_locks();
 
1636
  pthread_mutex_lock(&LOCK_thread_count);
 
1637
  thread_count--;
 
1638
  VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
 
1639
  pthread_mutex_unlock(&LOCK_thread_count);
 
1640
  free((uchar*) arg);
 
1641
  return 0;
 
1642
}
 
1643
 
 
1644
 
 
1645
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
 
1646
{
 
1647
  pthread_t tid;
 
1648
  pthread_attr_t thr_attr;
 
1649
  int i,*param,error;
 
1650
  MY_INIT(argv[0]);
 
1651
  if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
 
1652
    DBUG_PUSH(argv[1]+2);
 
1653
 
 
1654
  printf("Main thread: %s\n",my_thread_name());
 
1655
 
 
1656
  if ((error=pthread_cond_init(&COND_thread_count,NULL)))
 
1657
  {
 
1658
    fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
 
1659
            error,errno);
 
1660
    exit(1);
 
1661
  }
 
1662
  if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST)))
 
1663
  {
 
1664
    fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
 
1665
            error,errno);
 
1666
    exit(1);
 
1667
  }
 
1668
 
 
1669
  for (i=0 ; i < (int) array_elements(locks) ; i++)
 
1670
  {
 
1671
    thr_lock_init(locks+i);
 
1672
    locks[i].check_status= test_check_status;
 
1673
    locks[i].update_status=test_update_status;
 
1674
    locks[i].copy_status=  test_copy_status;
 
1675
    locks[i].get_status=   test_get_status;
 
1676
  }
 
1677
  if ((error=pthread_attr_init(&thr_attr)))
 
1678
  {
 
1679
    fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
 
1680
            error,errno);
 
1681
    exit(1);
 
1682
  }
 
1683
  if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
 
1684
  {
 
1685
    fprintf(stderr,
 
1686
            "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
 
1687
            error,errno);
 
1688
    exit(1);
 
1689
  }
 
1690
#ifndef pthread_attr_setstacksize               /* void return value */
 
1691
  if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
 
1692
  {
 
1693
    fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
 
1694
            error,errno);
 
1695
    exit(1);
 
1696
  }
 
1697
#endif
 
1698
#ifdef HAVE_THR_SETCONCURRENCY
 
1699
  VOID(thr_setconcurrency(2));
 
1700
#endif
 
1701
  for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
 
1702
  {
 
1703
    param=(int*) malloc(sizeof(int));
 
1704
    *param=i;
 
1705
 
 
1706
    if ((error=pthread_mutex_lock(&LOCK_thread_count)))
 
1707
    {
 
1708
      fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
 
1709
              error,errno);
 
1710
      exit(1);
 
1711
    }
 
1712
    if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
 
1713
    {
 
1714
      fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
 
1715
              error,errno);
 
1716
      pthread_mutex_unlock(&LOCK_thread_count);
 
1717
      exit(1);
 
1718
    }
 
1719
    thread_count++;
 
1720
    pthread_mutex_unlock(&LOCK_thread_count);
 
1721
  }
 
1722
 
 
1723
  pthread_attr_destroy(&thr_attr);
 
1724
  if ((error=pthread_mutex_lock(&LOCK_thread_count)))
 
1725
    fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
 
1726
  while (thread_count)
 
1727
  {
 
1728
    if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
 
1729
      fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
 
1730
  }
 
1731
  if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
 
1732
    fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
 
1733
  for (i=0 ; i < (int) array_elements(locks) ; i++)
 
1734
    thr_lock_delete(locks+i);
 
1735
#ifdef EXTRA_DEBUG
 
1736
  if (found_errors)
 
1737
    printf("Got %d warnings\n",found_errors);
 
1738
  else
 
1739
#endif
 
1740
    printf("Test succeeded\n");
 
1741
  return 0;
 
1742
}
 
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 */
 
1753
#endif /* MAIN */