~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/thr_lock.c

  • Committer: Monty Taylor
  • Date: 2008-07-11 15:23:55 UTC
  • mto: (77.6.1 glibclient-merge)
  • mto: This revision was merged to the branch mainline in revision 134.
  • Revision ID: monty@inaugust.com-20080711152355-o92cod4mg0u9ck03
More const-correctness.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
TL_READ                 # Low priority read
28
28
TL_READ_WITH_SHARED_LOCKS
 
29
TL_READ_HIGH_PRIORITY   # High priority read
29
30
TL_READ_NO_INSERT       # Read without concurrent inserts
30
31
TL_WRITE_ALLOW_WRITE    # Write lock that allows other writers
31
32
TL_WRITE_ALLOW_READ     # Write lock, but allow reading
32
33
TL_WRITE_CONCURRENT_INSERT
33
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
34
38
TL_WRITE                # High priority write
35
39
TL_WRITE_ONLY           # High priority write
36
40
                        # Abort all new lock request with an error
46
50
should put a pointer to the following functions in the lock structure:
47
51
(If the pointer is zero (default), the function is not called)
48
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.
49
66
 
50
67
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
51
 
TL_WRITE_CONCURRENT_INSERT lock at the same time as multiple read locks.
 
68
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
 
69
multiple read locks.
52
70
 
53
71
*/
54
72
 
55
 
#include "config.h"
56
 
#include "drizzled/internal/my_sys.h"
57
 
#include "drizzled/internal/thread_var.h"
58
 
#include "drizzled/statistics_variables.h"
 
73
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
 
74
#define FORCE_DBUG_OFF
 
75
#endif
59
76
 
60
 
#include "drizzled/session.h"
61
 
#include "drizzled/current_session.h"
 
77
#include "mysys_priv.h"
62
78
 
63
79
#include "thr_lock.h"
64
 
#include "drizzled/internal/m_string.h"
 
80
#include <m_string.h>
65
81
#include <errno.h>
66
 
#include <list>
67
 
 
68
 
#if TIME_WITH_SYS_TIME
69
 
# include <sys/time.h>
70
 
# include <time.h>
71
 
#else
72
 
# if HAVE_SYS_TIME_H
73
 
#  include <sys/time.h>
74
 
# else
75
 
#  include <time.h>
76
 
# endif
77
 
#endif
78
 
 
79
 
#include <drizzled/util/test.h>
80
 
 
81
 
using namespace std;
82
 
 
83
 
namespace drizzled
 
82
 
 
83
my_bool thr_lock_inited=0;
 
84
ulong locks_immediate = 0L, locks_waited = 0L;
 
85
ulong table_lock_wait_timeout;
 
86
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
 
87
 
 
88
/* The following constants are only for debug output */
 
89
#define MAX_THREADS 100
 
90
#define MAX_LOCKS   100
 
91
 
 
92
 
 
93
LIST *thr_lock_thread_list;                     /* List of threads in use */
 
94
ulong max_write_lock_count= ~(ulong) 0L;
 
95
 
 
96
static inline pthread_cond_t *get_cond(void)
84
97
{
85
 
 
86
 
uint64_t table_lock_wait_timeout;
87
 
static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
88
 
 
89
 
 
90
 
uint64_t max_write_lock_count= ~(uint64_t) 0L;
 
98
  return &my_thread_var->suspend;
 
99
}
91
100
 
92
101
/*
93
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
94
103
*/
95
104
 
96
 
static inline bool
 
105
my_bool init_thr_lock()
 
106
{
 
107
  thr_lock_inited=1;
 
108
  return 0;
 
109
}
 
110
 
 
111
static inline my_bool
97
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
98
113
{
99
114
  return rhs == lhs;
100
115
}
101
116
 
102
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
 
103
311
        /* Initialize a lock */
104
312
 
105
313
void thr_lock_init(THR_LOCK *lock)
106
314
{
107
 
  lock->init();
 
315
  DBUG_ENTER("thr_lock_init");
 
316
  bzero((char*) lock,sizeof(*lock));
 
317
  VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
108
318
  lock->read.last= &lock->read.data;
109
319
  lock->read_wait.last= &lock->read_wait.data;
110
320
  lock->write_wait.last= &lock->write_wait.data;
111
321
  lock->write.last= &lock->write.data;
112
 
}
113
 
 
114
 
 
115
 
void THR_LOCK_INFO::init()
116
 
{
117
 
  internal::st_my_thread_var *tmp= my_thread_var;
118
 
  thread= tmp->pthread_self;
119
 
  thread_id= tmp->id;
120
 
  n_cursors= 0;
 
322
 
 
323
  pthread_mutex_lock(&THR_LOCK_lock);           /* Add to locks in use */
 
324
  lock->list.data=(void*) lock;
 
325
  thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list);
 
326
  pthread_mutex_unlock(&THR_LOCK_lock);
 
327
  DBUG_VOID_RETURN;
 
328
}
 
329
 
 
330
 
 
331
void thr_lock_delete(THR_LOCK *lock)
 
