Some random code cleanups, and implemented a naive lock manager. (Still need to tie it into LLADD...)
This commit is contained in:
parent
815942ed4c
commit
6f022cc577
8 changed files with 358 additions and 39 deletions
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#ifndef __HASH_H
|
#ifndef __HASH_H
|
||||||
#define __HASH_H
|
#define __HASH_H
|
||||||
/** @todo replace() powl in hash with something more efficient, if hash() becomes a bottleneck. */
|
|
||||||
unsigned int max_bucket(unsigned char tableBits, unsigned long nextExtension);
|
unsigned int max_bucket(unsigned char tableBits, unsigned long nextExtension);
|
||||||
unsigned int hash(const void * val, long val_length, unsigned char tableBits, unsigned long nextExtension);
|
unsigned int hash(const void * val, long val_length, unsigned char tableBits, unsigned long nextExtension);
|
||||||
#define twoToThe(x) (1 << (x))
|
#define twoToThe(x) (1 << (x))
|
||||||
|
|
9
lladd/lockManager.h
Normal file
9
lladd/lockManager.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#include <lladd/transactional.h>
|
||||||
|
|
||||||
|
void lockManagerInit();
|
||||||
|
|
||||||
|
int lockManagerReadLockRecord(int xid, recordid rid);
|
||||||
|
int lockManagerWriteLockRecord(int xid, recordid rid);
|
||||||
|
|
||||||
|
int lockManagerUnlockRecord(int xid, recordid rid);
|
||||||
|
int lockManagerReleaseAll(int xid);
|
|
@ -111,44 +111,13 @@ void unlock(rwl * lock) {
|
||||||
pthread_mutex_unlock (lock->mut);
|
pthread_mutex_unlock (lock->mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void readunlock(rwl *lock) {
|
|
||||||
writeunlock(lock);
|
|
||||||
}*/
|
|
||||||
void readunlock(rwl * lock) {
|
void readunlock(rwl * lock) {
|
||||||
unlock(lock);
|
unlock(lock);
|
||||||
}
|
}
|
||||||
void writeunlock(rwl * lock) {
|
void writeunlock(rwl * lock) {
|
||||||
unlock(lock);
|
unlock(lock);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
void readunlock (rwl *lock)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock (lock->mut);
|
|
||||||
lock->readers--;
|
|
||||||
pthread_cond_signal (lock->writeOK);
|
|
||||||
|
|
||||||
/ * Don't need to broadcast, since only one writer can run at
|
|
||||||
once. * /
|
|
||||||
|
|
||||||
/ * pthread_cond_broadcast (lock->writeOK); * /
|
|
||||||
|
|
||||||
pthread_mutex_unlock (lock->mut);
|
|
||||||
/ * printf("readunlock done\n"); * /
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeunlock (rwl *lock)
|
|
||||||
{
|
|
||||||
/ * printf("writeunlock done\n");
|
|
||||||
fflush(NULL); * /
|
|
||||||
|
|
||||||
pthread_mutex_lock (lock->mut);
|
|
||||||
lock->writers--;
|
|
||||||
/ * Need this as well (in case there's another writer, which is blocking the all of the readers. * /
|
|
||||||
pthread_cond_signal (lock->writeOK);
|
|
||||||
pthread_cond_broadcast (lock->readOK);
|
|
||||||
pthread_mutex_unlock (lock->mut);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void deletelock (rwl *lock)
|
void deletelock (rwl *lock)
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy (lock->mut);
|
pthread_mutex_destroy (lock->mut);
|
||||||
|
|
|
@ -5,11 +5,12 @@ lib_LIBRARIES=liblladd.a
|
||||||
# removed: recovery.c transactional.c logger.c logger/logparser.c logger/logstreamer.c
|
# removed: recovery.c transactional.c logger.c logger/logparser.c logger/logstreamer.c
|
||||||
liblladd_a_SOURCES=crc32.c common.c stats.c io.c bufferManager.c linkedlist.c operations.c \
|
liblladd_a_SOURCES=crc32.c common.c stats.c io.c bufferManager.c linkedlist.c operations.c \
|
||||||
pageFile.c pageCache.c page.c blobManager.c recovery2.c transactional2.c \
|
pageFile.c pageCache.c page.c blobManager.c recovery2.c transactional2.c \
|
||||||
|
lockManager.c \
|
||||||
logger/logEntry.c logger/logWriter.c logger/logHandle.c logger/logger2.c \
|
logger/logEntry.c logger/logWriter.c logger/logHandle.c logger/logger2.c \
|
||||||
|
page/slotted.c page/header.c page/fixed.c \
|
||||||
operations/pageOperations.c page/indirect.c operations/decrement.c \
|
operations/pageOperations.c page/indirect.c operations/decrement.c \
|
||||||
operations/increment.c operations/prepare.c operations/set.c \
|
operations/increment.c operations/prepare.c operations/set.c \
|
||||||
operations/alloc.c operations/noop.c operations/instantSet.c \
|
operations/alloc.c operations/noop.c operations/instantSet.c \
|
||||||
page/slotted.c page/header.c page/fixed.c \
|
|
||||||
operations/arrayList.c hash.c operations/linearHash.c \
|
operations/arrayList.c hash.c operations/linearHash.c \
|
||||||
operations/naiveLinearHash.c operations/nestedTopActions.c \
|
operations/naiveLinearHash.c operations/nestedTopActions.c \
|
||||||
operations/linearHashNTA.c operations/linkedListNTA.c \
|
operations/linearHashNTA.c operations/linkedListNTA.c \
|
||||||
|
|
251
src/lladd/lockManager.c
Normal file
251
src/lladd/lockManager.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
#include <pbl/pbl.h>
|
||||||
|
#include <lladd/lockManager.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <lladd/hash.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MUTEX_COUNT 32
|
||||||
|
// These next two correspond to MUTEX count, and are the appropriate values to pass into hash().
|
||||||
|
#define MUTEX_BITS 5
|
||||||
|
#define MUTEX_EXT 32
|
||||||
|
|
||||||
|
static pthread_mutex_t mutexes[MUTEX_COUNT];
|
||||||
|
|
||||||
|
static pthread_mutex_t xid_table_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static pthread_mutex_t * getMutex(recordid rid) {
|
||||||
|
return &mutexes[hash(&rid, sizeof(recordid), MUTEX_BITS, MUTEX_EXT)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static pblHashTable_t * xidLockTable;
|
||||||
|
static pblHashTable_t * ridLockTable;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pthread_cond_t writeOK;
|
||||||
|
pthread_cond_t readOK;
|
||||||
|
int readers;
|
||||||
|
int writers;
|
||||||
|
int waiting;
|
||||||
|
int active;
|
||||||
|
} lock;
|
||||||
|
|
||||||
|
void lockManagerInit() {
|
||||||
|
int i = 0;
|
||||||
|
for(i = 0; i < MUTEX_COUNT; i++) {
|
||||||
|
pthread_mutex_init(&mutexes[i], NULL);
|
||||||
|
}
|
||||||
|
xidLockTable = pblHtCreate();
|
||||||
|
ridLockTable = pblHtCreate();
|
||||||
|
|
||||||
|
}
|
||||||
|
/** @todo startTransaction needs a mutex!! */
|
||||||
|
void startTransaction(int xid) {
|
||||||
|
pthread_mutex_lock(&xid_table_mutex);
|
||||||
|
|
||||||
|
pblHashTable_t * xidLocks = pblHtCreate();
|
||||||
|
pblHtInsert(xidLockTable, &xid, sizeof(int), xidLocks);
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock* createLock(recordid rid) {
|
||||||
|
lock * ret = malloc(sizeof(lock));
|
||||||
|
|
||||||
|
if(!ret) { return NULL; }
|
||||||
|
|
||||||
|
// pthread_mutex_init(&ret->mut, NULL);
|
||||||
|
pthread_cond_init(&ret->writeOK, NULL);
|
||||||
|
pthread_cond_init(&ret->readOK, NULL);
|
||||||
|
ret->readers = 0;
|
||||||
|
ret->writers = 0;
|
||||||
|
ret->waiting = 0;
|
||||||
|
|
||||||
|
pblHtInsert(ridLockTable, &rid, sizeof(recordid), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyLock(recordid rid, lock * l) {
|
||||||
|
pthread_cond_destroy(&l->writeOK);
|
||||||
|
pthread_cond_destroy(&l->readOK);
|
||||||
|
free (l);
|
||||||
|
pblHtRemove(ridLockTable, &rid, sizeof(recordid));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LM_READLOCK 1
|
||||||
|
#define LM_WRITELOCK 2
|
||||||
|
|
||||||
|
int lockManagerReadLockRecord(int xid, recordid rid) {
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xid_table_mutex);
|
||||||
|
pblHashTable_t * xidLocks = pblHtLookup(xidLockTable, &xid, sizeof(int));
|
||||||
|
if((int)pblHtLookup(xidLocks, &rid, sizeof(recordid)) >= LM_READLOCK) {
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
pthread_mutex_t * mut = getMutex(rid);
|
||||||
|
|
||||||
|
pthread_mutex_lock(mut);
|
||||||
|
|
||||||
|
lock * ridLock = pblHtLookup(ridLockTable, &rid, sizeof(recordid));
|
||||||
|
|
||||||
|
if(!ridLock) {
|
||||||
|
ridLock = createLock(rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ridLock->active++;
|
||||||
|
|
||||||
|
if(ridLock->writers || ridLock->waiting) {
|
||||||
|
struct timeval tv;
|
||||||
|
int tod_ret = gettimeofday (&tv, NULL);
|
||||||
|
tv.tv_sec++; // Wait up to one second to obtain a lock before detecting deadlock.
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = tv.tv_sec;
|
||||||
|
ts.tv_nsec = tv.tv_usec * 1000;
|
||||||
|
if(tod_ret != 0) {
|
||||||
|
perror("Could not get time of day");
|
||||||
|
return LLADD_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
int wait_ret = pthread_cond_timedwait(&ridLock->readOK, mut, &ts);
|
||||||
|
if(wait_ret == ETIMEDOUT) {
|
||||||
|
ridLock->active--;
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
return LLADD_DEADLOCK;
|
||||||
|
}
|
||||||
|
} while(ridLock->writers);
|
||||||
|
}
|
||||||
|
ridLock->readers++;
|
||||||
|
ridLock->active--;
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
pblHtInsert(xidLocks, &rid, sizeof(recordid), (void*)LM_READLOCK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lockManagerWriteLockRecord(int xid, recordid rid) {
|
||||||
|
pthread_mutex_lock(&xid_table_mutex);
|
||||||
|
pblHashTable_t * xidLocks = pblHtLookup(xidLockTable, &xid, sizeof(int));
|
||||||
|
|
||||||
|
|
||||||
|
int currentLockLevel = (int)pblHtLookup(xidLocks, &rid, sizeof(recordid));
|
||||||
|
int me = 0;
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
|
||||||
|
if(currentLockLevel >= LM_WRITELOCK) {
|
||||||
|
return 0;
|
||||||
|
} else if(currentLockLevel == LM_READLOCK) {
|
||||||
|
me = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_t * mut = getMutex(rid);
|
||||||
|
|
||||||
|
pthread_mutex_lock(mut);
|
||||||
|
lock * ridLock = pblHtLookup(ridLockTable, &rid, sizeof(recordid));
|
||||||
|
if(!ridLock) {
|
||||||
|
ridLock = createLock(rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ridLock->active++;
|
||||||
|
ridLock->waiting++;
|
||||||
|
if(ridLock->writers || (ridLock->readers - me)) {
|
||||||
|
struct timeval tv;
|
||||||
|
int tod_ret = gettimeofday(&tv, NULL);
|
||||||
|
tv.tv_sec++;
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec = tv.tv_sec;
|
||||||
|
ts.tv_nsec = tv.tv_usec * 1000;
|
||||||
|
if(tod_ret != 0) {
|
||||||
|
perror("Could not get time of day");
|
||||||
|
return LLADD_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
while(ridLock->writers || (ridLock->readers - me)) {
|
||||||
|
int lockret = pthread_cond_timedwait(&ridLock->writeOK, mut, &ts);
|
||||||
|
if(lockret == ETIMEDOUT) {
|
||||||
|
ridLock->waiting--;
|
||||||
|
ridLock->active--;
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
return LLADD_DEADLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ridLock->waiting--;
|
||||||
|
if(currentLockLevel == 0) {
|
||||||
|
ridLock->readers++;
|
||||||
|
}
|
||||||
|
ridLock->writers++;
|
||||||
|
ridLock->active--;
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
pblHtInsert(xidLocks, &rid, sizeof(recordid), (void*)LM_WRITELOCK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lockManagerUnlockRecord(int xid, recordid rid) {
|
||||||
|
pthread_mutex_lock(&xid_table_mutex);
|
||||||
|
|
||||||
|
pblHashTable_t * xidLocks = pblHtLookup(xidLockTable, &xid, sizeof(int));
|
||||||
|
|
||||||
|
|
||||||
|
int currentLevel = (int)pblHtLookup(xidLocks, &rid, sizeof(recordid));
|
||||||
|
|
||||||
|
if(currentLevel) {
|
||||||
|
pblHtRemove(xidLocks, &rid, sizeof(recordid));
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
pthread_mutex_t * mut = getMutex(rid);
|
||||||
|
pthread_mutex_lock(mut);
|
||||||
|
lock * ridLock = pblHtLookup(ridLockTable, &rid, sizeof(recordid));
|
||||||
|
assert(ridLock);
|
||||||
|
ridLock->active++;
|
||||||
|
|
||||||
|
if(currentLevel == LM_WRITELOCK) {
|
||||||
|
ridLock->writers--;
|
||||||
|
ridLock->readers--;
|
||||||
|
} else if(currentLevel == LM_READLOCK) {
|
||||||
|
ridLock->readers--;
|
||||||
|
} else if(currentLevel == 0) {
|
||||||
|
assert(0); // Someone tried to release a lock they didn't own!
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unknown lock type encountered!");
|
||||||
|
ridLock->active--;
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
return LLADD_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ridLock->active--;
|
||||||
|
|
||||||
|
if(!(ridLock->active || ridLock->waiting || ridLock->readers || ridLock->writers)) {
|
||||||
|
destroyLock(rid, ridLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(mut);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lockManagerReleaseAll(int xid) {
|
||||||
|
|
||||||
|
pthread_mutex_lock(&xid_table_mutex);
|
||||||
|
|
||||||
|
pblHashTable_t * xidLocks = pblHtLookup(xidLockTable, &xid, sizeof(int));
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&xid_table_mutex);
|
||||||
|
void * data;
|
||||||
|
int ret = 0;
|
||||||
|
for(data = pblHtFirst(xidLocks); data; data = pblHtNext(xidLocks)) {
|
||||||
|
recordid rid = *(recordid*)pblHtCurrentKey(xidLocks);
|
||||||
|
int tmpret = lockManagerUnlockRecord(xid, rid);
|
||||||
|
// Pass any error(s) up to the user.
|
||||||
|
// (This logic relies on the fact that currently it only returns 0 and LLADD_INTERNAL_ERROR)
|
||||||
|
if(tmpret) {
|
||||||
|
ret = tmpret;
|
||||||
|
}
|
||||||
|
pblHtRemove(xidLocks, &rid, sizeof(recordid));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -136,8 +136,7 @@ struct Page_s {
|
||||||
/** @todo The Page.LSN field seems extraneous. Why do we need it? */
|
/** @todo The Page.LSN field seems extraneous. Why do we need it? */
|
||||||
long LSN;
|
long LSN;
|
||||||
byte *memAddr;
|
byte *memAddr;
|
||||||
/** @todo dirty pages currently aren't marked dirty! */
|
byte dirty;
|
||||||
int dirty;
|
|
||||||
/** The next item in the replacement policy's queue */
|
/** The next item in the replacement policy's queue */
|
||||||
struct Page_s *next;
|
struct Page_s *next;
|
||||||
/** The previous item in the replacement policy's queue. */
|
/** The previous item in the replacement policy's queue. */
|
||||||
|
@ -201,6 +200,7 @@ struct Page_s {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
rwl * loadlatch;
|
rwl * loadlatch;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
INCLUDES = @CHECK_CFLAGS@
|
INCLUDES = @CHECK_CFLAGS@
|
||||||
if HAVE_CHECK
|
if HAVE_CHECK
|
||||||
## Had to disable check_lht because lht needs to be rewritten.
|
## Had to disable check_lht because lht needs to be rewritten.
|
||||||
TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA check_pageOrientedList
|
TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA check_pageOrientedList check_lockManager
|
||||||
#check_lladdhash
|
#check_lladdhash
|
||||||
else
|
else
|
||||||
TESTS =
|
TESTS =
|
||||||
endif
|
endif
|
||||||
noinst_PROGRAMS = $(TESTS)
|
noinst_PROGRAMS = $(TESTS)
|
||||||
LDADD = @CHECK_LIBS@ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a $(top_builddir)/src/libdfa/librw.a #-lefence
|
LDADD = @CHECK_LIBS@ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a $(top_builddir)/src/libdfa/librw.a #-lefence
|
||||||
CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log check_pageOrientedListNTA.log
|
CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log check_pageOrientedListNTA.log check_lockManager.log
|
||||||
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||||
|
|
90
test/lladd/check_lockManager.c
Normal file
90
test/lladd/check_lockManager.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include <lladd/transactional.h>
|
||||||
|
#include <lladd/lockManager.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
#include <lladd/transactional.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "../check_includes.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define LOG_NAME "check_lockManager.log"
|
||||||
|
|
||||||
|
/** Needs to be formatted as a floating point */
|
||||||
|
#define NUM_RECORDS 100000000.0
|
||||||
|
#define THREAD_COUNT 100
|
||||||
|
#define RIDS_PER_THREAD 10000
|
||||||
|
|
||||||
|
void * workerThread(void * j) {
|
||||||
|
|
||||||
|
int xid = *(int*)j;
|
||||||
|
startTransaction(xid);
|
||||||
|
recordid rid;
|
||||||
|
rid.page = 0;
|
||||||
|
rid.size = 0;
|
||||||
|
int k;
|
||||||
|
int deadlocks = 0;
|
||||||
|
for(k = 0; k < RIDS_PER_THREAD; k++) {
|
||||||
|
rid.slot = (int) (NUM_RECORDS*random()/(RAND_MAX+1.0));
|
||||||
|
int rw = random() % 2;
|
||||||
|
|
||||||
|
if(rw) {
|
||||||
|
// readlock
|
||||||
|
|
||||||
|
if(LLADD_DEADLOCK == lockManagerReadLockRecord(xid, rid)) {
|
||||||
|
deadlocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// writelock
|
||||||
|
if(LLADD_DEADLOCK == lockManagerWriteLockRecord(xid, rid)) {
|
||||||
|
deadlocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%2d ", deadlocks); fflush(stdout);
|
||||||
|
|
||||||
|
lockManagerReleaseAll(xid);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(lockManagerTest) {
|
||||||
|
|
||||||
|
lockManagerInit();
|
||||||
|
pthread_t workers[THREAD_COUNT];
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < THREAD_COUNT; i++) {
|
||||||
|
int *j = malloc(sizeof(int));
|
||||||
|
*j = i;
|
||||||
|
pthread_create(&workers[i], NULL, workerThread, j);
|
||||||
|
}
|
||||||
|
for(i = 0; i < THREAD_COUNT; i++) {
|
||||||
|
pthread_join(workers[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
} END_TEST
|
||||||
|
|
||||||
|
Suite * check_suite(void) {
|
||||||
|
Suite *s = suite_create("lockManager");
|
||||||
|
/* Begin a new test */
|
||||||
|
TCase *tc = tcase_create("multithreaded");
|
||||||
|
|
||||||
|
/* Sub tests are added, one per line, here */
|
||||||
|
|
||||||
|
tcase_add_test(tc, lockManagerTest);
|
||||||
|
|
||||||
|
/* --------------------------------------------- */
|
||||||
|
|
||||||
|
tcase_add_checked_fixture(tc, setup, teardown);
|
||||||
|
|
||||||
|
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "../check_setup.h"
|
Loading…
Reference in a new issue