/* * testcode/lock_verify.c - verifier program for lock traces, checks order. * * Copyright (c) 2007, NLnet Labs. All rights reserved. * * This software is open source. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the NLNET LABS nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * \file * * This file checks the lock traces generated by checklock.c. * Checks if locks are consistently locked in the same order. * If not, this can lead to deadlock if threads execute the different * ordering at the same time. * */ #include "config.h" #include "util/log.h" #include "util/rbtree.h" /* --- data structures --- */ /** a lock */ struct order_lock { /** rbnode in all tree */ rbnode_t node; /** the thread id that created it */ int thr; /** the instance number of creation */ int instance; /** the creation file */ char* create_file; /** creation line */ int create_line; /** set of all locks that are smaller than this one (locked earlier) */ rbtree_t* smaller; }; /** reference to a lock in a rbtree set */ struct lock_ref { /** rbnode, key is an order_lock ptr */ rbnode_t node; }; /** print program usage help */ static void usage() { printf("lock_verify \n"); } /** compare two order_locks */ int order_lock_cmp(const void* e1, const void* e2) { struct order_lock* o1 = (struct order_lock*)e1; struct order_lock* o2 = (struct order_lock*)e2; if(o1->thr < o2->thr) return -1; if(o1->thr > o2->thr) return 1; if(o1->instance < o2->instance) return -1; if(o1->instance > o2->instance) return 1; return 0; } /** read header entry */ static void read_header(FILE* in) { time_t t; pid_t p; int thrno; static int have_values = 0; static time_t the_time; static pid_t the_pid; static int threads[256]; if(fread(&t, sizeof(t), 1, in) != 1 || fread(&thrno, sizeof(thrno), 1, in) != 1 || fread(&p, sizeof(p), 1, in) != 1) { fatal_exit("fread: %s", strerror(errno)); } /* check these values are sorta OK */ if(!have_values) { the_time = t; the_pid = p; memset(threads, 0, 256*sizeof(int)); threads[thrno] = 1; have_values = 1; printf("Trace from pid %u on %s", (unsigned)p, ctime(&t)); } else { if(the_pid != p) fatal_exit("different pids in input files"); if(threads[thrno]) fatal_exit("same threadno in two files"); threads[thrno] = 1; if( abs(the_time - t) > 3600) fatal_exit("input files from different times: %u %u", (unsigned)the_time, (unsigned)t); } printf("reading trace of thread %d\n", thrno); } /** read a string from file, false on error */ static int readup_str(char** str, FILE* in) { #define STRMAX 1024 char buf[STRMAX]; int len = 0; int c; /* ends in zero */ while( (c = fgetc(in)) != 0) { if(c == EOF) fatal_exit("eof in readstr, file too short"); buf[len++] = c; if(len == STRMAX) { fatal_exit("string too long, bad file format"); } } buf[len] = 0; *str = strdup(buf); return 1; } /** read creation entry */ static void read_create(rbtree_t* all, FILE* in) { struct order_lock* o = calloc(1, sizeof(struct order_lock)); if(!o) fatal_exit("malloc failure"); if(fread(&o->thr, sizeof(int), 1, in) != 1 || fread(&o->instance, sizeof(int), 1, in) != 1 || !readup_str(&o->create_file, in) || fread(&o->create_line, sizeof(int), 1, in) != 1) fatal_exit("fread: %s", strerror(errno)); o->smaller = rbtree_create(order_lock_cmp); o->node.key = o; rbtree_insert(all, &o->node); printf("read create %s %d\n", o->create_file, o->create_line); } /** read lock entry */ static void read_lock(rbtree_t* all, FILE* in, int val) { } /** read input file */ static void readinput(rbtree_t* all, char* file) { FILE *in = fopen(file, "r"); int fst; if(!in) { perror(file); exit(1); } printf("reading file %s\n", file); read_header(in); while(fread(&fst, sizeof(fst), 1, in) == 1) { if(fst == -1) read_create(all, in); else read_lock(all, in, fst); } fclose(in); } /** main program to verify all traces passed */ int main(int argc, char* argv[]) { rbtree_t* all_locks; int i; if(argc <= 1) { usage(); return 1; } log_init(NULL); log_ident_set("lock-verify"); /* init */ all_locks = rbtree_create(order_lock_cmp); /* read the input files */ for(i=1; i