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)
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.
60
Before a write lock is released, this function is called.
61
In MyISAM this functions updates the count and length of the datafile
63
When one gets a lock this functions is called.
64
In MyISAM this stores the number of rows and size of the datafile
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
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
60
#include "drizzled/session.h"
61
#include "drizzled/current_session.h"
77
#include "mysys_priv.h"
63
79
#include "thr_lock.h"
64
#include "drizzled/internal/m_string.h"
68
#if TIME_WITH_SYS_TIME
69
# include <sys/time.h>
73
# include <sys/time.h>
79
#include <drizzled/util/test.h>
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;
88
/* The following constants are only for debug output */
89
#define MAX_THREADS 100
93
LIST *thr_lock_thread_list; /* List of threads in use */
94
ulong max_write_lock_count= ~(ulong) 0L;
96
static inline pthread_cond_t *get_cond(void)
86
uint64_t table_lock_wait_timeout;
87
static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
90
uint64_t max_write_lock_count= ~(uint64_t) 0L;
98
return &my_thread_var->suspend;
93
102
** For the future (now the thread specific cond is alloced by my_pthread.c)
105
my_bool init_thr_lock()
111
static inline my_bool
97
112
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
99
114
return rhs == lhs;
119
#define MAX_FOUND_ERRORS 10 /* Report 10 first errors */
120
static uint found_errors=0;
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)
125
THR_LOCK_DATA *data,**prev;
127
THR_LOCK_OWNER *first_owner;
132
enum thr_lock_type last_lock_type=list->data->type;
134
if (same_owner && list->data)
135
first_owner= list->data->owner;
136
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
138
if (data->type != last_lock_type)
139
last_lock_type=TL_IGNORE;
140
if (data->prev != prev)
143
"Warning: prev link %d didn't point at previous lock at %s: %s\n",
144
count, lock_type, where);
148
!thr_lock_owner_equal(data->owner, first_owner) &&
149
last_lock_type != TL_WRITE_ALLOW_WRITE)
152
"Warning: Found locks from different threads in %s: %s\n",
156
if (no_cond && data->cond)
159
"Warning: Found active lock with not reset cond %s: %s\n",
167
fprintf(stderr,"Warning: found too many locks at %s: %s\n",
172
if (prev != list->last)
174
fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
182
static void check_locks(THR_LOCK *lock, const char *where,
183
my_bool allow_no_locks)
185
uint old_found_errors=found_errors;
186
DBUG_ENTER("check_locks");
188
if (found_errors < MAX_FOUND_ERRORS)
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))
196
if (found_errors < MAX_FOUND_ERRORS)
200
for (data=lock->read.data ; data ; data=data->next)
202
if ((int) data->type == (int) TL_READ_NO_INSERT)
204
/* Protect against infinite loop. */
205
DBUG_ASSERT(count <= lock->read_no_write_count);
207
if (count != lock->read_no_write_count)
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);
214
if (!lock->write.data)
216
if (!allow_no_locks && !lock->read.data &&
217
(lock->write_wait.data || lock->read_wait.data))
221
"Warning at '%s': No locks in use but locks are in wait queue\n",
224
if (!lock->write_wait.data)
226
if (!allow_no_locks && lock->read_wait.data)
230
"Warning at '%s': No write locks and waiting read locks\n",
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 &&
246
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
251
{ /* Have write lock */
252
if (lock->write_wait.data)
254
if (!allow_no_locks &&
255
lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
256
lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
260
"Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
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)))
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));
283
if (lock->read_wait.data)
285
if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
286
lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
290
"Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
292
(int) lock->read_wait.data->type,
293
(int) lock->write.data->type);
298
if (found_errors != old_found_errors)
300
DBUG_PRINT("error",("Found wrong lock"));
306
#else /* EXTRA_DEBUG */
307
#define check_locks(A,B,C)
103
311
/* Initialize a lock */
105
313
void thr_lock_init(THR_LOCK *lock)
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;
115
void THR_LOCK_INFO::init()
117
internal::st_my_thread_var *tmp= my_thread_var;
118
thread= tmp->pthread_self;
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);
331
void thr_lock_delete(THR_LOCK *lock)
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);
342
void thr_lock_info_init(THR_LOCK_INFO *info)
344
struct st_my_thread_var *tmp= my_thread_var;
345
info->thread= tmp->pthread_self;
346
info->thread_id= tmp->id;
123
350
/* Initialize a lock instance */
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)
129
owner= NULL; /* no owner yet */
130
status_param= param_arg;
355
data->type=TL_UNLOCK;
356
data->owner= 0; /* no owner yet */
357
data->status_param=param;
362
static inline my_bool
136
363
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
138
365
for ( ; data ; data=data->next)
140
367
if (thr_lock_owner_equal(data->owner, owner))
141
return true; /* Already locked by thread */
368
return 1; /* Already locked by thread */
373
static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
374
enum thr_lock_type type)
376
for ( ; data ; data=data->next)
378
if (data->type == type)
146
385
static void wake_up_waiters(THR_LOCK *lock);
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)
151
Session *session= current_session;
152
internal::st_my_thread_var *thread_var= session->getThreadVar();
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");
159
399
if (!in_wait_list)
666
1096
This is used to abort all locks for a specific thread
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)
1101
THR_LOCK_DATA *data;
1102
my_bool found= FALSE;
1103
DBUG_ENTER("thr_abort_locks_for_thread");
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)
676
if (local_data->owner->info->thread_id == thread_id_arg)
1108
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
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. */
681
local_data->cond->notify_one();
682
local_data->cond= 0; /* Removed from list */
684
if (((*local_data->prev)= local_data->next))
685
local_data->next->prev= local_data->prev;
687
read_wait.last= local_data->prev;
690
for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
692
if (local_data->owner->info->thread_id == thread_id_arg)
694
local_data->type= TL_UNLOCK;
696
local_data->cond->notify_one();
697
local_data->cond= NULL;
699
if (((*local_data->prev)= local_data->next))
700
local_data->next->prev= local_data->prev;
702
write_wait.last= local_data->prev;
705
wake_up_waiters(this);
710
} /* namespace drizzled */
1114
pthread_cond_signal(data->cond);
1115
data->cond= 0; /* Removed from list */
1117
if (((*data->prev)= data->next))
1118
data->next->prev= data->prev;
1120
lock->read_wait.last= data->prev;
1123
for (data= lock->write_wait.data; data ; data= data->next)
1125
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
1127
DBUG_PRINT("info",("Aborting write-wait lock"));
1128
data->type= TL_UNLOCK;
1130
pthread_cond_signal(data->cond);
1133
if (((*data->prev)= data->next))
1134
data->next->prev= data->prev;
1136
lock->write_wait.last= data->prev;
1139
wake_up_waiters(lock);
1140
pthread_mutex_unlock(&lock->mutex);
1146
Downgrade a WRITE_* to a lower WRITE level
1148
thr_downgrade_write_lock()
1149
in_data Lock data of thread downgrading its lock
1150
new_lock_type New write lock type
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
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
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.
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
1175
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
1176
enum thr_lock_type new_lock_type)
1178
THR_LOCK *lock=in_data->lock;
1180
enum thr_lock_type old_lock_type= in_data->type;
1182
DBUG_ENTER("thr_downgrade_write_only_lock");
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);
1190
pthread_mutex_unlock(&lock->mutex);
1194
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1196
my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1198
THR_LOCK *lock=data->lock;
1199
DBUG_ENTER("thr_upgrade_write_delay_lock");
1201
pthread_mutex_lock(&lock->mutex);
1202
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1204
pthread_mutex_unlock(&lock->mutex);
1205
DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */
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 */
1211
/* Check if someone has given us the lock */
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);
1222
if (((*data->prev)=data->next)) /* remove from lock-list */
1223
data->next->prev= data->prev;
1225
lock->write.last=data->prev;
1227
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1228
data->next->prev= &data->next;
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);
1237
check_locks(lock,"waiting for lock",0);
1239
DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
1243
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1245
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1247
THR_LOCK *lock=data->lock;
1248
DBUG_ENTER("thr_reschedule_write_lock");
1250
pthread_mutex_lock(&lock->mutex);
1251
if (!lock->read_wait.data) /* No waiting read locks */
1253
pthread_mutex_unlock(&lock->mutex);
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;
1263
lock->write.last=data->prev;
1265
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1266
data->next->prev= &data->next;
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);
1274
pthread_mutex_unlock(&lock->mutex);
1275
DBUG_RETURN(thr_upgrade_write_delay_lock(data));
1281
static void thr_print_lock(const char* name,struct st_lock_list *list)
1283
THR_LOCK_DATA *data,**prev;
1288
printf("%-10s: ",name);
1290
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
1292
printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id,
1294
if (data->prev != prev)
1295
printf("\nWarning: prev didn't point at previous lock\n");
1299
if (prev != list->last)
1300
printf("Warning: last didn't point at last lock\n");
1304
void thr_print_locks(void)
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))
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)
1322
if (lock->write_wait.data)
1323
printf(" write_wait");
1324
if (lock->read.data)
1326
if (lock->read_wait.data)
1327
printf(" read_wait");
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));
1337
pthread_mutex_unlock(&THR_LOCK_lock);
1340
/*****************************************************************************
1341
** Test of thread locks
1342
****************************************************************************/
1348
enum thr_lock_type lock_type;
1351
THR_LOCK locks[5]; /* 4 locks */
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}};
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)
1394
static pthread_cond_t COND_thread_count;
1395
static pthread_mutex_t LOCK_thread_count;
1396
static uint thread_count;
1399
#define MAX_LOCK_COUNT 8
1401
/* The following functions is for WRITE_CONCURRENT_INSERT */
1403
static void test_get_status(void* param __attribute__((unused)),
1404
int concurrent_insert __attribute__((unused)))
1408
static void test_update_status(void* param __attribute__((unused)))
1412
static void test_copy_status(void* to __attribute__((unused)) ,
1413
void *from __attribute__((unused)))
1417
static my_bool test_check_status(void* param __attribute__((unused)))
1423
static void *test_thread(void *arg)
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];
1432
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
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 */
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;
1446
thr_multi_lock(multi_locks, lock_counts[param], &owner);
1447
pthread_mutex_lock(&LOCK_thread_count);
1449
int tmp=rand() & 7; /* Do something from 0-2 sec */
1457
for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
1461
pthread_mutex_unlock(&LOCK_thread_count);
1462
thr_multi_unlock(multi_locks,lock_counts[param]);
1465
printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
1467
pthread_mutex_lock(&LOCK_thread_count);
1469
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
1470
pthread_mutex_unlock(&LOCK_thread_count);
1476
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
1479
pthread_attr_t thr_attr;
1482
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
1483
DBUG_PUSH(argv[1]+2);
1485
printf("Main thread: %s\n",my_thread_name());
1487
if ((error=pthread_cond_init(&COND_thread_count,NULL)))
1489
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1493
if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST)))
1495
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1500
for (i=0 ; i < (int) array_elements(locks) ; i++)
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;
1508
if ((error=pthread_attr_init(&thr_attr)))
1510
fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
1514
if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
1517
"Got error: %d from pthread_attr_setdetachstate (errno: %d)",
1521
#ifndef pthread_attr_setstacksize /* void return value */
1522
if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
1524
fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
1529
#ifdef HAVE_THR_SETCONCURRENCY
1530
VOID(thr_setconcurrency(2));
1532
for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1534
param=(int*) malloc(sizeof(int));
1537
if ((error=pthread_mutex_lock(&LOCK_thread_count)))
1539
fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
1543
if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
1545
fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
1547
pthread_mutex_unlock(&LOCK_thread_count);
1551
pthread_mutex_unlock(&LOCK_thread_count);
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)
1559
if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
1560
fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
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);
1568
printf("Got %d warnings\n",found_errors);
1571
printf("Test succeeded\n");