119
119
return rhs == lhs;
124
#define MAX_THREADS 100
125
#define MAX_LOCKS 100
126
#define MAX_FOUND_ERRORS 10 /* Report 10 first errors */
127
static uint32_t found_errors=0;
129
static int check_lock(struct st_lock_list *list, const char* lock_type,
130
const char *where, bool same_owner, bool no_cond)
132
THR_LOCK_DATA *data,**prev;
134
THR_LOCK_OWNER *first_owner;
139
enum thr_lock_type last_lock_type=list->data->type;
141
if (same_owner && list->data)
142
first_owner= list->data->owner;
143
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
145
if (data->type != last_lock_type)
146
last_lock_type=TL_IGNORE;
147
if (data->prev != prev)
150
"Warning: prev link %d didn't point at previous lock at %s: %s\n",
151
count, lock_type, where);
155
!thr_lock_owner_equal(data->owner, first_owner) &&
156
last_lock_type != TL_WRITE_ALLOW_WRITE)
159
"Warning: Found locks from different threads in %s: %s\n",
163
if (no_cond && data->cond)
166
"Warning: Found active lock with not reset cond %s: %s\n",
174
fprintf(stderr,"Warning: found too many locks at %s: %s\n",
179
if (prev != list->last)
181
fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
189
static void check_locks(THR_LOCK *lock, const char *where,
192
uint32_t old_found_errors=found_errors;
194
if (found_errors < MAX_FOUND_ERRORS)
196
if (check_lock(&lock->write,"write",where,1,1) |
197
check_lock(&lock->write_wait,"write_wait",where,0,0) |
198
check_lock(&lock->read,"read",where,0,1) |
199
check_lock(&lock->read_wait,"read_wait",where,0,0))
202
if (found_errors < MAX_FOUND_ERRORS)
206
for (data=lock->read.data ; data ; data=data->next)
208
if ((int) data->type == (int) TL_READ_NO_INSERT)
210
/* Protect against infinite loop. */
211
assert(count <= lock->read_no_write_count);
213
if (count != lock->read_no_write_count)
217
"Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
220
if (!lock->write.data)
222
if (!allow_no_locks && !lock->read.data &&
223
(lock->write_wait.data || lock->read_wait.data))
227
"Warning at '%s': No locks in use but locks are in wait queue\n",
230
if (!lock->write_wait.data)
232
if (!allow_no_locks && lock->read_wait.data)
236
"Warning at '%s': No write locks and waiting read locks\n",
242
if (!allow_no_locks &&
243
(((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
244
lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
245
!lock->read_no_write_count) ||
246
lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
247
(lock->write_wait.data->type == TL_WRITE_DELAYED &&
252
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
257
{ /* Have write lock */
258
if (lock->write_wait.data)
260
if (!allow_no_locks &&
261
lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
262
lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
266
"Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
272
if (!thr_lock_owner_equal(lock->write.data->owner,
273
lock->read.data->owner) &&
274
((lock->write.data->type > TL_WRITE_DELAYED &&
275
lock->write.data->type != TL_WRITE_ONLY) ||
276
((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
277
lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
278
lock->read_no_write_count)))
282
"Warning at '%s': Found lock of type %d that is write and read locked\n",
283
where, lock->write.data->type);
286
if (lock->read_wait.data)
288
if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
289
lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
293
"Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
295
(int) lock->read_wait.data->type,
296
(int) lock->write.data->type);
305
#else /* EXTRA_DEBUG */
306
#define check_locks(A,B,C)
310
123
/* Initialize a lock */
1082
810
pthread_mutex_unlock(&lock->mutex);
1088
Downgrade a WRITE_* to a lower WRITE level
1090
thr_downgrade_write_lock()
1091
in_data Lock data of thread downgrading its lock
1092
new_lock_type New write lock type
1096
This can be used to downgrade a lock already owned. When the downgrade
1097
occurs also other waiters, both readers and writers can be allowed to
1099
The previous lock is often TL_WRITE_ONLY but can also be
1100
TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
1101
TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
1102
TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
1103
operation didn't need such a high lock.
1104
TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
1106
TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
1107
already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
1108
The implementation is conservative and rather don't start rather than
1109
go on unknown paths to start, the common cases are handled.
1112
In its current implementation it is only allowed to downgrade from
1113
TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
1117
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
1118
enum thr_lock_type new_lock_type)
1120
THR_LOCK *lock=in_data->lock;
1122
pthread_mutex_lock(&lock->mutex);
1123
in_data->type= new_lock_type;
1124
check_locks(lock,"after downgrading lock",0);
1126
pthread_mutex_unlock(&lock->mutex);
1130
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
1132
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
1134
THR_LOCK *lock=data->lock;
1136
pthread_mutex_lock(&lock->mutex);
1137
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
1139
pthread_mutex_unlock(&lock->mutex);
1140
return(data->type == TL_UNLOCK); /* Test if Aborted */
1142
check_locks(lock,"before upgrading lock",0);
1143
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
1144
data->type=TL_WRITE; /* Upgrade lock */
1146
/* Check if someone has given us the lock */
1149
if (!lock->read.data) /* No read locks */
1150
{ /* We have the lock */
1151
if (data->lock->get_status)
1152
(*data->lock->get_status)(data->status_param, 0);
1153
pthread_mutex_unlock(&lock->mutex);
1157
if (((*data->prev)=data->next)) /* remove from lock-list */
1158
data->next->prev= data->prev;
1160
lock->write.last=data->prev;
1162
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1163
data->next->prev= &data->next;
1165
lock->write_wait.last= &data->next;
1166
data->prev= &lock->write_wait.data;
1167
lock->write_wait.data=data;
1168
check_locks(lock,"upgrading lock",0);
1172
check_locks(lock,"waiting for lock",0);
1174
return(wait_for_lock(&lock->write_wait,data,1));
1178
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
1180
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
1182
THR_LOCK *lock=data->lock;
1184
pthread_mutex_lock(&lock->mutex);
1185
if (!lock->read_wait.data) /* No waiting read locks */
1187
pthread_mutex_unlock(&lock->mutex);
1191
data->type=TL_WRITE_DELAYED;
1192
if (lock->update_status)
1193
(*lock->update_status)(data->status_param);
1194
if (((*data->prev)=data->next)) /* remove from lock-list */
1195
data->next->prev= data->prev;
1197
lock->write.last=data->prev;
1199
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
1200
data->next->prev= &data->next;
1202
lock->write_wait.last= &data->next;
1203
data->prev= &lock->write_wait.data;
1204
data->cond=get_cond(); /* This was zero */
1205
lock->write_wait.data=data;
1206
free_all_read_locks(lock,0);
1208
pthread_mutex_unlock(&lock->mutex);
1209
return(thr_upgrade_write_delay_lock(data));
1215
/*****************************************************************************
1216
** Test of thread locks
1217
****************************************************************************/
1223
enum thr_lock_type lock_type;
1226
THR_LOCK locks[5]; /* 4 locks */
1228
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
1229
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
1230
struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
1231
struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
1232
struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
1233
struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
1234
struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
1235
struct st_test test_7[] = {{3,TL_READ}};
1236
struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}}; /* Should be quick */
1237
struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
1238
struct st_test test_10[] ={{4,TL_WRITE}};
1239
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 */
1240
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 */
1241
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}};
1242
struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
1243
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
1244
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
1246
struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
1247
test_7,test_8,test_9,test_10,test_11,test_12,
1248
test_13,test_14,test_15,test_16};
1249
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
1250
sizeof(test_1)/sizeof(struct st_test),
1251
sizeof(test_2)/sizeof(struct st_test),
1252
sizeof(test_3)/sizeof(struct st_test),
1253
sizeof(test_4)/sizeof(struct st_test),
1254
sizeof(test_5)/sizeof(struct st_test),
1255
sizeof(test_6)/sizeof(struct st_test),
1256
sizeof(test_7)/sizeof(struct st_test),
1257
sizeof(test_8)/sizeof(struct st_test),
1258
sizeof(test_9)/sizeof(struct st_test),
1259
sizeof(test_10)/sizeof(struct st_test),
1260
sizeof(test_11)/sizeof(struct st_test),
1261
sizeof(test_12)/sizeof(struct st_test),
1262
sizeof(test_13)/sizeof(struct st_test),
1263
sizeof(test_14)/sizeof(struct st_test),
1264
sizeof(test_15)/sizeof(struct st_test),
1265
sizeof(test_16)/sizeof(struct st_test)
1269
static pthread_cond_t COND_thread_count;
1270
static pthread_mutex_t LOCK_thread_count;
1271
static uint32_t thread_count;
1272
static uint32_t sum=0;
1274
#define MAX_LOCK_COUNT 8
1276
/* The following functions is for WRITE_CONCURRENT_INSERT */
1278
static void test_get_status(void* param __attribute__((unused)),
1279
int concurrent_insert __attribute__((unused)))
1283
static void test_update_status(void* param __attribute__((unused)))
1287
static void test_copy_status(void* to __attribute__((unused)) ,
1288
void *from __attribute__((unused)))
1292
static bool test_check_status(void* param __attribute__((unused)))
1298
static void *test_thread(void *arg)
1300
int i,j,param=*((int*) arg);
1301
THR_LOCK_DATA data[MAX_LOCK_COUNT];
1302
THR_LOCK_OWNER owner;
1303
THR_LOCK_INFO lock_info;
1304
THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
1307
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
1310
thr_lock_info_init(&lock_info);
1311
thr_lock_owner_init(&owner, &lock_info);
1312
for (i=0; i < lock_counts[param] ; i++)
1313
thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
1314
for (j=1 ; j < 10 ; j++) /* try locking 10 times */
1316
for (i=0; i < lock_counts[param] ; i++)
1317
{ /* Init multi locks */
1318
multi_locks[i]= &data[i];
1319
data[i].type= tests[param][i].lock_type;
1321
thr_multi_lock(multi_locks, lock_counts[param], &owner);
1322
pthread_mutex_lock(&LOCK_thread_count);
1324
int tmp=rand() & 7; /* Do something from 0-2 sec */
1332
for (k=0 ; k < (uint32_t) (tmp-2)*100000L ; k++)
1336
pthread_mutex_unlock(&LOCK_thread_count);
1337
thr_multi_unlock(multi_locks,lock_counts[param]);
1340
printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
1342
pthread_mutex_lock(&LOCK_thread_count);
1344
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
1345
pthread_mutex_unlock(&LOCK_thread_count);
1346
free((unsigned char*) arg);
1351
int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
1354
pthread_attr_t thr_attr;
1358
printf("Main thread: %s\n",my_thread_name());
1360
if ((error=pthread_cond_init(&COND_thread_count,NULL)))
1362
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1366
if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST)))
1368
fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
1373
for (i=0 ; i < (int) array_elements(locks) ; i++)
1375
thr_lock_init(locks+i);
1376
locks[i].check_status= test_check_status;
1377
locks[i].update_status=test_update_status;
1378
locks[i].copy_status= test_copy_status;
1379
locks[i].get_status= test_get_status;
1381
if ((error=pthread_attr_init(&thr_attr)))
1383
fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
1387
if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
1390
"Got error: %d from pthread_attr_setdetachstate (errno: %d)",
1394
#ifndef pthread_attr_setstacksize /* void return value */
1395
if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
1397
fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
1402
#ifdef HAVE_THR_SETCONCURRENCY
1403
thr_setconcurrency(2);
1405
for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1407
param=(int*) malloc(sizeof(int));
1410
if ((error=pthread_mutex_lock(&LOCK_thread_count)))
1412
fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
1416
if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
1418
fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
1420
pthread_mutex_unlock(&LOCK_thread_count);
1424
pthread_mutex_unlock(&LOCK_thread_count);
1427
pthread_attr_destroy(&thr_attr);
1428
if ((error=pthread_mutex_lock(&LOCK_thread_count)))
1429
fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
1430
while (thread_count)
1432
if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
1433
fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
1435
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
1436
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
1437
for (i=0 ; i < (int) array_elements(locks) ; i++)
1438
thr_lock_delete(locks+i);
1441
printf("Got %d warnings\n",found_errors);
1444
printf("Test succeeded\n");