Home | History | Annotate | Line # | Download | only in testcode
      1      1.1  christos /*
      2      1.1  christos  * testcode/lock_verify.c - verifier program for lock traces, checks order.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * This software is open source.
      7      1.1  christos  *
      8      1.1  christos  * Redistribution and use in source and binary forms, with or without
      9      1.1  christos  * modification, are permitted provided that the following conditions
     10      1.1  christos  * are met:
     11      1.1  christos  *
     12      1.1  christos  * Redistributions of source code must retain the above copyright notice,
     13      1.1  christos  * this list of conditions and the following disclaimer.
     14      1.1  christos  *
     15      1.1  christos  * Redistributions in binary form must reproduce the above copyright notice,
     16      1.1  christos  * this list of conditions and the following disclaimer in the documentation
     17      1.1  christos  * and/or other materials provided with the distribution.
     18      1.1  christos  *
     19      1.1  christos  * Neither the name of the NLNET LABS nor the names of its contributors may
     20      1.1  christos  * be used to endorse or promote products derived from this software without
     21      1.1  christos  * specific prior written permission.
     22      1.1  christos  *
     23      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24      1.1  christos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25      1.1  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26      1.1  christos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27      1.1  christos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28      1.1  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29      1.1  christos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30      1.1  christos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31      1.1  christos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32      1.1  christos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33      1.1  christos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34      1.1  christos  */
     35      1.1  christos 
     36      1.1  christos /**
     37      1.1  christos  * \file
     38      1.1  christos  *
     39      1.1  christos  * This file checks the lock traces generated by checklock.c.
     40      1.1  christos  * Checks if locks are consistently locked in the same order.
     41      1.1  christos  * If not, this can lead to deadlock if threads execute the different
     42      1.1  christos  * ordering at the same time.
     43      1.1  christos  *
     44      1.1  christos  */
     45      1.1  christos 
     46      1.1  christos #include "config.h"
     47      1.1  christos #ifdef HAVE_TIME_H
     48      1.1  christos #include <time.h>
     49      1.1  christos #endif
     50      1.1  christos #include "util/log.h"
     51      1.1  christos #include "util/rbtree.h"
     52      1.1  christos #include "util/locks.h"
     53      1.1  christos #include "util/fptr_wlist.h"
     54      1.1  christos 
     55      1.1  christos /* --- data structures --- */
     56      1.1  christos struct lock_ref;
     57      1.1  christos 
     58      1.1  christos /** keep track of lock id in lock-verify application
     59      1.1  christos  * Also defined in smallapp/worker_cb.c for fptr_wlist encapsulation
     60      1.1  christos  * breakage (the security tests break encapsulation for this test app) */
     61      1.1  christos struct order_id {
     62      1.1  christos         /** the thread id that created it */
     63      1.1  christos         int thr;
     64      1.1  christos         /** the instance number of creation */
     65      1.1  christos         int instance;
     66      1.1  christos };
     67      1.1  christos 
     68      1.1  christos /** a lock */
     69      1.1  christos struct order_lock {
     70      1.1  christos 	/** rbnode in all tree */
     71  1.1.1.2  christos 	rbnode_type node;
     72      1.1  christos 	/** lock id */
     73      1.1  christos 	struct order_id id;
     74      1.1  christos 	/** the creation file */
     75      1.1  christos 	char* create_file;
     76      1.1  christos 	/** creation line */
     77      1.1  christos 	int create_line;
     78      1.1  christos 	/** set of all locks that are smaller than this one (locked earlier) */
     79  1.1.1.2  christos 	rbtree_type* smaller;
     80      1.1  christos 	/** during depthfirstsearch, this is a linked list of the stack
     81      1.1  christos 	 * of locks. points to the next lock bigger than this one. */
     82      1.1  christos 	struct lock_ref* dfs_next;
     83      1.1  christos 	/** if lock has been visited (all smaller locks have been compared to
     84      1.1  christos 	 * this lock), only need to compare this with all unvisited(bigger)
     85      1.1  christos 	 * locks */
     86      1.1  christos 	int visited;
     87      1.1  christos };
     88      1.1  christos 
     89      1.1  christos /** reference to a lock in a rbtree set */
     90      1.1  christos struct lock_ref {
     91      1.1  christos 	/** rbnode, key is an order_id ptr */
     92  1.1.1.2  christos 	rbnode_type node;
     93      1.1  christos 	/** the lock referenced */
     94      1.1  christos 	struct order_lock* lock;
     95      1.1  christos 	/** why is this ref */
     96      1.1  christos 	char* file;
     97      1.1  christos 	/** line number */
     98      1.1  christos 	int line;
     99      1.1  christos };
    100      1.1  christos 
    101      1.1  christos /** count of errors detected */
    102      1.1  christos static int errors_detected = 0;
    103      1.1  christos /** verbose? */
    104      1.1  christos static int verb = 0;
    105      1.1  christos 
    106      1.1  christos /** print program usage help */
    107      1.1  christos static void
    108  1.1.1.2  christos usage(void)
    109      1.1  christos {
    110      1.1  christos 	printf("lock_verify <trace files>\n");
    111      1.1  christos }
    112      1.1  christos 
    113      1.1  christos /** read header entry.
    114      1.1  christos  * @param in: file to read header of.
    115      1.1  christos  * @return: False if it does not belong to the rest. */
    116      1.1  christos static int
    117      1.1  christos read_header(FILE* in)
    118      1.1  christos {
    119      1.1  christos 	time_t t;
    120      1.1  christos 	pid_t p;
    121      1.1  christos 	int thrno;
    122      1.1  christos 	static int have_values = 0;
    123      1.1  christos 	static time_t the_time;
    124      1.1  christos 	static pid_t the_pid;
    125      1.1  christos 	static int threads[256];
    126      1.1  christos 
    127      1.1  christos 	if(fread(&t, sizeof(t), 1, in) != 1 ||
    128      1.1  christos 		fread(&thrno, sizeof(thrno), 1, in) != 1 ||
    129      1.1  christos 		fread(&p, sizeof(p), 1, in) != 1) {
    130      1.1  christos 		fatal_exit("fread failed");
    131      1.1  christos 	}
    132      1.1  christos 	/* check these values are sorta OK */
    133      1.1  christos 	if(!have_values) {
    134      1.1  christos 		the_time = t;
    135      1.1  christos 		the_pid = p;
    136      1.1  christos 		memset(threads, 0, 256*sizeof(int));
    137      1.1  christos 		if(thrno >= 256) {
    138      1.1  christos 			fatal_exit("Thread number too big. %d", thrno);
    139      1.1  christos 		}
    140      1.1  christos 		threads[thrno] = 1;
    141      1.1  christos 		have_values = 1;
    142      1.1  christos 		printf(" trace %d from pid %u on %s", thrno,
    143      1.1  christos 			(unsigned)p, ctime(&t));
    144      1.1  christos 	} else {
    145      1.1  christos 		if(the_pid != p) {
    146      1.1  christos 			printf(" has pid %u, not %u. Skipped.\n",
    147      1.1  christos 				(unsigned)p, (unsigned)the_pid);
    148      1.1  christos 			return 0;
    149      1.1  christos 		}
    150      1.1  christos 		if(threads[thrno])
    151      1.1  christos 			fatal_exit("same threadno in two files");
    152      1.1  christos 		threads[thrno] = 1;
    153      1.1  christos 		if( abs((int)(the_time - t)) > 3600)
    154      1.1  christos 			fatal_exit("input files from different times: %u %u",
    155      1.1  christos 				(unsigned)the_time, (unsigned)t);
    156      1.1  christos 		printf(" trace of thread %u:%d\n", (unsigned)p, thrno);
    157      1.1  christos 	}
    158      1.1  christos 	return 1;
    159      1.1  christos }
    160      1.1  christos 
    161      1.1  christos /** max length of strings: filenames and function names. */
    162      1.1  christos #define STRMAX 1024
    163      1.1  christos /** read a string from file, false on error */
    164      1.1  christos static int readup_str(char** str, FILE* in)
    165      1.1  christos {
    166      1.1  christos 	char buf[STRMAX];
    167      1.1  christos 	int len = 0;
    168      1.1  christos 	int c;
    169      1.1  christos 	/* ends in zero */
    170      1.1  christos 	while( (c = fgetc(in)) != 0) {
    171      1.1  christos 		if(c == EOF)
    172      1.1  christos 			fatal_exit("eof in readstr, file too short");
    173      1.1  christos 		buf[len++] = c;
    174      1.1  christos 		if(len == STRMAX) {
    175      1.1  christos 			fatal_exit("string too long, bad file format");
    176      1.1  christos 		}
    177      1.1  christos 	}
    178      1.1  christos 	buf[len] = 0;
    179      1.1  christos 	*str = strdup(buf);
    180  1.1.1.4  christos 	if(!*str)
    181  1.1.1.4  christos 		fatal_exit("strdup failed: out of memory");
    182      1.1  christos 	return 1;
    183      1.1  christos }
    184      1.1  christos 
    185      1.1  christos /** read creation entry */
    186  1.1.1.2  christos static void read_create(rbtree_type* all, FILE* in)
    187      1.1  christos {
    188      1.1  christos 	struct order_lock* o = calloc(1, sizeof(struct order_lock));
    189      1.1  christos 	if(!o) fatal_exit("malloc failure");
    190      1.1  christos 	if(fread(&o->id.thr, sizeof(int), 1, in) != 1 ||
    191      1.1  christos 	   fread(&o->id.instance, sizeof(int), 1, in) != 1 ||
    192      1.1  christos 	   !readup_str(&o->create_file, in) ||
    193      1.1  christos 	   fread(&o->create_line, sizeof(int), 1, in) != 1)
    194      1.1  christos 		fatal_exit("fread failed");
    195      1.1  christos 	o->smaller = rbtree_create(order_lock_cmp);
    196      1.1  christos 	o->node.key = &o->id;
    197      1.1  christos 	if(!rbtree_insert(all, &o->node)) {
    198      1.1  christos 		/* already inserted */
    199      1.1  christos 		struct order_lock* a = (struct order_lock*)rbtree_search(all,
    200      1.1  christos 			&o->id);
    201      1.1  christos 		log_assert(a);
    202      1.1  christos 		a->create_file = o->create_file;
    203      1.1  christos 		a->create_line = o->create_line;
    204      1.1  christos 		free(o->smaller);
    205      1.1  christos 		free(o);
    206      1.1  christos 		o = a;
    207      1.1  christos 	}
    208      1.1  christos 	if(verb) printf("read create %u %u %s %d\n",
    209      1.1  christos 		(unsigned)o->id.thr, (unsigned)o->id.instance,
    210      1.1  christos 		o->create_file, o->create_line);
    211      1.1  christos }
    212      1.1  christos 
    213      1.1  christos /** insert lock entry (empty) into list */
    214      1.1  christos static struct order_lock*
    215  1.1.1.2  christos insert_lock(rbtree_type* all, struct order_id* id)
    216      1.1  christos {
    217      1.1  christos 	struct order_lock* o = calloc(1, sizeof(struct order_lock));
    218      1.1  christos 	if(!o) fatal_exit("malloc failure");
    219      1.1  christos 	o->smaller = rbtree_create(order_lock_cmp);
    220      1.1  christos 	o->id = *id;
    221      1.1  christos 	o->node.key = &o->id;
    222      1.1  christos 	if(!rbtree_insert(all, &o->node))
    223      1.1  christos 		fatal_exit("insert fail should not happen");
    224      1.1  christos 	return o;
    225      1.1  christos }
    226      1.1  christos 
    227      1.1  christos /** read lock entry */
    228  1.1.1.2  christos static void read_lock(rbtree_type* all, FILE* in, int val)
    229      1.1  christos {
    230      1.1  christos 	struct order_id prev_id, now_id;
    231      1.1  christos 	struct lock_ref* ref;
    232      1.1  christos 	struct order_lock* prev, *now;
    233      1.1  christos 	ref = (struct lock_ref*)calloc(1, sizeof(struct lock_ref));
    234      1.1  christos 	if(!ref) fatal_exit("malloc failure");
    235      1.1  christos 	prev_id.thr = val;
    236      1.1  christos 	if(fread(&prev_id.instance, sizeof(int), 1, in) != 1 ||
    237      1.1  christos 	   fread(&now_id.thr, sizeof(int), 1, in) != 1 ||
    238      1.1  christos 	   fread(&now_id.instance, sizeof(int), 1, in) != 1 ||
    239      1.1  christos 	   !readup_str(&ref->file, in) ||
    240      1.1  christos 	   fread(&ref->line, sizeof(int), 1, in) != 1)
    241      1.1  christos 		fatal_exit("fread failed");
    242      1.1  christos 	if(verb) printf("read lock %u %u %u %u %s %d\n",
    243      1.1  christos 		(unsigned)prev_id.thr, (unsigned)prev_id.instance,
    244      1.1  christos 		(unsigned)now_id.thr, (unsigned)now_id.instance,
    245      1.1  christos 		ref->file, ref->line);
    246      1.1  christos 	/* find the two locks involved */
    247      1.1  christos 	prev = (struct order_lock*)rbtree_search(all, &prev_id);
    248      1.1  christos 	now = (struct order_lock*)rbtree_search(all, &now_id);
    249      1.1  christos 	/* if not there - insert 'em */
    250      1.1  christos 	if(!prev) prev = insert_lock(all, &prev_id);
    251      1.1  christos 	if(!now) now = insert_lock(all, &now_id);
    252      1.1  christos 	ref->lock = prev;
    253      1.1  christos 	ref->node.key = &prev->id;
    254      1.1  christos 	if(!rbtree_insert(now->smaller, &ref->node)) {
    255      1.1  christos 		free(ref->file);
    256      1.1  christos 		free(ref);
    257      1.1  christos 	}
    258      1.1  christos }
    259      1.1  christos 
    260      1.1  christos /** read input file */
    261  1.1.1.2  christos static void readinput(rbtree_type* all, char* file)
    262      1.1  christos {
    263      1.1  christos 	FILE *in = fopen(file, "r");
    264      1.1  christos 	int fst;
    265      1.1  christos 	if(!in) {
    266      1.1  christos 		perror(file);
    267      1.1  christos 		exit(1);
    268      1.1  christos 	}
    269      1.1  christos 	printf("file %s", file);
    270      1.1  christos 	if(!read_header(in)) {
    271      1.1  christos 		fclose(in);
    272      1.1  christos 		return;
    273      1.1  christos 	}
    274      1.1  christos 	while(fread(&fst, sizeof(fst), 1, in) == 1) {
    275      1.1  christos 		if(fst == -1)
    276      1.1  christos 			read_create(all, in);
    277      1.1  christos 		else	read_lock(all, in, fst);
    278      1.1  christos 	}
    279      1.1  christos 	fclose(in);
    280      1.1  christos }
    281      1.1  christos 
    282      1.1  christos /** print cycle message */
    283      1.1  christos static void found_cycle(struct lock_ref* visit, int level)
    284      1.1  christos {
    285      1.1  christos 	struct lock_ref* p;
    286      1.1  christos 	int i = 0;
    287      1.1  christos 	errors_detected++;
    288      1.1  christos 	printf("Found inconsistent locking order of length %d\n", level);
    289      1.1  christos 	printf("for lock %d %d created %s %d\n",
    290      1.1  christos 		visit->lock->id.thr, visit->lock->id.instance,
    291      1.1  christos 		visit->lock->create_file, visit->lock->create_line);
    292      1.1  christos 	printf("sequence is:\n");
    293      1.1  christos 	p = visit;
    294      1.1  christos 	while(p) {
    295      1.1  christos 		struct order_lock* next =
    296      1.1  christos 			p->lock->dfs_next?p->lock->dfs_next->lock:visit->lock;
    297      1.1  christos 		printf("[%d] is locked at line %s %d before lock %d %d\n",
    298      1.1  christos 			i, p->file, p->line, next->id.thr, next->id.instance);
    299      1.1  christos 		printf("[%d] lock %d %d is created at %s %d\n",
    300      1.1  christos 			i, next->id.thr, next->id.instance,
    301      1.1  christos 			next->create_file, next->create_line);
    302      1.1  christos 		i++;
    303      1.1  christos 		p = p->lock->dfs_next;
    304      1.1  christos 		if(p && p->lock == visit->lock)
    305      1.1  christos 			break;
    306      1.1  christos 	}
    307      1.1  christos }
    308      1.1  christos 
    309      1.1  christos /** Detect cycle by comparing visited now with all (unvisited) bigger nodes */
    310      1.1  christos static int detect_cycle(struct lock_ref* visit, struct lock_ref* from)
    311      1.1  christos {
    312      1.1  christos 	struct lock_ref* p = from;
    313      1.1  christos 	while(p) {
    314      1.1  christos 		if(p->lock == visit->lock)
    315      1.1  christos 			return 1;
    316      1.1  christos 		p = p->lock->dfs_next;
    317      1.1  christos 	}
    318      1.1  christos 	return 0;
    319      1.1  christos }
    320      1.1  christos 
    321      1.1  christos /** recursive function to depth first search for cycles.
    322      1.1  christos  * @param visit: the lock visited at this step.
    323      1.1  christos  *	its dfs_next pointer gives the visited lock up in recursion.
    324      1.1  christos  * 	same as lookfor at level 0.
    325      1.1  christos  * @param level: depth of recursion. 0 is start.
    326      1.1  christos  * @param from: search for matches from unvisited node upwards.
    327      1.1  christos  */
    328      1.1  christos static void search_cycle(struct lock_ref* visit, int level,
    329      1.1  christos 	struct lock_ref* from)
    330      1.1  christos {
    331      1.1  christos 	struct lock_ref* ref;
    332      1.1  christos 	/* check for cycle */
    333      1.1  christos 	if(detect_cycle(visit, from) && level != 0) {
    334      1.1  christos 		found_cycle(visit, level);
    335      1.1  christos 		fatal_exit("found lock order cycle");
    336      1.1  christos 	}
    337      1.1  christos 	/* recurse */
    338      1.1  christos 	if(!visit->lock->visited)
    339      1.1  christos 		from = visit;
    340      1.1  christos 	if(verb > 1) fprintf(stderr, "[%d] visit lock %u %u %s %d\n", level,
    341      1.1  christos 			(unsigned)visit->lock->id.thr,
    342      1.1  christos 			(unsigned)visit->lock->id.instance,
    343      1.1  christos 			visit->lock->create_file, visit->lock->create_line);
    344      1.1  christos 	RBTREE_FOR(ref, struct lock_ref*, visit->lock->smaller) {
    345      1.1  christos 		ref->lock->dfs_next = visit;
    346      1.1  christos 		search_cycle(ref, level+1, from);
    347      1.1  christos 	}
    348      1.1  christos 	visit->lock->visited = 1;
    349      1.1  christos }
    350      1.1  christos 
    351      1.1  christos /** Check ordering of one lock */
    352      1.1  christos static void check_order_lock(struct order_lock* lock)
    353      1.1  christos {
    354      1.1  christos 	struct lock_ref start;
    355      1.1  christos 	if(lock->visited) return;
    356      1.1  christos 
    357      1.1  christos 	start.node.key = &lock->id;
    358      1.1  christos 	start.lock = lock;
    359      1.1  christos 	start.file = lock->create_file;
    360      1.1  christos 	start.line = lock->create_line;
    361      1.1  christos 
    362      1.1  christos 	if(!lock->create_file)
    363      1.1  christos 		log_err("lock %u %u does not have create info",
    364      1.1  christos 			(unsigned)lock->id.thr, (unsigned)lock->id.instance);
    365      1.1  christos 
    366      1.1  christos 	/* depth first search to find cycle with this lock at head */
    367      1.1  christos 	lock->dfs_next = NULL;
    368      1.1  christos 	search_cycle(&start, 0, &start);
    369      1.1  christos }
    370      1.1  christos 
    371      1.1  christos /** Check ordering of locks */
    372  1.1.1.2  christos static void check_order(rbtree_type* all_locks)
    373      1.1  christos {
    374      1.1  christos 	/* check each lock */
    375      1.1  christos 	struct order_lock* lock;
    376      1.1  christos 	int i=0;
    377      1.1  christos 	RBTREE_FOR(lock, struct order_lock*, all_locks) {
    378      1.1  christos 		if(verb)
    379      1.1  christos 		    printf("[%d/%d] Checking lock %d %d %s %d\n",
    380      1.1  christos 			i, (int)all_locks->count,
    381      1.1  christos 			lock->id.thr, lock->id.instance,
    382      1.1  christos 			lock->create_file, lock->create_line);
    383      1.1  christos 		else if (i % ((all_locks->count/75)<1?1:all_locks->count/75)
    384      1.1  christos 			== 0)
    385      1.1  christos 		    fprintf(stderr, ".");
    386      1.1  christos 		i++;
    387      1.1  christos 		check_order_lock(lock);
    388      1.1  christos 	}
    389      1.1  christos 	fprintf(stderr, "\n");
    390      1.1  christos }
    391      1.1  christos 
    392  1.1.1.3  christos /** delete lock ref */
    393  1.1.1.3  christos static void dellockref(rbnode_type* node, void* ATTR_UNUSED(arg))
    394  1.1.1.3  christos {
    395  1.1.1.3  christos 	struct lock_ref* o = (struct lock_ref*)node;
    396  1.1.1.3  christos 	if(!o) return;
    397  1.1.1.3  christos 	free(o->file);
    398  1.1.1.3  christos 	free(o);
    399  1.1.1.3  christos }
    400  1.1.1.3  christos 
    401  1.1.1.3  christos /** delete lock node */
    402  1.1.1.3  christos static void delnode(rbnode_type* node, void* ATTR_UNUSED(arg))
    403  1.1.1.3  christos {
    404  1.1.1.3  christos 	struct order_lock* o = (struct order_lock*)node;
    405  1.1.1.3  christos 	if(!o) return;
    406  1.1.1.3  christos 	free(o->create_file);
    407  1.1.1.3  christos 	if(o->smaller) {
    408  1.1.1.3  christos 		traverse_postorder(o->smaller, &dellockref, NULL);
    409  1.1.1.3  christos 		free(o->smaller);
    410  1.1.1.3  christos 	}
    411  1.1.1.3  christos 	free(o);
    412  1.1.1.3  christos }
    413  1.1.1.3  christos 
    414  1.1.1.3  christos /** delete allocated memory */
    415  1.1.1.3  christos static void locks_free(rbtree_type* all_locks)
    416  1.1.1.3  christos {
    417  1.1.1.3  christos 	if(!all_locks)
    418  1.1.1.3  christos 		return;
    419  1.1.1.3  christos 	traverse_postorder(all_locks, &delnode, NULL);
    420  1.1.1.3  christos 	free(all_locks);
    421  1.1.1.3  christos }
    422  1.1.1.3  christos 
    423      1.1  christos /** main program to verify all traces passed */
    424      1.1  christos int
    425      1.1  christos main(int argc, char* argv[])
    426      1.1  christos {
    427  1.1.1.2  christos 	rbtree_type* all_locks;
    428      1.1  christos 	int i;
    429      1.1  christos 	time_t starttime = time(NULL);
    430      1.1  christos #ifdef USE_THREAD_DEBUG
    431      1.1  christos 	/* do not overwrite the ublocktrace files with the ones generated
    432      1.1  christos 	 * by this program (i.e. when the log code creates a lock) */
    433      1.1  christos 	check_locking_order = 0;
    434      1.1  christos #endif
    435      1.1  christos 	if(argc <= 1) {
    436      1.1  christos 		usage();
    437      1.1  christos 		return 1;
    438      1.1  christos 	}
    439  1.1.1.3  christos 	checklock_start();
    440      1.1  christos 	log_init(NULL, 0, NULL);
    441      1.1  christos 	log_ident_set("lock-verify");
    442      1.1  christos 	/* init */
    443      1.1  christos 	all_locks = rbtree_create(order_lock_cmp);
    444      1.1  christos 	errors_detected = 0;
    445      1.1  christos 
    446      1.1  christos 	/* read the input files */
    447      1.1  christos 	for(i=1; i<argc; i++) {
    448      1.1  christos 		readinput(all_locks, argv[i]);
    449      1.1  christos 	}
    450      1.1  christos 
    451      1.1  christos 	/* check ordering */
    452      1.1  christos 	check_order(all_locks);
    453      1.1  christos 
    454      1.1  christos 	/* do not free a thing, OS will do it */
    455      1.1  christos 	printf("checked %d locks in %d seconds with %d errors.\n",
    456      1.1  christos 		(int)all_locks->count, (int)(time(NULL)-starttime),
    457      1.1  christos 		errors_detected);
    458  1.1.1.3  christos 	locks_free(all_locks);
    459      1.1  christos 	if(errors_detected) return 1;
    460      1.1  christos 	return 0;
    461      1.1  christos }
    462