332
{
 
333
  DBUG_ENTER("thr_lock_delete");
 
334
  VOID(pthread_mutex_destroy(&lock->mutex));
 
335
  pthread_mutex_lock(&THR_LOCK_lock);
 
336
  thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
 
337
  pthread_mutex_unlock(&THR_LOCK_lock);
 
338
  DBUG_VOID_RETURN;
 
339
}
 
340
 
 
341
 
 
342
void thr_lock_info_init(THR_LOCK_INFO *info)
 
343
{
 
344
  struct st_my_thread_var *tmp= my_thread_var;
 
345
  info->thread=    tmp->pthread_self;
 
346
  info->thread_id= tmp->id;
 
347
  info->n_cursors= 0;
121
348
}
122
349
 
123
350
        /* Initialize a lock instance */
124
351
 
125
 
void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
 
352
void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
126
353
{
127
 
  lock= lock_arg;
128
 
  type= TL_UNLOCK;
129
 
  owner= NULL;                               /* no owner yet */
130
 
  status_param= param_arg;
131
 
  cond= NULL;
 
354
  data->lock=lock;
 
355
  data->type=TL_UNLOCK;
 
356
  data->owner= 0;                               /* no owner yet */
 
357
  data->status_param=param;
 
358
  data->cond=0;
132
359
}
133
360
 
134
361
 
135
 
static inline bool
 
362
static inline my_bool
136
363
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
137
364
{
138
365
  for ( ; data ; data=data->next)
139
366
  {
140
367
    if (thr_lock_owner_equal(data->owner, owner))
141
 
      return true;                                      /* Already locked by thread */
142
 
  }
143
 
  return false;
144
 
}
 
368
      return 1;                                 /* Already locked by thread */
 
369
  }
 
370
  return 0;
 
371
}
 
372
 
 
373
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
 
374
                                         enum thr_lock_type type)
 
375
{
 
376
  for ( ; data ; data=data->next)
 
377
  {
 
378
    if (data->type == type)
 
379
      return 1;
 
380
  }
 
381
  return 0;
 
382
}
 
383
 
145
384
 
146
385
static void wake_up_waiters(THR_LOCK *lock);
147
386
 
148
387
 
149
 
static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, bool in_wait_list)
 
388
static enum enum_thr_lock_result
 
389
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
 
390
              my_bool in_wait_list)
150
391
{
151
 
  Session *session= current_session;
152
 
  internal::st_my_thread_var *thread_var= session->getThreadVar();
153
 
 
154
 
  boost::condition_variable *cond= &thread_var->suspend;
 
392
  struct st_my_thread_var *thread_var= my_thread_var;
 
393
  pthread_cond_t *cond= &thread_var->suspend;
155
394
  struct timespec wait_timeout;
156
395
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
157
 
  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");
158
398
 
159
399
  if (!in_wait_list)
160
400
  {
163
403
    wait->last= &data->next;
164
404
  }
165
405
 
166
 
  current_global_counters.locks_waited++;
 
406
  statistic_increment(locks_waited, &THR_LOCK_lock);
167
407
 
168
408
  /* Set up control struct to allow others to abort locks */
169
 
  thread_var->current_mutex= data->lock->native_handle();
170
 
  thread_var->current_cond=  &thread_var->suspend;
171
 
  data->cond= &thread_var->suspend;;
 
409
  thread_var->current_mutex= &data->lock->mutex;
 
410
  thread_var->current_cond=  cond;
 
411
  data->cond= cond;
172
412
 
173
413
  if (can_deadlock)
174
414
    set_timespec(wait_timeout, table_lock_wait_timeout);
175
415
  while (!thread_var->abort || in_wait_list)
176
416
  {
177
417
    int rc= (can_deadlock ?
178
 
             pthread_cond_timedwait(cond->native_handle(), data->lock->native_handle()->native_handle(), &wait_timeout) :
179
 
             pthread_cond_wait(cond->native_handle(), data->lock->native_handle()->native_handle()));
 
418
             pthread_cond_timedwait(cond, &data->lock->mutex,
 
419
                                    &wait_timeout) :
 
420
             pthread_cond_wait(cond, &data->lock->mutex));
180
421
    /*
181
422
      We must break the wait if one of the following occurs:
182
423
      - the connection has been aborted (!thread_var->abort), but
190
431
      Order of checks below is important to not report about timeout
191
432
      if the predicate is true.
192
433
    */
193
 
    if (data->cond == NULL)
 
434
    if (data->cond == 0)
194
435
    {
 
436
      DBUG_PRINT("thr_lock", ("lock granted/aborted"));
195
437
      break;
196
438
    }
197
439
    if (rc == ETIMEDOUT || rc == ETIME)
198
440
    {
 
441
      /* purecov: begin inspected */
 
442
      DBUG_PRINT("thr_lock", ("lock timed out"));
199
443
      result= THR_LOCK_WAIT_TIMEOUT;
200
444
      break;
 
445
      /* purecov: end */
201
446
    }
202
447
  }
 
448
  DBUG_PRINT("thr_lock", ("aborted: %d  in_wait_list: %d",
 
449
                          thread_var->abort, in_wait_list));
 
450
 
203
451
  if (data->cond || data->type == TL_UNLOCK)
