AC_CHECK_HEADERS([getopt.h time.h],,, [AC_INCLUDES_DEFAULT])
-CHECK_COMPILER_FLAG_NEEDED(-std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600,
+CHECK_COMPILER_FLAG_NEEDED(-std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE,
[
#include "confdefs.h"
#include <stdlib.h>
str = gai_strerror(0);
return a;
}
-], [CFLAGS="$CFLAGS -std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600"])
+], [CFLAGS="$CFLAGS -std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE"])
CHECK_COMPILER_FLAG_NEEDED(-std=c99,
[
+22 March 2007: Wouter
+ - AIX configure check.
+ - lock-verify can handle references to locks that are created
+ in files it has not yet read in.
+ - threaded hash table test.
+ - unit test runs lock-verify afterwards and checks result.
+
21 March 2007: Wouter
- unit test of hash table, fixup locking problem in table_grow().
- fixup accounting of sizes for removing items from hashtable.
if( abs((int)(the_time - t)) > 3600)
fatal_exit("input files from different times: %u %u",
(unsigned)the_time, (unsigned)t);
- printf(" trace of thread %d\n", thrno);
+ printf(" trace of thread %u:%d\n", (unsigned)p, thrno);
}
return 1;
}
fatal_exit("fread: %s", strerror(errno));
o->smaller = rbtree_create(order_lock_cmp);
o->node.key = &o->id;
+ if(!rbtree_insert(all, &o->node)) {
+ /* already inserted */
+ struct order_lock* a = (struct order_lock*)rbtree_search(all,
+ &o->id);
+ log_assert(a);
+ a->create_file = o->create_file;
+ a->create_line = o->create_line;
+ free(o->smaller);
+ free(o);
+ o = a;
+ }
+ if(verb) printf("read create %u %u %s %d\n",
+ (unsigned)o->id.thr, (unsigned)o->id.instance,
+ o->create_file, o->create_line);
+}
+
+/** insert lock entry (empty) into list */
+static struct order_lock*
+insert_lock(rbtree_t* all, struct order_id* id)
+{
+ struct order_lock* o = calloc(1, sizeof(struct order_lock));
+ if(!o) fatal_exit("malloc failure");
+ o->smaller = rbtree_create(order_lock_cmp);
+ o->id = *id;
+ o->node.key = &o->id;
if(!rbtree_insert(all, &o->node))
- fatal_exit("lock created twice");
- if(verb) printf("read create %s %d\n", o->create_file, o->create_line);
+ fatal_exit("insert fail should not happen");
+ return o;
}
/** read lock entry */
!readup_str(&ref->file, in) ||
fread(&ref->line, sizeof(int), 1, in) != 1)
fatal_exit("fread: %s", strerror(errno));
- if(verb) printf("read lock %s %d\n", ref->file, ref->line);
+ if(verb) printf("read lock %u %u %u %u %s %d\n",
+ (unsigned)prev_id.thr, (unsigned)prev_id.instance,
+ (unsigned)now_id.thr, (unsigned)now_id.instance,
+ ref->file, ref->line);
/* find the two locks involved */
prev = (struct order_lock*)rbtree_search(all, &prev_id);
now = (struct order_lock*)rbtree_search(all, &now_id);
- if(!prev || !now)
- fatal_exit("Could not find locks involved.");
+ /* if not there - insert 'em */
+ if(!prev) prev = insert_lock(all, &prev_id);
+ if(!now) now = insert_lock(all, &now_id);
ref->lock = prev;
ref->node.key = &prev->id;
if(!rbtree_insert(now->smaller, &ref->node)) {
start.file = lock->create_file;
start.line = lock->create_line;
+ if(!lock->create_file)
+ log_err("lock %u %u does not have create info",
+ (unsigned)lock->id.thr, (unsigned)lock->id.instance);
+
/* depth first search to find cycle with this lock at head */
lock->dfs_next = NULL;
search_cycle(&start, 0, &start);
i, (int)all_locks->count,
lock->id.thr, lock->id.instance,
lock->create_file, lock->create_line);
- else if (i % 100 == 0)
+ else if (i % (all_locks->count/75) == 0)
fprintf(stderr, ".");
i++;
check_order_lock(lock);
/** test adding a random element (unlimited range) */
static void
-testadd_unlim(struct lruhash* table, struct testdata* ref[])
+testadd_unlim(struct lruhash* table, struct testdata** ref)
{
int numtoadd = random() % (HASHTESTMAX * 10);
struct testdata* data = newdata(numtoadd);
struct testkey* key = newkey(numtoadd);
key->entry.data = data;
lruhash_insert(table, myhash(numtoadd), &key->entry, data);
- ref[numtoadd] = data;
+ if(ref)
+ ref[numtoadd] = data;
}
/** test adding a random element (unlimited range) */
static void
-testremove_unlim(struct lruhash* table, struct testdata* ref[])
+testremove_unlim(struct lruhash* table, struct testdata** ref)
{
int num = random() % (HASHTESTMAX*10);
struct testkey* key = newkey(num);
lruhash_remove(table, myhash(num), key);
- ref[num] = NULL;
+ if(ref)
+ ref[num] = NULL;
delkey(key);
}
/** test adding a random element (unlimited range) */
static void
-testlookup_unlim(struct lruhash* table, struct testdata* ref[])
+testlookup_unlim(struct lruhash* table, struct testdata** ref)
{
int num = random() % (HASHTESTMAX*10);
struct testkey* key = newkey(num);
unit_assert(en->key);
unit_assert(en->data);
}
- if(0) log_info("lookup unlim %d got %d, expect %d", num, en ?
+ if(0 && ref) log_info("lookup unlim %d got %d, expect %d", num, en ?
data->data :-1, ref[num] ? ref[num]->data : -1);
- if(data) {
+ if(data && ref) {
/* its okay for !data, it fell off the lru */
unit_assert( data == ref[num] );
}
}
}
+/** structure to threaded test the lru hash table */
+struct test_thr {
+ /** thread num, first entry. */
+ int num;
+ /** id */
+ ub_thread_t id;
+ /** hash table */
+ struct lruhash* table;
+};
+
+/** main routine for threaded hash table test */
+static void*
+test_thr_main(void* arg)
+{
+ struct test_thr* t = (struct test_thr*)arg;
+ int i;
+ log_thread_set(&t->num);
+ for(i=0; i<1000; i++) {
+ switch(random() % 4) {
+ case 0:
+ case 3:
+ testadd_unlim(t->table, NULL);
+ break;
+ case 1:
+ testremove_unlim(t->table, NULL);
+ break;
+ case 2:
+ testlookup_unlim(t->table, NULL);
+ break;
+ default:
+ unit_assert(0);
+ }
+ if(0) lruhash_status(t->table, "hashtest", 1);
+ if(i % 100 == 0) /* because of locking, not all the time */
+ check_table(t->table);
+ }
+ check_table(t->table);
+ return NULL;
+}
+
+/** test hash table access by multiple threads. */
+static void
+test_threaded_table(struct lruhash* table)
+{
+ int numth = 10;
+ struct test_thr t[100];
+ int i;
+
+ for(i=1; i<numth; i++) {
+ t[i].num = i;
+ t[i].table = table;
+ ub_thread_create(&t[i].id, test_thr_main, &t[i]);
+ }
+
+ for(i=1; i<numth; i++) {
+ ub_thread_join(t[i].id);
+ }
+ if(0) lruhash_status(table, "hashtest", 1);
+}
+
void lruhash_test()
{
/* start very very small array, so it can do lots of table_grow() */
test_lru(table);
test_short_table(table);
test_long_table(table);
- /* hashtable tests go here */
+ lruhash_delete(table);
+ table = lruhash_create(2, 4096,
+ test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
+ test_threaded_table(table);
lruhash_delete(table);
}