204
452
  {
205
453
    if (data->cond)                             /* aborted or timed out */
209
457
      else
210
458
        wait->last=data->prev;
211
459
      data->type= TL_UNLOCK;                    /* No lock */
 
460
      check_locks(data->lock, "killed or timed out wait_for_lock", 1);
212
461
      wake_up_waiters(data->lock);
213
462
    }
 
463
    else
 
464
    {
 
465
      DBUG_PRINT("thr_lock", ("lock aborted"));
 
466
      check_locks(data->lock, "aborted wait_for_lock", 0);
 
467
    }
214
468
  }
215
469
  else
216
470
  {
217
471
    result= THR_LOCK_SUCCESS;
 
472
    if (data->lock->get_status)
 
473
      (*data->lock->get_status)(data->status_param, 0);
 
474
    check_locks(data->lock,"got wait_for_lock",0);
218
475
  }
219
 
  data->lock->unlock();
 
476
  pthread_mutex_unlock(&data->lock->mutex);
220
477
 
221
478
  /* The following must be done after unlock of lock->mutex */
222
 
  boost::mutex::scoped_lock scopedLock(thread_var->mutex);
223
 
  thread_var->current_mutex= NULL;
224
 
  thread_var->current_cond= NULL;
225
 
  return(result);
 
479
  pthread_mutex_lock(&thread_var->mutex);
 
480
  thread_var->current_mutex= 0;
 
481
  thread_var->current_cond=  0;
 
482
  pthread_mutex_unlock(&thread_var->mutex);
 
483
  DBUG_RETURN(result);
226
484
}
227
485
 
228
486
 
229
 
static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
 
487
enum enum_thr_lock_result
 
488
thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
 
489
         enum thr_lock_type lock_type)
230
490
{
231
 
  THR_LOCK *lock= data->lock;
 
491
  THR_LOCK *lock=data->lock;
232
492
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
233
493
  struct st_lock_list *wait_queue;
234
494
  THR_LOCK_DATA *lock_owner;
 
495
  DBUG_ENTER("thr_lock");
235
496
 
236
497
  data->next=0;
237
498
  data->cond=0;                                 /* safety */
238
499
  data->type=lock_type;
239
500
  data->owner= owner;                           /* Must be reset ! */
240
 
  lock->lock();
 
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);
241
507
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
242
508
  {
243
509
    /* Request for READ lock */
252
518
           and the read lock is not TL_READ_NO_INSERT
253
519
      */
254
520
 
 
521
      DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",
 
522
                         lock->write.data->owner->info->thread_id));
255
523
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
256
 
          (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
257
 
           (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
 
524
          (lock->write.data->type <= TL_WRITE_DELAYED &&
 
525
           (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
258
526
            (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
259
527
             lock->write.data->type != TL_WRITE_ALLOW_READ))))
260
528
      {                                         /* Already got a write lock */
263
531
        lock->read.last= &data->next;
264
532
        if (lock_type == TL_READ_NO_INSERT)
265
533
          lock->read_no_write_count++;
266
 
        current_global_counters.locks_immediate++;
 
534
        check_locks(lock,"read lock with old write lock",0);
 
535
        if (lock->get_status)
 
536
          (*lock->get_status)(data->status_param, 0);
 
537
        statistic_increment(locks_immediate,&THR_LOCK_lock);
267
538
        goto end;
268
539
      }
269
540
      if (lock->write.data->type == TL_WRITE_ONLY)
275
546
      }
276
547
    }
277
548
    else if (!lock->write_wait.data ||
278
 
             lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
 
549
             lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
 
550
             lock_type == TL_READ_HIGH_PRIORITY ||
279
551
             have_old_read_lock(lock->read.data, data->owner))
280
552
    {                                           /* No important write-locks */
281
553
      (*lock->read.last)=data;                  /* Add to running FIFO */
282
554
      data->prev=lock->read.last;
283
555
      lock->read.last= &data->next;
 
556
      if (lock->get_status)
 
557
        (*lock->get_status)(data->status_param, 0);
284
558
      if (lock_type == TL_READ_NO_INSERT)
285
559
        lock->read_no_write_count++;
286
 
      current_global_counters.locks_immediate++;
 
560
      check_locks(lock,"read lock with no write locks",0);
 
561
      statistic_increment(locks_immediate,&THR_LOCK_lock);
287
562
      goto end;
288
563
    }
289
564
    /*
295
570
  }
296
571
  else                                          /* Request for WRITE lock */
297
572
  {
298
 
    if (lock_type == TL_WRITE_CONCURRENT_INSERT)
 
573
    if (lock_type == TL_WRITE_DELAYED)
 
574
    {
 
575
      if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
 
576
      {
 
577
        data->type=TL_UNLOCK;
 
578
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
 
579
        goto end;
 
580
      }
 
581
      /*
 
582
        if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
 
583
        (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
 
584
      */
 
585
      if ((!lock->write.data ||
 
586
           lock->write.data->type != TL_WRITE_ALLOW_READ) &&
 
587
          !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
 
588
          (lock->write.data || lock->read.data))
 
589
      {
 
590
        /* Add delayed write lock to write_wait queue, and return at once */
 
591
        (*lock->write_wait.last)=data;
 
592
        data->prev=lock->write_wait.last;
 
593
        lock->write_wait.last= &data->next;
 
594
        data->cond=get_cond();
 
595
        /*
 
596
          We don't have to do get_status here as we will do it when we change
 
597
          the delayed lock to a real write lock
 
598
        */
 
599
        statistic_increment(locks_immediate,&THR_LOCK_lock);
 
600
        goto end;
 
601
      }
 
602
    }
 
603
    else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
299
604
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;
300
605
 
301
606
    if (lock->write.data)                       /* If there is a write lock */
326
631
          We have already got a write lock or all locks are
327
632
          TL_WRITE_ALLOW_WRITE
328
633
        */
 
634
        DBUG_PRINT("info", ("write_wait.data: 0x%lx  old_type: %d",
 
635
                            (ulong) lock->write_wait.data,
 
636
                            lock->write.data->type));
329
637
 
330
638
        (*lock->write.last)=data;       /* Add to running fifo */
331
639
        data->prev=lock->write.last;
332
640
        lock->write.last= &data->next;
333
 
        current_global_counters.locks_immediate++;
 
641
        check_locks(lock,"second write lock",0);
 
642
        if (data->lock->get_status)
 
643
          (*data->lock->get_status)(data->status_param, 0);
 
644
        statistic_increment(locks_immediate,&THR_LOCK_lock);
334
645
        goto end;
335
646
      }
 
647
      DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx",
 
648
                         lock->write.data->owner->info->thread_id));
336
649
    }
337
650
    else
338
651
    {
 
652
      DBUG_PRINT("info", ("write_wait.data: 0x%lx",
 
653
                          (ulong) lock->write_wait.data));
339
654
      if (!lock->write_wait.data)
340
655
      {                                         /* no scheduled write locks */
341
 
        bool concurrent_insert= 0;
 
656
        my_bool concurrent_insert= 0;
342
657
        if (lock_type == TL_WRITE_CONCURRENT_INSERT)
343
658
        {
344
659
          concurrent_insert= 1;
 
660
          if ((*lock->check_status)(data->status_param))
 
661
          {
 
662
            concurrent_insert= 0;
 
663
            data->type=lock_type= thr_upgraded_concurrent_insert_lock;
 
664
          }
345
665
        }
346
666
 
347
667
        if (!lock->read.data ||
348
 
            (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
 
668
            (lock_type <= TL_WRITE_DELAYED &&
349
669
             ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
350
670
               lock_type != TL_WRITE_ALLOW_WRITE) ||
351
671
              !lock->read_no_write_count)))
353
673
          (*lock->write.last)=data;             /* Add as current write lock */
354
674
          data->prev=lock->write.last;
355
675
          lock->write.last= &data->next;
356
 
          current_global_counters.locks_immediate++;
 
676
          if (data->lock->get_status)
 
677
            (*data->lock->get_status)(data->status_param, concurrent_insert);
 
678
          check_locks(lock,"only write lock",0);
 
679
          statistic_increment(locks_immediate,&THR_LOCK_lock);
357
680
          goto end;
358
681
        }
359
682
      }
 
683
      DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx  type: %d",
 
684
                         lock->read.data->owner->info->thread_id, data->type));
360
685
    }
361
686
    wait_queue= &lock->write_wait;
362
687
  }
369
694
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
370
695
  if (lock_owner && lock_owner->owner->info == owner->info)
371
696
  {
 
697
    DBUG_PRINT("lock",("deadlock"));
372
698
    result= THR_LOCK_DEADLOCK;
373
699
    goto end;
374
700
  }
375
 
 
376
701
  /* Can't get lock yet;  Wait for it */
377
 
  return(wait_for_lock(wait_queue, data, 0));
 
702
  DBUG_RETURN(wait_for_lock(wait_queue, data, 0));
378
703
end:
379
 
  lock->unlock();
380
 
 
381
 
  return(result);
 
704
  pthread_mutex_unlock(&lock->mutex);
 
705
  DBUG_RETURN(result);
382
706
}
383
707
 
384
708
 
385
 
static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
 
709
static inline void free_all_read_locks(THR_LOCK *lock,
 
710
                                       my_bool using_concurrent_insert)
386
711
{
387
 
  THR_LOCK_DATA *data= lock->read_wait.data;
 
712
  THR_LOCK_DATA *data=lock->read_wait.data;
 
713
 
 
714
  check_locks(lock,"before freeing read locks",1);
388
715
 
389
716
  /* move all locks from read_wait list to read list */
390
717
  (*lock->read.last)=data;
396
723
 
397
724
  do
398
725
  {
399
 
    boost::condition_variable *cond= data->cond;
 
726
    pthread_cond_t *cond=data->cond;
400
727
    if ((int) data->type == (int) TL_READ_NO_INSERT)
401
728
    {
402
729
      if (using_concurrent_insert)
403
730
      {
404
731
        /*
405
 
          We can't free this lock;
 
732
          We can't free this lock; 
406
733
          Link lock away from read chain back into read_wait chain
407
734
        */
408
735
        if (((*data->prev)=data->next))
415
742
        continue;
416
743
      }
417
744
      lock->read_no_write_count++;
418
 
    }
419
 
    data->cond= NULL;                           /* Mark thread free */
420
 
    cond->notify_one();
 
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 */
 
750
    data->cond=0;                               /* Mark thread free */
 
751
    VOID(pthread_cond_signal(cond));
421
752
  } while ((data=data->next));
422
753
  *lock->read_wait.last=0;
423
754
  if (!lock->read_wait.data)
424
755
    lock->write_lock_count=0;
 
756
  check_locks(lock,"after giving read locks",0);
425
757
}
426
758
 
427
 
/* Unlock lock and free next thread on same lock */
 
759
        /* Unlock lock and free next thread on same lock */
428
760
 
429
 
static void thr_unlock(THR_LOCK_DATA *data)
 
761
void thr_unlock(THR_LOCK_DATA *data)
430
762
{
431
763
  THR_LOCK *lock=data->lock;
432
764
  enum thr_lock_type lock_type=data->type;
433
 
  lock->lock();
 
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));
 
768
  pthread_mutex_lock(&lock->mutex);
 
769
  check_locks(lock,"start of release lock",0);
434
770
 
435
771
  if (((*data->prev)=data->next))               /* remove from lock-list */
436
772
    data->next->prev= data->prev;
437
773
  else if (lock_type <= TL_READ_NO_INSERT)
438
774
    lock->read.last=data->prev;
 
775
  else if (lock_type == TL_WRITE_DELAYED && data->cond)
 
776
  {
 
777
    /*
 
778
      This only happens in extreme circumstances when a 
 
779
      write delayed lock that is waiting for a lock
 
780
    */
 
781
    lock->write_wait.last=data->prev;           /* Put it on wait queue */
 
782
  }
439
783
  else
440
784
    lock->write.last=data->prev;
441
785
  if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
442
 
  { }
 
786
  {
 
787
    if (lock->update_status)
 
788
      (*lock->update_status)(data->status_param);
 
789
  }
443
790
  else
444
 
  { }
 
791
  {
 
792
    if (lock->restore_status)
 
793
      (*lock->restore_status)(data->status_param);
 
794
  }
445
795
  if (lock_type == TL_READ_NO_INSERT)
446
796
    lock->read_no_write_count--;
447
797
  data->type=TL_UNLOCK;                         /* Mark unlocked */
 
798
  check_locks(lock,"after releasing lock",1);
448
799
  wake_up_waiters(lock);
449
 
  lock->unlock();
 
800
  pthread_mutex_unlock(&lock->mutex);
 
801
  DBUG_VOID_RETURN;
450
802
}
451
803
 
452
804
 
463
815
  THR_LOCK_DATA *data;
464
816
  enum thr_lock_type lock_type;
465
817
 
 
818
  DBUG_ENTER("wake_up_waiters");
 
819
 
466
820
  if (!lock->write.data)                        /* If no active write locks */
467
821
  {
468
822
    data=lock->write_wait.data;
470
824
    {
471
825
      /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
472
826
      if (data &&
473
 
          (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
 
827
          (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
 
828
           lock->read_wait.data->type < TL_READ_HIGH_PRIORITY))
474
829
      {
475
830
        if (lock->write_lock_count++ > max_write_lock_count)
476
831
        {
478
833
          lock->write_lock_count=0;
479
834
          if (lock->read_wait.data)
480
835
          {
 
836
            DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
481
837
            free_all_read_locks(lock,0);
482
838
            goto end;
483
839
          }
492
848
          data->prev=lock->write.last;
493
849
          data->next=0;
494
850
          lock->write.last= &data->next;
495
 
 
 
851
          if (data->type == TL_WRITE_CONCURRENT_INSERT &&
 
852
              (*lock->check_status)(data->status_param))
 
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 */
496
858
          {
497
 
            boost::condition_variable *cond= data->cond;
498
 
            data->cond= NULL;                           /* Mark thread free */
499
 
            cond->notify_one(); /* Start waiting thred */
 
859
            pthread_cond_t *cond=data->cond;
 
860
            data->cond=0;                               /* Mark thread free */
 
861
            VOID(pthread_cond_signal(cond));    /* Start waiting thread */
500
862
          }
501
863
          if (data->type != TL_WRITE_ALLOW_WRITE ||
502
864
              !lock->write_wait.data ||
504
866
            break;
505
867
          data=lock->write_wait.data;           /* Free this too */
506
868
        }
507
 
        if (data->type >= TL_WRITE)
 
869
        if (data->type >= TL_WRITE_LOW_PRIORITY)
508
870
          goto end;
509
871
        /* Release possible read locks together with the write lock */
510
872
      }
513
875
                            data &&
514
876
                            (data->type == TL_WRITE_CONCURRENT_INSERT ||
515
877
                             data->type == TL_WRITE_ALLOW_WRITE));
 
878
      else
 
879
      {
 
880
        DBUG_PRINT("lock",("No waiting read locks to free"));
 
881
      }
516
882
    }
517
883
    else if (data &&
518
 
             (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
 
884
             (lock_type=data->type) <= TL_WRITE_DELAYED &&
519
885
             ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
520
886
               lock_type != TL_WRITE_ALLOW_WRITE) ||
521
887
              !lock->read_no_write_count))
522
888
    {
 
889
      /*
 
890
        For DELAYED, ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks
 
891
        start WRITE locks together with the READ locks
 
892
      */
 
893
      if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
 
894
          (*lock->check_status)(data->status_param))
 
895
      {
 
896
        data->type=TL_WRITE;                    /* Upgrade lock */
 
897
        if (lock->read_wait.data)
 
898
          free_all_read_locks(lock,0);
 
899
        goto end;
 
900
      }
523
901
      do {
524
 
        boost::condition_variable *cond= data->cond;
 
902
        pthread_cond_t *cond=data->cond;
525
903
        if (((*data->prev)=data->next))         /* remove from wait-list */
526
904
          data->next->prev= data->prev;
527
905
        else
530
908
        data->prev=lock->write.last;
531
909
        lock->write.last= &data->next;
532
910
        data->next=0;                           /* Only one write lock */
533
 
        data->cond= NULL;                               /* Mark thread free */
534
 
        cond->notify_one(); /* Start waiting thread */
 
911
        data->cond=0;                           /* Mark thread free */
 
912
        VOID(pthread_cond_signal(cond));        /* Start waiting thread */
535
913
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
536
914
               (data=lock->write_wait.data) &&
537
915
               data->type == TL_WRITE_ALLOW_WRITE);
541
919
                             lock_type == TL_WRITE_ALLOW_WRITE));
542
920
    }
543
921
    else if (!data && lock->read_wait.data)
544
 
    {
545
922
      free_all_read_locks(lock,0);
546
 
    }
547
923
  }
548
924
end:
549
 
  return;
 
925
  check_locks(lock, "after waking up waiters", 0);
 
926
  DBUG_VOID_RETURN;
550
927
}
551
928
 
552
929
 
557
934
*/
558
935
 
559
936
 
560
 
#define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint32_t) ((A)->type) < (unsigned char*) (B->lock)- (uint32_t) ((B)->type))
 
937
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
561
938
 
562
 
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
 
939
static void sort_locks(THR_LOCK_DATA **data,uint count)
563
940
{
564
941
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
565
942
 
581
958
 
582
959
 
583
960
enum enum_thr_lock_result
584
 
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)
585
962
{
586
963
  THR_LOCK_DATA **pos,**end;
 
964
  DBUG_ENTER("thr_multi_lock");
 
965
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
587
966
  if (count > 1)
588
967
    sort_locks(data,count);
589
968
  /* lock everything */
592
971
    enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
593
972
    if (result != THR_LOCK_SUCCESS)
594
973
    {                                           /* Aborted */
595
 
      thr_multi_unlock(data,(uint32_t) (pos-data));
596
 
      return(result);
 
974
      thr_multi_unlock(data,(uint) (pos-data));
 
975
      DBUG_RETURN(result);
597
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
598
981
  }
599
982
  /*
600
983
    Ensure that all get_locks() have the same status
609
992
    do
610
993
    {
611
994
      pos--;
612
 
      last_lock=(*pos);
 
995
      if (last_lock->lock == (*pos)->lock &&
 
996
          last_lock->lock->copy_status)
 
997
      {
 
998
        if (last_lock->type <= TL_READ_NO_INSERT)
 
999
        {
 
1000
          THR_LOCK_DATA **read_lock;
 
1001
          /*
 
1002
            If we are locking the same table with read locks we must ensure
 
1003
            that all tables share the status of the last write lock or
 
1004
            the same read lock.
 
1005
          */
 
1006
          for (;
 
1007
               (*pos)->type <= TL_READ_NO_INSERT &&
 
1008
                 pos != data &&
 
1009
                 pos[-1]->lock == (*pos)->lock ;
 
1010
               pos--) ;
 
1011
 
 
1012
          read_lock = pos+1;
 
1013
          do
 
1014
          {
 
1015
            (last_lock->lock->copy_status)((*read_lock)->status_param,
 
1016
                                           (*pos)->status_param);
 
1017
          } while (*(read_lock++) != last_lock);
 
1018
          last_lock= (*pos);                    /* Point at last write lock */
 
1019
        }
 
1020
        else
 
1021
          (*last_lock->lock->copy_status)((*pos)->status_param,
 
1022
                                          last_lock->status_param);
 
1023
      }
 
1024
      else
 
1025
        last_lock=(*pos);
613
1026
    } while (pos != data);
614
1027
  }
615
1028
#endif
616
 
  return(THR_LOCK_SUCCESS);
 
1029
  DBUG_RETURN(THR_LOCK_SUCCESS);
617
1030
}
618
1031
 
619
1032
  /* free all locks */
620
1033
 
621
 
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
 
1034
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
622
1035
{
623
1036
  THR_LOCK_DATA **pos,**end;
 
1037
  DBUG_ENTER("thr_multi_unlock");
 
1038
  DBUG_PRINT("lock",("data: 0x%lx  count: %d", (long) data, count));
624
1039
 
625
1040
  for (pos=data,end=data+count; pos < end ; pos++)
626
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
627
1047
    if ((*pos)->type != TL_UNLOCK)
628
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
    }
629
1055
  }
630
 
  return;
 
1056
  DBUG_VOID_RETURN;
631
1057
}
632
1058
 
633
1059
/*
635
1061
  TL_WRITE_ONLY to abort any new accesses to the lock
636
1062
*/
637
1063
 
638
 
void THR_LOCK::abort_locks()
 
1064
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock)
639
1065
{
640
 
  boost::mutex::scoped_lock scopedLock(mutex);
 
1066
  THR_LOCK_DATA *data;
 
1067
  DBUG_ENTER("thr_abort_locks");
 
1068
  pthread_mutex_lock(&lock->mutex);
641
1069
 
642
 
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
 
1070
  for (data=lock->read_wait.data; data ; data=data->next)
643
1071
  {
644
 
    local_data->type= TL_UNLOCK;                        /* Mark killed */
 
1072
    data->type=TL_UNLOCK;                       /* Mark killed */
645
1073
    /* It's safe to signal the cond first: we're still holding the mutex. */
646
 
    local_data->cond->notify_one();
647
 
    local_data->cond= NULL;                             /* Removed from list */
 
1074
    pthread_cond_signal(data->cond);
 
1075
    data->cond=0;                               /* Removed from list */
648
1076
  }
649
 
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
 
1077
  for (data=lock->write_wait.data; data ; data=data->next)
650
1078
  {
651
 
    local_data->type= TL_UNLOCK;
652
 
    local_data->cond->notify_one();
653
 
    local_data->cond= NULL;
 
1079
    data->type=TL_UNLOCK;
 
1080
    pthread_cond_signal(data->cond);
 
1081
    data->cond=0;
654
1082
  }
655
 
  read_wait.last= &read_wait.data;
656
 
  write_wait.last= &write_wait.data;
657
 
  read_wait.data= write_wait.data=0;
658
 
  if (write.data)
659
 
    write.data->type=TL_WRITE_ONLY;
 
1083
  lock->read_wait.last= &lock->read_wait.data;
 
1084
  lock->write_wait.last= &lock->write_wait.data;
 
1085
  lock->read_wait.data=lock->write_wait.data=0;
 
1086
  if (upgrade_lock && lock->write.data)
 
1087
    lock->write.data->type=TL_WRITE_ONLY;
 
1088
  pthread_mutex_unlock(&lock->mutex);
 
1089
  DBUG_VOID_RETURN;
660
1090
}
661
1091
 
662
1092
 
666
1096
  This is used to abort all locks for a specific thread
667
1097
*/
668
1098
 
669
 
bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
 
1099
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
670
1100
{
671
 
  bool found= false;
 
1101
  THR_LOCK_DATA *data;
 
1102
  my_bool found= FALSE;
 
1103
  DBUG_ENTER("thr_abort_locks_for_thread");
672
1104
 
673
 
  boost::mutex::scoped_lock scopedLock(mutex);
674
 
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
 
1105
  pthread_mutex_lock(&lock->mutex);
 
1106
  for (data= lock->read_wait.data; data ; data= data->next)
675
1107
  {
676
 
    if (local_data->owner->info->thread_id == thread_id_arg)
 
1108
    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
677
1109
    {
678
 
      local_data->type= TL_UNLOCK;                      /* Mark killed */
 
1110
      DBUG_PRINT("info",("Aborting read-wait lock"));
 
1111
      data->type= TL_UNLOCK;                    /* Mark killed */
679
1112
      /* It's safe to signal the cond first: we're still holding the mutex. */
680
 
      found= true;
681
 
      local_data->cond->notify_one();
682
 
      local_data->cond= 0;                              /* Removed from list */
683
 
 
684
 
      if (((*local_data->prev)= local_data->next))
685
 
        local_data->next->prev= local_data->prev;
686
 
      else
687
 
        read_wait.last= local_data->prev;
688
 
    }
689
 
  }
690
 
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
691
 
  {
692
 
    if (local_data->owner->info->thread_id == thread_id_arg)
693
 
    {
694
 
      local_data->type= TL_UNLOCK;
695
 
      found= true;
696
 
      local_data->cond->notify_one();
697
 
      local_data->cond= NULL;
698
 
 
699
 
      if (((*local_data->prev)= local_data->next))
700
 
        local_data->next->prev= local_data->prev;
701
 
      else
702
 
        write_wait.last= local_data->prev;
703
 
    }
704
 
  }
705
 
  wake_up_waiters(this);
706
 
 
707
 
  return found;
708
 
}
709
 
 
710
 
} /* namespace drizzled */
 
1113
      found= TRUE;
 
1114
      pthread_cond_signal(data->cond);
 
1115
      data->cond= 0;                            /* Removed from list */
 
1116
 
 
1117
      if (((*data->prev)= data->next))
 
1118
        data->next->prev= data->prev;
 
1119
      else
 
1120
        lock->read_wait.last= data->prev;
 
1121
    }
 
1122
  }
 
1123
  for (data= lock->write_wait.data; data ; data= data->next)
 
1124
  {
 
1125
    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
 
1126
    {
 
1127
      DBUG_PRINT("info",("Aborting write-wait lock"));
 
1128
      data->type= TL_UNLOCK;
 
1129
      found= TRUE;
 
1130
      pthread_cond_signal(data->cond);
 
1131
      data->cond= 0;
 
1132
 
 
1133
      if (((*data->prev)= data->next))
 
1134
        data->next->prev= data->prev;
 
1135
      else
 
1136
        lock->write_wait.last= data->prev;
 
1137
    }
 
1138
  }
 
1139
  wake_up_waiters(lock);
 
1140
  pthread_mutex_unlock(&lock->mutex);
 
1141
  DBUG_RETURN(found);
 
1142
}
 
1143
 
 
1144
 
 
1145
/*
 
1146
  Downgrade a WRITE_* to a lower WRITE level
 
1147
  SYNOPSIS
 
1148
    thr_downgrade_write_lock()
 
1149
    in_data                   Lock data of thread downgrading its lock
 
1150
    new_lock_type             New write lock type
 
1151
  RETURN VALUE
 
1152
    NONE
 
1153
  DESCRIPTION
 
1154
    This can be used to downgrade a lock already owned. When the downgrade
 
1155
    occurs also other waiters, both readers and writers can be allowed to
 
1156
    start.
 
1157
    The previous lock is often TL_WRITE_ONLY but can also be
 
1158
    TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
 
1159
    TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
 
1160
    TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
 
1161
    operation didn't need such a high lock.
 
1162
    TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
 
1163
    write table lock
 
1164
    TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
 
1165
    already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
 
1166
    The implementation is conservative and rather don't start rather than
 
1167
    go on unknown paths to start, the common cases are handled.
 
1168
 
 
1169
    NOTE:
 
1170
    In its current implementation it is only allowed to downgrade from
 
1171
    TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
 
1172
    logic is required.
 
1173
*/
 
1174
 
 
1175
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
 
1176
                              enum thr_lock_type new_lock_type)
 
1177
{
 
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");
 
1183
 
 
1184
  pthread_mutex_lock(&lock->mutex);
 
1185
  DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
 
1186
  DBUG_ASSERT(old_lock_type > new_lock_type);
 
1187
  in_data->type= new_lock_type;
 
1188
  check_locks(lock,"after downgrading lock",0);
 
1189
 
 
1190
  pthread_mutex_unlock(&lock->mutex);
 
1191
  DBUG_VOID_RETURN;
 
1192
}
 
1193
 
 
1194
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
 
1195
 
 
1196
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
 
1197
{
 
1198
  THR_LOCK *lock=data->lock;
 
1199
  DBUG_ENTER("thr_upgrade_write_delay_lock");
 
1200
 
 
1201
  pthread_mutex_lock(&lock->mutex);
 
1202
  if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
 
1203
  {
 
1204
    pthread_mutex_unlock(&lock->mutex);
 
1205
    DBUG_RETURN(data->type == TL_UNLOCK);       /* Test if Aborted */
 
1206
  }
 
1207
  check_locks(lock,"before upgrading lock",0);
 
1208
  /* TODO:  Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
 
1209
  data->type=TL_WRITE;                          /* Upgrade lock */
 
1210
 
 
1211
  /* Check if someone has given us the lock */
 
1212
  if (!data->cond)
 
1213
  {
 
1214
    if (!lock->read.data)                       /* No read locks */
 
1215
    {                                           /* We have the lock */
 
1216
      if (data->lock->get_status)
 
1217
        (*data->lock->get_status)(data->status_param, 0);
 
1218
      pthread_mutex_unlock(&lock->mutex);
 
1219
      DBUG_RETURN(0);
 
1220
    }
 
1221
 
 
1222
    if (((*data->prev)=data->next))             /* remove from lock-list */
 
1223
      data->next->prev= data->prev;
 
1224
    else
 
1225
      lock->write.last=data->prev;
 
1226
 
 
1227
    if ((data->next=lock->write_wait.data))     /* Put first in lock_list */
 
1228
      data->next->prev= &data->next;
 
1229
    else
 
1230
      lock->write_wait.last= &data->next;
 
1231
    data->prev= &lock->write_wait.data;
 
1232
    lock->write_wait.data=data;
 
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));
 
1240
}
 
1241
 
 
1242
 
 
1243
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
 
1244
 
 
1245
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
 
1246
{
 
1247
  THR_LOCK *lock=data->lock;
 
1248
  DBUG_ENTER("thr_reschedule_write_lock");
 
1249
 
 
1250
  pthread_mutex_lock(&lock->mutex);
 
1251
  if (!lock->read_wait.data)                    /* No waiting read locks */
 
1252
  {
 
1253
    pthread_mutex_unlock(&lock->mutex);
 
1254
    DBUG_RETURN(0);
 
1255
  }
 
1256
 
 
1257
  data->type=TL_WRITE_DELAYED;
 
1258
  if (lock->update_status)
 
1259
    (*lock->update_status)(data->status_param);
 
1260
  if (((*data->prev)=data->next))               /* remove from lock-list */
 
1261
    data->next->prev= data->prev;
 
1262
  else
 
1263
    lock->write.last=data->prev;
 
1264
 
 
1265
  if ((data->next=lock->write_wait.data))       /* Put first in lock_list */
 
1266
    data->next->prev= &data->next;
 
1267
  else
 
1268
    lock->write_wait.last= &data->next;
 
1269
  data->prev= &lock->write_wait.data;
 
1270
  data->cond=get_cond();                        /* This was zero */
 
1271
  lock->write_wait.data=data;
 
1272
  free_all_read_locks(lock,0);
 
1273
 
 
1274
  pthread_mutex_unlock(&lock->mutex);
 
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 */