1 /* BLURB gpl
2 
3                            Coda File System
4                               Release 5
5 
6           Copyright (c) 1987-2016 Carnegie Mellon University
7                   Additional copyrights listed below
8 
9 This  code  is  distributed "AS IS" without warranty of any kind under
10 the terms of the GNU General Public Licence Version 2, as shown in the
11 file  LICENSE.  The  technical and financial  contributors to Coda are
12 listed in the file CREDITS.
13 
14                         Additional copyrights
15                            none currently
16 
17 #*/
18 
19 /*
20 *
21 *			RVM Stress Test Program
22 *
23 */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <string.h>
40 #include <time.h>
41 
42 #include <rvm/rvm.h>
43 #include <rvm/rvm_statistics.h>
44 #include <rvm/rvm_segment.h>
45 #include <rvm/rds.h>
46 
47 #ifdef __CYGWIN32__
48 /* XXX MJC: hack -- no random(), srandom() so use rand() (and forget about
49   setting seeds for now */
50 #define random rand
51 #define srandom
52 #endif
53 
54 #ifndef RVM_MAJOR_VERSION
55 #define RVM_MAJOR_VERSION     1
56 #endif /* RVM_MAJOR_VERSION */
57 #ifndef RVM_MINOR_VERSION
58 #define RVM_MINOR_VERSION     3
59 #endif /* RVM_MINOR_VERSION */
60 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
61 #include "rvm_query.h"
62 #endif /* VERSION_TEST */
63 
64 #ifdef RVM_USELWP
65 #include "rvm_lwp.h"
66 #elif defined(RVM_USEPT)
67 #include "rvm_pthread.h"
68 #else /* fake cthreads wrapper */
69 /* XXX bogus by Eric and Peter to get compile */
70 #include <cthreads.h>
71 /* define types symbolically to permit use of non-Cthread thread support */
72 #define RVM_MUTEX       struct mutex
73 #define RVM_CONDITION	struct condition
74 #endif
75 
76 extern rvm_region_def_t *RegionDefs;    /* hooks to rds */
77 extern long NRegionDefs;
78 extern rvm_bool_t rds_testsw;                 /* special test mode switch */
79 
80 #ifdef CODA_ASSERT
81 #undef CODA_ASSERT
82 #endif
83 #define CODA_ASSERT(ex) \
84     { \
85     if (!(ex)) \
86         { \
87         fprintf(stderr,"ASSERTion failed: file \"%s\", line %d\n", \
88                 __FILE__, __LINE__); \
89         fflush(stderr); \
90         abort(); \
91          } \
92     }
93 
94 #undef CRITICAL
95 #define CRITICAL(lock,body) do { \
96     mutex_lock(&lock); { body } mutex_unlock(&lock); \
97 } while(0)
98 
99 typedef struct list_entry_s
100     {
101     struct list_entry_s *nextentry;	/* in accordance with insque(3) */
102     struct list_entry_s *preventry;
103     union
104         {
105         struct list_entry_s  *name;     /* back pointer to head of list */
106         int                  length;    /* length of list if header */
107         }               list;
108     rvm_bool_t          is_header;      /* true if list header */
109     }
110 list_entry_t;
111 
112 typedef struct
113     {
114     list_entry_t    links;              /* allocated list links */
115     int             size;               /* usable size of block */
116     rvm_length_t    chksum;             /* block checksum */
117     char            *ptr;               /* ptr to rds allocated space */
118     }
119 block_t;
120 /* system variables */
121 #define CMD_MAX     2048                /* maximum cmd line length */
122 static char         cmd_line[CMD_MAX];  /* command line buffer */
123 static char         *cmd_cur;           /* ptr to current command line
124                                            position */
125 
126 list_entry_t        alloc_list;         /* list of allocated blocks */
127 RVM_MUTEX           alloc_list_lock;    /* protects list header & block links */
128 
129 int		    nthreads = 0;       /* Number of threads */
130 cthread_t	    *threads;           /* thread handles vector */
131 int                 *last;              /* last operation of thread */
132 rvm_bool_t          Terminate = rvm_false; /* thread exit switch */
133 RVM_MUTEX           init_lock;          /* syncronize worker start */
134 RVM_MUTEX           thread_lock = MUTEX_INITIALIZER; /* lock for thread exit code */
135 RVM_CONDITION	    init_cv;		/* signal thread start completion */
136 RVM_CONDITION       thread_exit_code;   /* code to signal termination to main */
137 
138 RVM_MUTEX           chk_lock = MUTEX_INITIALIZER; /* segment checker variables */
139 rvm_bool_t          chk_block;          /* require threads to block for chk */
140 RVM_CONDITION       blk_code;           /* blocked threads wait code */
141 RVM_CONDITION       chk_code;           /* checker wait code */
142 int                 blk_cnt;            /* counter for blocked threads */
143 rvm_length_t        optimizations;      /* optimizations used in test */
144 int                 max_cycles;         /* maximum operation loop cycles */
145 int                 max_ranges;         /* maximum number ranges/trans */
146 int                 max_trans;          /* max number trans per modify test */
147 int                 max_block_size;     /* maximum modification block size */
148 int                 max_mod_size;       /* maximum modification size */
149 int                 max_moby_size;      /* maximum moby modification size */
150 int                 num_pre_alloc;      /* number of blocks to preallocate */
151 int                 cycle;              /* operation loop cycle count */
152 int                 op_cnt;             /* basher operation count */
153 int                 max_op_cnt;         /* operation count threshold */
154 int                 chk_range_frac;     /* fraction of ranges to check */
155 int                 abort_frac;         /* fraction of trans to abort */
156 int                 restore_frac;       /* fraction of trans to begin in
157                                            restore mode and commit */
158 int                 flush_frac;         /* fraction of trans to commit/flush  */
159 int                 trunc_frac;         /* truncation threshold */
160 int                 epoch_trunc_frac;   /* epoch truncation threshold */
161 int                 incr_trunc_time;    /* incr trunc run time slice */
162 int                 seed;               /* random num gen seed */
163 int                 chk_alloc;          /* allocation checking level */
164 rvm_offset_t	    DataLen;            /* length of data raw partition */
165 char                DataFileName[MAXPATHLEN+1]; /* heap segment file name */
166 char                LogFileName[MAXPATHLEN+1]; /* log file name */
167 char                PlumberFileName[MAXPATHLEN+1]; /* plumber file name */
168 FILE                *PlumberFile;       /* file descriptor for plumber file */
169 struct timeval      init_time;          /* time when test run started */
170 rvm_length_t        rec_buf_len;        /* recovery buffer length */
171 rvm_length_t        flush_buf_len;      /* flush buffer length */
172 rvm_length_t        max_read_len;       /* maximum read length */
173 rvm_bool_t          all_tests;          /* do all tests */
174 rvm_bool_t          time_tests;         /* timestamp op loop if true */
175 rvm_bool_t          vm_test;            /* compare vm with segment if true */
176 rvm_bool_t          moby_test;          /* do large range test if true */
177 rvm_bool_t          chk_sum_sw;         /* request checksumming */
178 rvm_bool_t          no_yield_sw;        /* request no-yield truncations */
179 rvm_bool_t          vm_protect_sw;      /* request vm buffer protection */
180 rvm_bool_t          pre_alloc_trunc;    /* truncate after preallocation */
181 rvm_bool_t          show_brk;           /* print break point */
182 rvm_bool_t	    do_private_map;	/* Do a private mapping */
183 
184 FILE               *para_file;          /* parameter file */
185 
186 /* string name lookup entry declarations */
187 
188 typedef enum
189     {
190     UNKNOWN = -123456789,               /* unknown string key */
191 
192     ALL_KEY = 1,                        /* key for do all entities */
193     ABORT_KEY,                          /* set abort fraction key */
194     BLOCK_SIZE_KEY,                     /* allocation block size key */
195     BRK_KEY,                            /* show break point key */
196     CHK_ALLOC_KEY,                      /* allocation checker key */
197     CHK_SUM_KEY,                        /* rvm_chk_sum key */
198     CYCLES_KEY,                         /* number of cycles key */
199     DATA_KEY,                           /* set data file key */
200     FLUSH_KEY,                          /* set flush fraction key */
201     FLUSH_BUF_KEY,                      /* set flush buffer length key */
202     INCR_KEY,                           /* enable incrmental truncation key */
203     LOG_KEY,                            /* set log file key */
204     MAX_READ_KEY,                       /* set max read length key */
205     MOBY_KEY,                           /* moby range test key */
206     MOBY_MAX_KEY,                       /* maximum moby range size key */
207     MOD_SIZE_KEY,                       /* maximum modification size key */
208     NONE_KEY,                           /* no choices key */
209     OPS_KEY,                            /* number of operations/cycle key */
210     OPT_KEY,                            /* set optimizations key */
211     PARMS_KEY,                          /* show test parameters key */
212     PLUMBER_KEY,                        /* setup plumber file key */
213     PRE_ALLOC_KEY,                      /* number of blocks to preallocate */
214     PRE_ALLOC_TRUNC_KEY,                /* truncate after preallocation */
215     PRIORITY_KEY,                       /* set run priority */
216     QUIT_KEY,                           /* quit program key */
217     RANGES_KEY,                         /* set num ranges key */
218     REC_BUF_KEY,                        /* set recovery buffer length */
219     RESTORE_KEY,                        /* set restore fraction key */
220     RUN_KEY,                            /* start tests key */
221     SEED_KEY,                           /* random num gen key */
222     THREADS_KEY,                        /* set num threads key */
223     TIME_KEY,                           /* timestamp cycle key */
224     TRANS_KEY,                          /* set num trans key */
225     TRUNC_KEY,                          /* set truncation fraction key */
226     EPOCH_TRUNC_KEY,                    /* set epoch truncation fraction key */
227     INCR_TRUNC_TIME_KEY,                /* set incr trunc time slice key */
228     VM_KEY,                             /* key for vm check */
229     CHK_RANGE_KEY,                      /* set chk_range fraction key */
230     NO_YIELD_KEY,                       /* set no_yield truncation mode */
231     VM_PROT_KEY,                        /* request vm buffer protection */
232     VM_MAP_PRIV				/* set RVM_MAP_PRIVATE option */
233     }
234 key_id_t;
235 
236 #define STR_NAME_LEN 31                 /* maximum length of string name */
237 
238 typedef struct                          /* string name vector entry */
239     {
240     char            str_name[STR_NAME_LEN+1];  /* character string for name */
241     key_id_t        key;
242     }
243 str_name_entry_t;
244 
245 /* test parameter defaults */
246 
247 #define             FLUSH_DEFAULT       20
248 #define             ABORT_DEFAULT       10
249 #define             RESTORE_DEFAULT     20
250 #define             TRANS_DEFAULT       10
251 #define             RANGES_DEFAULT      100
252 #define             CYCLES_DEFAULT      -1
253 #define             OP_CNT_DEFAULT      1000
254 #define             THREADS_DEFAULT     25
255 #define             BLOCK_SIZE_DEFAULT  10000
256 #define             MOD_SIZE_DEFAULT    10000
257 #define             MOBY_MOD_SIZE_DEFAULT 1000000
258 #define             PRE_ALLOC_DEFAULT   1000
259 #define             SEED_DEFAULT        1
260 #define             CHK_ALLOC_DEFAULT   0
261 #define             CHK_RANGE_DEFAULT   0
262 /* list maintainance functions */
263 
264 /* list header initializer */
init_list_head(whichlist)265 static void init_list_head(whichlist)
266     list_entry_t    *whichlist;         /* pointer to list header */
267     {
268     whichlist->nextentry = whichlist;   /* pointers are to self now */
269     whichlist->preventry = whichlist;
270     whichlist->list.length = 0;         /* list is empty */
271     whichlist->is_header = rvm_true;    /* mark header */
272     }
273 
274 /* list entry initializer */
init_list_ent(entry)275 static void init_list_ent(entry)
276     list_entry_t    *entry;
277     {
278     entry->nextentry = NULL;
279     entry->preventry = NULL;
280     entry->list.name = NULL;
281     entry->is_header = rvm_false;
282     }
283 /* list entry mover */
move_list_ent(fromptr,toptr,victim)284 static list_entry_t *move_list_ent(fromptr, toptr, victim)
285     register list_entry_t *fromptr;     /* from list header */
286     register list_entry_t *toptr;       /* to list header */
287     register list_entry_t *victim;      /* pointer to entry to be moved */
288     {
289 
290     if (fromptr != NULL)
291         {
292         CODA_ASSERT(fromptr->is_header);
293         if ((victim == NULL) && (fromptr->list.length == 0))
294             return NULL;
295         else
296             {
297             if (victim == NULL)         /* choose 1st if no victim */
298                 victim = fromptr->nextentry;
299             CODA_ASSERT(!victim->is_header);
300             CODA_ASSERT(victim->list.name == fromptr);
301 
302             /* remque((void *)victim); */ /* unlink from first list */
303             if (victim->nextentry)
304                 victim->nextentry->preventry = victim->preventry;
305             if (victim->preventry)
306                 victim->preventry->nextentry = victim->nextentry;
307             victim->preventry = victim->nextentry = NULL;
308 
309             fromptr->list.length --;
310             }
311         }
312     else
313         {
314         CODA_ASSERT(victim != NULL);
315         CODA_ASSERT(!victim->is_header);
316         CODA_ASSERT(toptr != NULL);
317         }
318 
319     if (toptr != NULL)
320         {
321         CODA_ASSERT(toptr->is_header);
322         victim->list.name = toptr;
323         /* insque((void *)victim,(void *)toptr->preventry); */ /* insert at tail of second list */
324         victim->preventry = toptr->preventry;
325         victim->nextentry = toptr;
326         victim->preventry->nextentry = toptr->preventry = victim;
327         toptr->list.length ++;
328         }
329     else victim->list.name = NULL;
330 
331     return victim;
332     }
333 /* Byte-aligned checksum and move functions */
334 
335 #define LENGTH_MASK          ((rvm_length_t)(~(sizeof(rvm_length_t)-1)))
336 #define ROUND_TO_LENGTH(len) (((rvm_length_t)((rvm_length_t)(len) \
337                                               +sizeof(rvm_length_t)-1)) \
338                               & LENGTH_MASK)
339 #define CHOP_TO_LENGTH(len)  ((rvm_length_t)((rvm_length_t)(len) \
340                                              & LENGTH_MASK))
341 #define ALIGNED_LEN(addr,len) (ROUND_TO_LENGTH((rvm_length_t)(addr) \
342                                                +(rvm_length_t)(len)) \
343                                - CHOP_TO_LENGTH(addr))
344 #define BYTE_SKEW(len)       ((rvm_length_t)(len) & ~LENGTH_MASK)
345 
346 /* zero-pad unused bytes of word */
zero_pad(word,addr,leading)347 static rvm_length_t zero_pad(word,addr,leading)
348     rvm_length_t    word;               /* value to be zero-padded */
349     char            *addr;              /* address of 1st/last byte */
350     rvm_bool_t      leading;            /* true if leading bytes are zeroed */
351     {
352     char            *word_array = (char *)&word; /* byte access of word value */
353     int             skew = BYTE_SKEW(addr);
354     int             i;
355 
356     if (leading)                        /* zero pad leading bytes */
357         {
358         for (i=sizeof(rvm_length_t)-1; i>0; i--)
359             if (i <= skew) word_array[i-1] = 0;
360         }
361     else                                /* zero pad trailing bytes */
362         {
363         for (i=0; i<(sizeof(rvm_length_t)-1); i++)
364           if (i >= skew) word_array[i+1] = 0;
365         }
366 
367     return word;
368     }
369 /* checksum function: forms checksum of arbitrarily aligned range
370    by copying preceeding, trailing bytes to make length 0 mod length size */
check_sum(nvaddr,len)371 static rvm_length_t check_sum(nvaddr,len)
372     char            *nvaddr;            /* address of 1st byte */
373     rvm_length_t    len;                /* byte count */
374     {
375     rvm_length_t    *base;              /* 0 mod sizeof(rvm_length_t) addr */
376     rvm_length_t    length;             /* number of words to sum */
377     rvm_length_t    chk_sum;            /* check sum temp */
378     rvm_length_t    i;
379 
380     if (len == 0) return 0;
381 
382     /* get zero-byte aligned base address & length of region */
383     base = (rvm_length_t *)CHOP_TO_LENGTH(nvaddr);
384     length = (ALIGNED_LEN(nvaddr,len)/sizeof(rvm_length_t)) - 1;
385 
386     /* process boundary words */
387     chk_sum = zero_pad(*base,nvaddr,rvm_true);
388     if (length >= 2)
389         chk_sum += zero_pad(base[length--],&nvaddr[len-1],rvm_false);
390     if (length <= 1) return chk_sum;
391 
392     /* form check sum of remaining full words */
393     for (i=1; i < length; i++)
394         chk_sum += base[i];
395 
396     return chk_sum;
397     }
398 /* test block check sum */
test_chk_sum(block)399 static rvm_bool_t test_chk_sum(block)
400     block_t         *block;
401     {
402     rvm_length_t    chksum;
403 
404     chksum = check_sum(block->ptr,block->size);
405     if (chksum != block->chksum)
406         {
407 	fprintf(stderr, "chktst %p, %ld\n", block->ptr, chksum);
408         printf("\n?  Block checksum doesn't match\n");
409         CODA_ASSERT(rvm_false);
410         }
411 
412     return rvm_true;
413     }
414 /* pick random block from alloc list */
pick_random()415 static block_t *pick_random()
416     {
417     block_t         *block;             /* allocated block descriptor */
418     int             i;
419 
420     /* exit if list empty */
421     if (alloc_list.list.length == 0)
422         return NULL;
423 
424 #if 0
425     /* check checksums of all blocks on the list */
426     block = (block_t *)alloc_list.nextentry;
427     for (i = alloc_list.list.length; i > 0;i--) {
428         block = (block_t *)block->links.nextentry;
429 	test_chk_sum(block);
430     }
431 #endif
432 
433     /* pick a random block */
434     block = (block_t *)alloc_list.nextentry;
435     for (i = random() % alloc_list.list.length; i > 0;i--)
436         block = (block_t *)block->links.nextentry;
437 
438     return block;
439     }
440 /* allocator */
do_malloc(id)441 static void do_malloc(id)
442     int             id;                 /* thread id */
443     {
444     rvm_tid_t       tid;                /* transaction identifier */
445     rvm_return_t    ret;                /* rvm error return */
446     int             err;                /* rds error return */
447     block_t         *block;             /* allocated block descriptor */
448 
449     /* pick a size and allocate a block in recoverable heap */
450     block = (block_t *)malloc(sizeof(block_t));
451     init_list_ent(&block->links);
452     block->size = random() % max_block_size;
453     if (block->size == 0) block->size = 1;
454     block->ptr = rds_malloc(block->size, 0, &err);
455     if (err != SUCCESS)
456         {
457         if (err > SUCCESS)
458             printf("\n%d: rds_malloc = %s\n", id,
459                    /* rvm_return((rvm_return_t *)err)); XXX BOGUS JET */
460                    rvm_return((rvm_return_t)err));
461         else
462             {
463             if (err == ENO_ROOM) return;
464             printf("\n%d: rds_malloc = %d\n", id, err);
465             }
466         CODA_ASSERT(rvm_false);
467 	}
468 
469     /* transactionally clear the allocated space */
470     rvm_init_tid(&tid);
471     if ((ret=rvm_begin_transaction(&tid,no_restore))
472         != RVM_SUCCESS)
473         {
474         printf("\n%d: ERROR: malloc begin_trans, code: %s\n",
475                id,rvm_return(ret));
476         CODA_ASSERT(rvm_false);
477         }
478     if ((ret=rvm_set_range(&tid,block->ptr,block->size))
479         != RVM_SUCCESS)
480         {
481         printf("\n%d: ERROR: malloc set_range, code: %s\n",
482                id,rvm_return(ret));
483         CODA_ASSERT(rvm_false);
484         }
485     memset(block->ptr, 0, block->size); /* blow away obsolete guards */
486     block->chksum = 0;
487     /* commit the block */
488     if ((ret=rvm_end_transaction(&tid,no_flush)) != RVM_SUCCESS)
489         {
490         printf("\n%d: ERROR: alloc end_trans, code: %s\n",
491                id,rvm_return(ret));
492         CODA_ASSERT(rvm_false);
493             }
494 
495     /* put the block on the allocated list */
496     CRITICAL(alloc_list_lock,           /* begin alloc list crit sec */
497         {
498         (void)move_list_ent(NULL,&alloc_list,(list_entry_t *)block);
499         });                             /* end alloc list crit sec */
500 
501     }
502 /* deallocator function */
do_free(id)503 static void do_free(id)
504     int             id;                 /* thread id */
505     {
506     int             err;                /* rds error return */
507     block_t         *block;             /* allocated block descriptor */
508 
509     CRITICAL(alloc_list_lock,           /* begin alloc list crit sec */
510         {
511         /* select a random entry */
512         if ((block=pick_random()) == NULL)
513             {
514             /* exit if list empty */
515             mutex_unlock(&alloc_list_lock);
516             return;
517             }
518 
519         /* unlink the block */
520         (void)move_list_ent(&alloc_list,NULL,(list_entry_t *)block);
521         });                             /* end alloc list crit sec */
522 
523     /* check sum */
524     test_chk_sum(block);
525 
526     /* free the selected block */
527     rds_free(block->ptr, 0, &err);
528     if (err != SUCCESS)
529         {
530         if (err > SUCCESS)
531             printf("\n%d: rds_free = %s\n", id,
532                    /* rvm_return((rvm_return_t *)err)); */
533                    rvm_return((rvm_return_t)err));
534         else
535             printf("\n%d: rds_free = %d\n", id, err);
536         CODA_ASSERT(rvm_false);
537         }
538 
539     /* deallocate list entry */
540     free(block);
541     }
542 /* rvm_chk_range test */
test_chk_range(tid,addr,len,id)543 static void test_chk_range(tid,addr,len,id)
544     rvm_tid_t       *tid;
545     char            *addr;
546     rvm_length_t    len;
547     int             id;                 /* thread id */
548     {
549 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
550     rvm_return_t    ret;             /* rvm return code */
551     /* test if range is declared in tid */
552     if ((ret = rvm_chk_range(tid,addr,len))
553         != RVM_SUCCESS)
554         {
555         printf("\n%d: ERROR: modify chk_range, code: %s\n",
556                id,rvm_return(ret));
557         CODA_ASSERT(rvm_false);
558         }
559 
560     /* modify range and re-test: should fail */
561     if ((ret = rvm_chk_range(tid,addr,len+1))
562         != RVM_ENO_RANGE)
563         {
564         printf("\n%d: ERROR: modify chk_range, code: %s\n",
565                id,rvm_return(ret));
566         CODA_ASSERT(rvm_false);
567         }
568 
569     if ((ret = rvm_chk_range(tid,addr+1,len))
570         != RVM_ENO_RANGE)
571         {
572         printf("\n%d: ERROR: modify chk_range, code: %s\n",
573                id,rvm_return(ret));
574         CODA_ASSERT(rvm_false);
575         }
576 #endif /* VERSION_TEST */
577     }
578 /* block modifier transaction */
do_trans(block,range_list,do_flush,id)579 static void do_trans(block,range_list,do_flush,id)
580     block_t         *block;             /* block descriptor */
581     block_t         *range_list;        /* list of modification ranges */
582     rvm_bool_t      do_flush;
583     int             id;                 /* thread id */
584     {
585     int             start,finish,temp,i,j;
586     int             n_ranges;
587     block_t         *range;
588     char            *save_area = NULL;
589     char            new_val;
590     rvm_bool_t      do_abort = rvm_false;
591     rvm_tid_t       tid;
592     rvm_mode_t      start_mode = no_restore;
593     rvm_mode_t      commit_mode = no_flush;
594     rvm_return_t    ret;                /* rvm error return */
595 
596     /* choose number of ranges and whether to abort */
597     n_ranges = random() % max_ranges;
598     if ((random() % 100) < abort_frac)
599         {
600         do_abort = rvm_true;
601         save_area = malloc(block->size);
602         CODA_ASSERT(save_area != NULL);
603         memcpy(save_area, block->ptr, block->size);
604         start_mode = restore;
605         }
606     else
607         if ((random() % 100) < restore_frac)
608             start_mode = restore;       /* force test of existing data buffers */
609 
610     /* prepare a transaction */
611     rvm_init_tid(&tid);
612     if ((ret=rvm_begin_transaction(&tid,start_mode))
613         != RVM_SUCCESS)
614         {
615         printf("\n%d: ERROR: modify begin_trans, code: %s\n",
616                id,rvm_return(ret));
617         CODA_ASSERT(rvm_false);
618         }
619     /* pick random ranges and modifications */
620     for (j=0; j<n_ranges; j++)
621         {
622         /* select a random range within the recoverable block */
623         range = (block_t *)malloc(sizeof(block_t));
624         CODA_ASSERT(range != NULL);
625         init_list_ent(&range->links);
626         start = random() % block->size;
627         temp = finish = random() % block->size;
628         if (start > finish)
629             {
630             finish = start;
631             start = temp;
632             }
633         range->ptr = &block->ptr[start];
634         range->size = finish-start+1;
635         if (range->size > max_mod_size)
636             range->size = random() % max_mod_size;
637         move_list_ent(NULL,range_list,range);
638 
639         /* tell RVM */
640         if ((ret=rvm_set_range(&tid,range->ptr,range->size))
641             != RVM_SUCCESS)
642             {
643             printf("\n%d: ERROR: modify set_range, code: %s\n",
644                    id,rvm_return(ret));
645             CODA_ASSERT(rvm_false);
646             }
647         /* see if range should be checked */
648         if ((random() % 100) < chk_range_frac)
649             test_chk_range(&tid,range->ptr,range->size,id);
650 
651         /* set the selected range to random values */
652         new_val = random() % 256;
653         for (i=0; i<range->size; i++)
654             block->ptr[start+i] = new_val;
655         }
656 
657     /* commit or abort the changes */
658     if (do_abort)
659         {
660         if ((ret=rvm_abort_transaction(&tid)) != RVM_SUCCESS)
661             {
662             printf("\n%d: ERROR: modify abort_trans, code: %s\n",
663                id,rvm_return(ret));
664             CODA_ASSERT(rvm_false);
665             }
666 
667         /* check restoration */
668         for (i=0; i<block->size; i++)
669             if (save_area[i] != block->ptr[i])
670                 {
671                 printf("\n%d: modified region improperly restored by abort %p[%d]\n", id, block->ptr, i);
672                 CODA_ASSERT(rvm_false);
673                 }
674         free(save_area);
675         }
676     else
677         {
678         if (do_flush) commit_mode = flush;
679         if ((ret=rvm_end_transaction(&tid,commit_mode)) != RVM_SUCCESS)
680             {
681             printf("\n%d: ERROR: modify end_trans, code: %s\n",
682                id,rvm_return(ret));
683             CODA_ASSERT(rvm_false);
684             }
685         }
686     }
687 /* block modifier */
do_modify(id)688 static void do_modify(id)
689     int             id;                 /* thread id */
690     {
691     int             n_trans;            /* number of transactions per block */
692     block_t         *block;             /* block descriptor */
693     block_t         range_list;         /* list of modification ranges */
694     block_t         *range;
695     rvm_bool_t      do_flush;
696 
697     /* select a random entry */
698     CRITICAL(alloc_list_lock,           /* begin alloc list crit sec */
699         {
700         if ((block=pick_random()) != NULL)
701 	    /* unlink the block */
702 	    (void)move_list_ent(&alloc_list,NULL,(list_entry_t *)block);
703         });                             /* end alloc list crit sec */
704     if (block == NULL) return;          /* exit if list empty */
705     test_chk_sum(block);                /* test for damage  */
706 
707     /* pick random number of transactions; modify block */
708     n_trans = random() % max_trans;
709     init_list_head(&range_list);
710 
711     /* execute the transactions */
712     while (n_trans-- >= 0)
713         {
714         do_flush = (rvm_bool_t)((random() % 100) < flush_frac);
715         do_trans(block,&range_list,do_flush,id);
716 
717         /* insert marker between transactions */
718         range = (block_t *)malloc(sizeof(block_t));
719         CODA_ASSERT(range != NULL);
720         init_list_ent(&range->links);
721         range->size = n_trans+1;
722         range->ptr = NULL;
723         move_list_ent(NULL,&range_list,range);
724         cthread_yield();
725         }
726 
727     /* resum block and kill range list */
728     block->chksum = check_sum(block->ptr,block->size);
729     while (range_list.links.nextentry->is_header != rvm_true)
730         {
731         range = (block_t *)move_list_ent(&range_list,NULL,NULL);
732         free(range);
733         }
734     /* put the block back on the allocated list */
735     CRITICAL(alloc_list_lock,           /* begin alloc list crit sec */
736         {
737         (void)move_list_ent(NULL,&alloc_list,(list_entry_t *)block);
738         });                             /* end alloc list crit sec */
739     }
740 /* region checker for chk_vm */
chk_region(seg_file,region)741 static rvm_bool_t chk_region(seg_file,region)
742     FILE            *seg_file;
743     int             region;             /* index of region */
744     {
745     int             j;
746     int             c;
747     char            *vm;
748     rvm_length_t    reg_pos;            /* region position */
749     int             io_ret;
750 
751     /* set up read of region data */
752     reg_pos = RVM_OFFSET_TO_LENGTH(RegionDefs[region].offset);
753     if ((io_ret=fseek(seg_file,reg_pos,0)) != 0)
754         {
755         printf("\n? Can't seek to %lu in segment file, ret = %d\n",
756                reg_pos, io_ret);
757         CODA_ASSERT(rvm_false);
758         }
759 
760     /* scan and check loop */
761     vm = RegionDefs[region].vmaddr;
762     for (j=0; j < RegionDefs[region].length; j++)
763         {
764         /* scan file */
765         c = getc(seg_file);
766         if (c == EOF)
767             {
768             printf("\n? EOF encountered while reading segment; "
769                    "offset = %lu\n", reg_pos);
770             CODA_ASSERT(rvm_false);
771             }
772 #if 0
773 	/* CL */
774 	printf("j: %6d; vm:0x%x; region%d:0x%x; reg_pos:%d\n",
775 	       j, (vm[j] & 255), region, (c & 255), reg_pos);
776 #endif
777         /* check the data against vm */
778         if ((char)c != vm[j])
779             {
780             printf("\n? Error: mapped data doesn't match:\n");
781             printf("         vm[%d] = 0x%x\n",j,(vm[j] & 255));
782             printf("         region%d[%d] = 0x%x\n",region,j,
783                    (c & 255));
784             printf("         region offset = %lu\n",reg_pos);
785             CODA_ASSERT(rvm_false);
786             return rvm_false;
787             }
788         reg_pos++;
789         }
790 
791     return rvm_true;
792     }
793 /* vm <==> disk comparator */
chk_vm()794 static rvm_bool_t chk_vm()
795     {
796     rvm_return_t    ret;
797     FILE            *seg_file;
798     int             i;
799     int             io_ret;
800     rvm_statistics_t *stats;
801 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
802     rvm_query_t     *query;
803 #endif /* VERSION_TEST */
804     rvm_return_t    retval;
805     rvm_length_t    n_recs;
806     rvm_length_t    tot_recs;
807 
808     if ((stats=rvm_malloc_statistics()) == NULL)
809         {
810         printf("\n?  rvm_malloc_statistics failed\n");
811         CODA_ASSERT(rvm_false);
812         }
813 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
814     if ((query=rvm_malloc_query()) == NULL)
815         {
816         printf("\n?  rvm_malloc_query failed\n");
817         CODA_ASSERT(rvm_false);
818         }
819     if ((retval=RVM_QUERY(query,NULL)) != RVM_SUCCESS)
820         {
821         printf("\n?  rvm_query failed, code: %s\n",
822                rvm_return(ret));
823         CODA_ASSERT(rvm_false);
824         }
825 #endif /* VERSION_TEST */
826     printf("\nChecking segment consistency...\n");
827 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
828     printf("  log head = %d\n",RVM_OFFSET_TO_LENGTH(query->log_head));
829 #endif /* VERSION_TEST */
830 
831     /* check vm heap if required */
832 #ifdef RVM_USELWP
833 #ifdef HAS_PLUMBER
834     if (chk_alloc != 0)
835         CheckAllocs("Checking heap before truncation");
836 #endif
837 #endif /* RVM_USELWP */
838 
839     /* truncate to sync segement with vm */
840     if ((ret=rvm_truncate()) != RVM_SUCCESS)
841         {
842         printf("\n?  rvm_truncate failed, code: %s\n",
843                rvm_return(ret));
844         CODA_ASSERT(rvm_false);
845         }
846 
847     /* re-check vm heap if required */
848 #ifdef RVM_USELWP
849 #ifdef HAS_PLUMBER
850     if (chk_alloc != 0)
851         CheckAllocs("Checking heap after truncation");
852 #endif
853 #endif /* RVM_USELWP */
854 
855     /* get current state */
856     if ((retval=RVM_STATISTICS(stats)) != RVM_SUCCESS)
857         {
858         printf("\n?  rvm_statistics failed, code: %s\n",
859                rvm_return(retval));
860         CODA_ASSERT(rvm_false);
861         }
862 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
863     if ((retval=RVM_QUERY(query,NULL)) != RVM_SUCCESS)
864         {
865         printf("\n?  rvm_query failed, code: %s\n",
866                rvm_return(retval));
867         CODA_ASSERT(rvm_false);
868         }
869 #endif /* VERSION_TEST */
870 
871     /* record log data */
872     n_recs = stats->n_flush_commit + stats->n_no_flush_commit
873         + stats->n_split + stats->n_special + stats->n_wrap;
874     tot_recs =  n_recs+stats->tot_flush_commit+stats->tot_no_flush_commit
875         + stats->tot_split + stats->tot_special + stats->tot_wrap;
876 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
877     printf("  log tail = %d, records written = %d\n",
878            RVM_OFFSET_TO_LENGTH(query->log_tail),tot_recs);
879     printf("  number tree nodes = %d, tree depth = %d\n",
880            query->n_nodes,query->max_depth);
881 #else
882     printf("  records written = %lu\n",tot_recs);
883 #endif /* VERSION_TEST */
884 
885     /* open segment file read-only */
886     if ((seg_file = fopen(DataFileName,"rb")) == NULL)
887         {
888         printf("\n? Error opening segment file\n");
889         printf("    errno = %d\n",errno);
890         CODA_ASSERT(rvm_false);
891         }
892     /* check all mapped regions against segment file */
893     for (i=0; i<NRegionDefs; i++)
894         {
895         if (!chk_region(seg_file,i))
896             CODA_ASSERT(rvm_false);
897         }
898 
899     /* all's well -- close file & release the other threads */
900     io_ret = fclose(seg_file);
901     if (io_ret)
902         {
903         printf("\n? Error closing segment file\n");
904         printf("    ret = %d, errno = %d\n",ret,errno);
905         CODA_ASSERT(rvm_false);
906         }
907     printf("  memory and segment agree!\n");
908 
909     /* reset time */
910     if (gettimeofday(&init_time,NULL) < 0)
911         {
912         perror("?  Error getting time of day");
913         CODA_ASSERT(rvm_false);
914         }
915 
916     rvm_free_statistics(stats);
917 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
918     rvm_free_query(query);
919 #endif /* VERSION_TEST */
920     return rvm_true;
921     }
922 
chk_time()923 static rvm_bool_t chk_time()
924     {
925     struct timeval  time;
926 
927     /* get current time */
928     if (gettimeofday(&time,NULL) < 0)
929         {
930         perror("?  Error getting time of day");
931         return rvm_false;
932         }
933 
934     /* print time */
935     printf("  time: %s", ctime(&time.tv_sec));
936     printf("  number of test operations: %d\n", max_op_cnt);
937     printf("  elapsed time: %ld sec.\n", time.tv_sec-init_time.tv_sec);
938 
939     init_time = time;                   /* update loop start time */
940     return rvm_true;
941     }
942 
943 /* moby range test */
chk_moby()944 static rvm_bool_t chk_moby()
945     {
946     rvm_length_t    length;             /* range length */
947     char            *start;             /* starting offset for range */
948     rvm_length_t    temp;
949     int             i;
950     char            *vm_save;           /* data save area for test range */
951     rvm_tid_t       tid;                /* transaction identifier */
952     rvm_return_t    ret;                /* rvm error return */
953 
954     /* choose a large size for moby range */
955         length = random() % max_moby_size;
956 
957     /* pick a starting point for mods */
958     temp = RegionDefs[0].length - length;
959     start = RVM_ADD_LENGTH_TO_ADDR(RegionDefs[0].vmaddr,
960                                    (random() % temp));
961 
962     /* announce test */
963     printf("\nLarge range modification\n  addr:   %p\n  length: %lu\n",
964            start,length);
965 
966     /* get a buffer and save vm */
967     if ((vm_save = malloc(length)) == NULL)
968         {
969         printf("? Error: can't allocate buffer for moby test\n");
970         CODA_ASSERT(rvm_false);
971         }
972     memcpy(vm_save, start, length);
973 
974     /* set up transaction for moby modification */
975     rvm_init_tid(&tid);
976     if ((ret=rvm_begin_transaction(&tid,no_restore))
977         != RVM_SUCCESS)
978         {
979         printf("? ERROR: chk_moby begin_trans 1, code: %s\n",
980                rvm_return(ret));
981         CODA_ASSERT(rvm_false);
982         }
983     if ((ret=rvm_set_range(&tid,start,length)) != RVM_SUCCESS)
984         {
985         printf("? ERROR: chk_moby set_range 1, code: %s\n",
986                rvm_return(ret));
987         CODA_ASSERT(rvm_false);
988         }
989     /* store random trash in test range & commit */
990     for (i=0; i<length; i++)
991         start[i] = (char)(random() % 256);
992     if ((ret=rvm_end_transaction(&tid,flush)) != RVM_SUCCESS)
993         {
994         printf("? ERROR: chk_moby end_trans 1, code: %s\n",
995                rvm_return(ret));
996         CODA_ASSERT(rvm_false);
997         }
998 
999     /* check the results and restore the test range contents */
1000     if (chk_vm() == rvm_false) return rvm_false;
1001     printf("\n  Restoring original data\n");
1002     if ((ret=rvm_begin_transaction(&tid,no_restore))
1003         != RVM_SUCCESS)
1004         {
1005         printf("? ERROR: chk_moby begin_trans 2, code: %s\n",
1006                rvm_return(ret));
1007         CODA_ASSERT(rvm_false);
1008         }
1009     if ((ret=rvm_set_range(&tid,start,length)) != RVM_SUCCESS)
1010         {
1011         printf("? ERROR: chk_moby set_range 2, code: %s\n",
1012                rvm_return(ret));
1013         CODA_ASSERT(rvm_false);
1014         }
1015     memcpy(start, vm_save, length);
1016     if ((ret=rvm_end_transaction(&tid,flush)) != RVM_SUCCESS)
1017         {
1018         printf("? ERROR: chk_moby end_trans 2, code: %s\n",
1019                rvm_return(ret));
1020         CODA_ASSERT(rvm_false);
1021         }
1022 
1023     free(vm_save);
1024     return rvm_true;
1025     }
1026 /* test monitor */
monitor()1027 static void monitor()
1028     {
1029 
1030     mutex_lock(&chk_lock);              /* begin chk_lock crit sec */
1031     if (chk_block)
1032         {
1033         /* block while check is done */
1034         blk_cnt++;
1035         condition_signal(&chk_code);
1036         while (chk_block)
1037             condition_wait(&blk_code,&chk_lock);
1038         }
1039 
1040     /* count operations and become chk thread if at threshold */
1041     if ((op_cnt-- ) == 0)
1042         {
1043         /* block other worker threads and truncate */
1044         chk_block = rvm_true;
1045         if (nthreads > 1)
1046             while (blk_cnt != (nthreads-1))
1047                 condition_wait(&chk_code,&chk_lock);
1048 
1049         /* do monitoring tests */
1050         printf("\nEnd test cycle %5d\n",cycle);
1051         if (time_tests)                 /* timestamp the loop */
1052             if (!chk_time()) goto err_exit;
1053         if (moby_test)                  /* test large range */
1054             if (!chk_moby()) goto err_exit;
1055         if (vm_test)                    /* compare vm with segment */
1056             if (!chk_vm()) goto err_exit;
1057 
1058         chk_block = rvm_false;
1059         blk_cnt = 0;
1060         op_cnt = max_op_cnt;
1061         if (((cycle++) >= max_cycles) && (max_cycles != -1))
1062             Terminate = rvm_true;
1063         condition_broadcast(&blk_code);
1064         }
1065     goto exit;
1066 
1067   err_exit:
1068     Terminate = rvm_true;
1069   exit:
1070     mutex_unlock(&chk_lock);            /* end chk_lock crit sec */
1071     return;
1072     }
1073 /* testing thread function */
worker(void * idp)1074 static void worker(void *idp)
1075 {
1076     int id = *(int *)idp;
1077 
1078     CRITICAL(init_lock,
1079 	printf("Worker thread %d running...\n\n",id);
1080 	condition_signal(&init_cv); /* wake up main thread */
1081     );
1082 
1083     while (!Terminate)
1084         {
1085         monitor();                      /* do monitoring functions */
1086 
1087         last[id] = 1;
1088         do_malloc(id);                  /* allocate a recoverable heap block */
1089         cthread_yield();
1090 
1091         last[id] = 2;
1092         do_free(id);                    /* free a recoverable heap block */
1093         cthread_yield();
1094 
1095         last[id] = 3;
1096         do_modify(id);                  /* modify a recoverable heap block */
1097 
1098         cthread_yield();
1099         }
1100 
1101     /* signal termination */
1102     if (--nthreads == 0)
1103         condition_signal(&thread_exit_code);
1104     cthread_exit(0);
1105     return;
1106     }
1107 /* string name lookup: accepts minimum substring for match */
lookup_str_name(str,str_vec,ambig_str)1108 static int  lookup_str_name(str,str_vec,ambig_str)
1109     char            *str;               /* name to lookup */
1110     str_name_entry_t *str_vec;          /* defining vector */
1111     char            *ambig_str;         /* ambiguous name type */
1112     {
1113     int             i = 0;              /* loop counter */
1114     int             str_index = (int)UNKNOWN; /* string index in vector */
1115 
1116     while (str_vec[i].str_name[0] != '\0')
1117         {
1118         /* test if name string starts with str */
1119         if (strstr(str_vec[i].str_name,str) ==
1120             str_vec[i].str_name)
1121             {
1122             /* yes, candidate found -- test further */
1123             if (strcmp(str_vec[i].str_name,str) == 0)
1124                 return i;               /* exact match, select this name */
1125             if (str_index == (int)UNKNOWN)
1126                 str_index = i;          /* substring match, remember name */
1127             else
1128                 {                       /* error: ambigous name */
1129                 fprintf(stderr,"? %s: ambiguous %s: %s or %s?\n",
1130                         str,
1131                         ambig_str,
1132                         str_vec[i].str_name,
1133                         str_vec[str_index].str_name);
1134                 return (int)UNKNOWN;
1135                 }
1136             }
1137         i++;
1138         }
1139 
1140     /* see if name not found */
1141     if (str_index == (int)UNKNOWN)
1142         fprintf(stderr,"? %s: %s not found\n",str,ambig_str);
1143 
1144     return str_index;
1145     }
1146 /* scanner utilities */
1147 
1148 /* cmd line cursor incrementor */
1149 #define incr_cur(_i) cmd_cur = &cmd_cur[_i]
1150 
1151 /* tests for end of line characters */
1152 #define end_line(c) (((c) == '\0') || ((c) == '\n'))
1153 #define scan_stop(c) (end_line(c) || ((c) == '#'))
1154 
skip_white(ptr)1155 static void skip_white(ptr)
1156     char            **ptr;
1157     {
1158     while (isspace(**ptr))
1159         (*ptr)++;
1160     }
1161 
1162 /* string scanner */
scan_str(str,len)1163 static int  scan_str(str,len)
1164     char            *str;               /* ptr to string buffer */
1165     int             len;                /* maximum length */
1166     {
1167     int             indx = 0;
1168 
1169     skip_white(&cmd_cur);
1170     while (!scan_stop(*cmd_cur) && (!isspace(*cmd_cur))
1171            && (indx < len))
1172         str[indx++] = *(cmd_cur++);
1173 
1174     str[indx] = '\0';
1175 
1176     return indx;                        /* return length */
1177     }
1178 /* integer scanner & range checker */
scan_int(low_range,high_range,default_val,name_str,err_str)1179 static int scan_int(low_range,high_range,default_val,name_str,err_str)
1180     int                 low_range;
1181     int                 high_range;
1182     int                 default_val;
1183     char                *name_str;
1184     char                *err_str;
1185     {
1186     int                 val;
1187 
1188     /* be sure there's something there */
1189     skip_white(&cmd_cur);
1190     if (scan_stop(*cmd_cur))
1191         {
1192         printf("?  No parameter given for %s\n",name_str);
1193         return 0;
1194         }
1195 
1196     /* scan as interger */
1197     val = strtol(cmd_cur,&cmd_cur,0);
1198 
1199     /* check range */
1200 #if 0
1201 /* I guess this code fragment is wrong, under this, when (low_range != 0)
1202  * val will be return no matter whatever value it is.  More reasonable
1203  * behaviour should be returning val only when
1204  * (either low_range or high_range is non-zero) AND
1205  * (val fall within range) -- clement
1206  */
1207     if ((low_range != 0) || (high_range != 0)
1208         && ((val >= low_range) && (val <= high_range)))
1209         return val;
1210 #endif
1211     if ( ((low_range != 0) || (high_range != 0))
1212         && ((val >= low_range) && (val <= high_range)) )
1213         return val ;
1214 
1215     /* out of range - print message, return default */
1216     printf("?  Warning: %d is out of range %d: %d for %s\n",val,
1217            low_range,high_range,name_str);
1218     printf("     %d assigned as default\n",default_val);
1219 
1220     return default_val;
1221     }
1222 /* read prompted line from terminal */
read_prompt_line(prompt,null_ok)1223 static char *read_prompt_line(prompt,null_ok)
1224     char            *prompt;            /* prompt string */
1225     rvm_bool_t      null_ok;            /* true if null input ok */
1226     {
1227 
1228     /* read from input stream if nothing left in command line */
1229     skip_white(&cmd_cur);
1230     if (scan_stop(*cmd_cur) && (! null_ok))
1231         while (rvm_true)
1232             {
1233             /* prompt if required */
1234             cmd_line[0] = '\0';
1235             if (prompt != NULL)
1236                 printf("%s ",prompt);
1237 
1238             /* get line and check termination conditions */
1239             cmd_cur = fgets(cmd_line,CMD_MAX,para_file);
1240             if (cmd_cur == NULL)
1241                 {
1242                 if (feof(para_file))
1243                     {
1244                     printf("\n?  Error: EOF reported from parameter file !!\n");
1245                     exit(1);
1246                     }
1247                 return NULL;            /* error */
1248                 }
1249             if ((null_ok) || (cmd_line[0] != '\0'))
1250                 return cmd_cur=cmd_line;
1251             }
1252     return NULL;
1253 
1254     }
1255 
1256 
1257 /* display test parameters */
1258 
show_test_parms()1259 static void show_test_parms()
1260     {
1261     int             priority;
1262 
1263     printf("\nCurrent Test Parameters:\n\n");
1264 
1265     printf("  Log file:  %s\n",LogFileName);
1266     printf("  Data file: %s\n",DataFileName);
1267     printf("  Data file length:                         %lu\n",
1268            RVM_OFFSET_TO_LENGTH(DataLen));
1269     printf("  Number of operations/cycle:               %d\n",max_op_cnt);
1270     printf("  Maximum number of transactions/operation: %d\n",max_trans);
1271     printf("  Maximum number of ranges/transaction:     %d\n",max_ranges);
1272     printf("  Maximum modification range size:          %d\n",max_mod_size);
1273     printf("  Maximum big modification range size:      %d\n",max_moby_size);
1274     printf("  Maximum allocation block size:            %d\n",
1275            max_block_size);
1276     printf("  Number of preallocated blocks:            %d\n",
1277            num_pre_alloc);
1278     if (pre_alloc_trunc)
1279         printf("  Truncate after preallocation:              true\n");
1280     else
1281         printf("  Truncate after preallocation:             false\n");
1282 
1283 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1284     printf("  %% ranges to check:                        %d\n",chk_range_frac);
1285 #endif /* VERSION_TEST */
1286     printf("  %% transactions to abort:                  %d\n",abort_frac);
1287     printf("  %% transactions to commit with flush:      %d\n",flush_frac);
1288     printf("  %% transactions started with restore:      %d\n",restore_frac);
1289 
1290     printf("\n");
1291     if (max_cycles == -1)
1292         printf("  Number of test cycles:                    unlimited\n");
1293     else
1294         printf("  Number of test cycles:                    %d\n",
1295                max_cycles);
1296     printf("  Number of worker threads:                 %d\n",nthreads);
1297 #ifdef PRIO_PROCESS
1298     priority = getpriority(PRIO_PROCESS,0);
1299 #else
1300     priority = -1;
1301 #endif
1302     printf("  Execution priority:                       %d\n",priority);
1303     printf("  Random seed:                              %d\n",seed);
1304     printf("  Allocator check level:                    %d\n",chk_alloc);
1305     if (PlumberFileName[0] != '\0')
1306         printf("  Plumber file: %s\n",PlumberFileName);
1307 
1308     /* print test options */
1309     printf("  Test options: ");
1310     if (moby_test)
1311         printf("big_range ");
1312     if (time_tests)
1313         printf("time_tests ");
1314     if (vm_test)
1315         printf("chk_vm ");
1316     printf("\n");
1317 
1318     /* print optimizations */
1319     printf("\n  RVM optimizations: ");
1320     if (optimizations == 0)
1321         printf("none");
1322     if ((optimizations & RVM_COALESCE_RANGES) != 0)
1323         printf("coalesce_ranges ");
1324     if ((optimizations & RVM_COALESCE_TRANS) != 0)
1325         printf("coalesce_trans ");
1326 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1327     if ((optimizations & RVM_INCR_TRUNCATION) != 0)
1328         printf("incr_truncation ");
1329 #endif /* VERSION_TEST */
1330     printf("\n");
1331     printf("  RVM truncation threshold:                 %d%%\n",
1332            trunc_frac);
1333 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1334     printf("  RVM epoch truncation threshold:           %d%%\n",
1335            epoch_trunc_frac);
1336     printf("  RVM incremental truncation time slice:    %d msec.\n",
1337            incr_trunc_time);
1338 #endif /* VERSION_TEST */
1339     printf("  RVM recovery buffer length:               %lu\n",rec_buf_len);
1340     printf("  RVM flush buffer length:                  %lu\n",flush_buf_len);
1341     printf("  RVM max. read length:                     %lu\n",max_read_len);
1342     if (chk_sum_sw)
1343         printf("  RVM check sum flag:                        true\n");
1344     else
1345         printf("  RVM check sum flag:                       false\n");
1346     if (no_yield_sw)
1347         printf("  RVM no yield flag:                         true\n");
1348     else
1349         printf("  RVM no yield flag:                        false\n");
1350     if (vm_protect_sw)
1351         printf("  RVM vm protect flag:                       true\n");
1352     else
1353         printf("  RVM vm protect flag:                      false\n");
1354     if (do_private_map)
1355         printf("  RVM private map:                           true\n");
1356     else
1357         printf("  RVM private map:                          false\n");
1358     if (show_brk)
1359         printf("  Show break point:                          true\n");
1360     else
1361         printf("  Show break point:                         false\n");
1362     printf("\n");
1363     }
1364 /* get data file name and size */
set_data_file()1365 static void set_data_file()
1366     {
1367     int                 len;
1368     struct stat 	sbuf;
1369 
1370     while (rvm_true)
1371         {
1372         read_prompt_line("  Enter data file name: ",rvm_false);
1373         skip_white(&cmd_cur);
1374         len = scan_str(DataFileName,MAXPATHLEN);
1375         if (len != 0) break;
1376         printf("\n?  Data file name must be specified\n");
1377         }
1378 
1379     /* get length of segment if partition specified */
1380     if (stat(DataFileName, &sbuf) < 0)
1381     {
1382 	char *errstr = NULL;
1383 #ifdef HAVE_STRERROR
1384         errstr = strerror(errno);
1385 #endif
1386 	printf("%s\n", errstr != NULL ? errstr : "Cannot stat data file");
1387         DataFileName[0] = '\000';
1388 	return;
1389         }
1390     switch (sbuf.st_mode & S_IFMT)
1391         {
1392 #ifdef S_IFSOCK
1393       case S_IFSOCK:
1394 #endif
1395       case S_IFDIR:
1396 #ifdef S_IFLNK
1397       case S_IFLNK:
1398 #endif
1399 /* LINUX use the same block device for raw control */
1400 #ifndef __linux__
1401       case S_IFBLK:
1402 #endif
1403 	printf("Illegal file type!\n");
1404         DataFileName[0] = '\0';
1405 	return;
1406 
1407 /* LINUX use the same block device for raw control */
1408 #ifdef __linux__
1409       case S_IFBLK:
1410 #endif
1411       case S_IFCHR:
1412         while (rvm_true)
1413             {
1414             read_prompt_line("Enter the length of device: ",rvm_false);
1415             len = scan_int(512,2000000000,0,"DataLen",
1416                            "?  Bad data device length\n");
1417             if (len != 0) break;
1418             }
1419 	DataLen = RVM_MK_OFFSET(0,len);
1420         return;
1421 
1422       default:
1423         DataLen = RVM_MK_OFFSET(0,sbuf.st_size); /* Normal files. */
1424         return;
1425         }
1426     }
1427 /* get log file name */
set_log_file()1428 static void set_log_file()
1429     {
1430     int             len;
1431 
1432     while (rvm_true)
1433         {
1434         read_prompt_line("  Enter log file name: ",rvm_false);
1435         skip_white(&cmd_cur);
1436         len = scan_str(LogFileName,MAXPATHLEN);
1437         if (len != 0) break;
1438         printf("\n?  Log file name must be specified\n");
1439         }
1440     }
1441 
1442 /* set execution priority */
set_priority()1443 static void set_priority()
1444     {
1445     int             priority;
1446     int             err;
1447 
1448     priority = scan_int(0,20,0,"scheduling priority",
1449                         "?  Bad scheduling priority");
1450 
1451 #ifdef PRIO_PROCESS
1452     err = setpriority(PRIO_PROCESS,0,priority);
1453 #else
1454     err = 0;
1455 #endif
1456     if (err != 0)
1457         printf("?  Error setting process priority, err = %d\n",err);
1458 
1459     }
1460 /* option flags */
1461 #define MAX_FLAGS   15                  /* maximum number of flag codes */
1462 
1463 static str_name_entry_t flag_vec[MAX_FLAGS] = /* flag codes vector */
1464                     {
1465                     {"all_optimizations",ALL_KEY}, /* enable all optimizations */
1466                     {"none",NONE_KEY}, /* no optimizations */
1467                     {"coalesce_ranges",RANGES_KEY}, /* enable range coalesce */
1468                     {"rvm_coalesce_ranges",RANGES_KEY}, /* enable range coalesce */
1469                     {"ranges",RANGES_KEY}, /* enable range coalesce */
1470                     {"coalesce_trans",TRANS_KEY}, /* enable transaction coalesce */
1471                     {"rvm_coalesce_trans",TRANS_KEY}, /* enable transaction coalesce */
1472                     {"trans",TRANS_KEY}, /* enable transaction coalesce */
1473 
1474 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1475                     {"rvm_incr_truncation",INCR_KEY}, /* enable incr truncation */
1476                     {"incr",INCR_KEY}, /* enable incr truncation */
1477                     {"incr_truncation",INCR_KEY}, /* enable incr truncation */
1478 
1479 #endif /* VERSION_TEST */
1480                     {"",(key_id_t)NULL} /* end mark, do not delete */
1481                     };
1482 /* set rvm_options flags */
set_flags()1483 static void set_flags()
1484     {
1485     char            string[80];         /* flag code name string */
1486     int             i;
1487 
1488     optimizations = 0;
1489 
1490     /* scan loop */
1491     while (rvm_true)
1492         {
1493         /* see if done */
1494         skip_white(&cmd_cur);
1495         if (scan_stop(*cmd_cur))
1496             return;
1497 
1498         /* scan and lookup flag code */
1499         (void)scan_str(string,80);
1500         i = lookup_str_name(string,flag_vec,"option flag");
1501         if (i == (int)UNKNOWN)          /* error */
1502             {
1503             *cmd_cur = '\0';
1504             return;
1505             }
1506 
1507         /* process code */
1508         switch (flag_vec[i].key)
1509             {
1510           case ALL_KEY:
1511             optimizations |= RVM_ALL_OPTIMIZATIONS;
1512             continue;
1513           case NONE_KEY:
1514             optimizations = 0;
1515             continue;
1516           case RANGES_KEY:
1517             optimizations |= RVM_COALESCE_RANGES;
1518             continue;
1519           case TRANS_KEY:
1520             optimizations |= RVM_COALESCE_TRANS;
1521             continue;
1522 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1523           case INCR_KEY:
1524             optimizations |= RVM_INCR_TRUNCATION;
1525 	    continue;
1526 #endif /* VERSION_TEST */
1527 	  default:
1528 	    continue;
1529             }
1530         }
1531     }
1532 /* plumber support */
setup_plumber_file()1533 static void setup_plumber_file()
1534     {
1535     int             len;
1536 
1537     while (rvm_true)
1538         {
1539         read_prompt_line("  Enter plumber file name: ",rvm_false);
1540         skip_white(&cmd_cur);
1541         len = scan_str(PlumberFileName,MAXPATHLEN);
1542         if (len != 0) break;
1543         printf("\n?  Plumber file name must be specified\n");
1544         }
1545 
1546     /* try to open file if really can use plumber */
1547 #ifdef RVM_USELWP
1548 #ifdef HAS_PLUMBER
1549     PlumberFile = fopen(PlumberFileName,"w");
1550     if (PlumberFile == NULL)
1551         printf("?  File %s could not be opened, errno = %d\n",
1552                PlumberFileName,errno);
1553     else
1554         fclose(PlumberFile);
1555 #endif
1556 #else /* RVM_USELWP */
1557     printf("W  Plumber not available with Cthreads\n");
1558 #endif /* RVM_USELWP */
1559     }
1560 
1561 #ifdef DEBUG_GDB
1562 /* call function (to be used from GDB) */
call_plumber()1563 void call_plumber()
1564     {
1565 #ifdef RVM_USELWP
1566 #ifdef HAS_PLUMBER
1567     PlumberFile = fopen(PlumberFileName,"w");
1568     if (PlumberFile == NULL)
1569         printf("?  File %s could not be opened, errno = %d\n",
1570                PlumberFileName,errno);
1571     plumber(PlumberFile);
1572     fclose(PlumberFile);
1573 #endif
1574 #else /* RVM_USELWP */
1575     printf("?  Plumber not available with Cthreads\n");
1576 #endif /* RVM_USELWP */
1577     }
1578 #endif /* DEBUG_GDB */
1579 /* print break point and limit */
show_break()1580 static void show_break()
1581     {
1582     rvm_length_t    cur_brk;
1583 #ifdef RLIMIT_DATA
1584     struct rlimit   rlp;
1585 #endif
1586 
1587     /* get current break point */
1588     errno = 0;
1589     if ((cur_brk=(rvm_length_t)sbrk(0)) == -1)
1590         {
1591         printf("\n? Error getting current break point\n");
1592         printf("    errno = %d\n",errno);
1593         CODA_ASSERT(rvm_false);
1594         }
1595 
1596     /* get system maximum */
1597     errno = 0;
1598 #ifdef RLIMIT_DATA
1599     if (getrlimit(RLIMIT_DATA,&rlp) < 0)
1600         {
1601         printf("\n? Error getting data segment limit\n");
1602         printf("    errno = %d\n",errno);
1603         CODA_ASSERT(rvm_false);
1604         }
1605 
1606     /* print the limits */
1607     printf("\nCurrent break point:         0x%lx\n",
1608            RVM_ROUND_LENGTH_UP_TO_PAGE_SIZE(cur_brk+5*RVM_PAGE_SIZE));
1609     printf("Maximum data segment length: 0x%lx\n\n",rlp.rlim_max);
1610 #endif
1611     exit(0);
1612     }
1613 /* command dispatch */
1614 #define MAX_CMDS   50                   /* maximum number of commands */
1615 
1616 static str_name_entry_t cmd_vec[MAX_CMDS] = /* command codes vector */
1617                     {
1618                     {"abort_frac",ABORT_KEY}, /* set abort fraction */
1619                     {"all_tests",ALL_KEY},    /* do all test options */
1620                     {"block_size",BLOCK_SIZE_KEY}, /* set maximum allocation block size */
1621                     {"mod_size",MOD_SIZE_KEY},  /* set maximum modification size */
1622                     {"log_file",LOG_KEY}, /* set log file */
1623                     {"data_file",DATA_KEY}, /* set data file */
1624                     {"restore_frac",RESTORE_KEY}, /* set restore fraction */
1625                     {"flush_buf",FLUSH_BUF_KEY}, /* set flush buffer length */
1626                     {"flush_frac",FLUSH_KEY}, /* set flush fraction */
1627                     {"check_alloc",CHK_ALLOC_KEY}, /* enable allocation checking */
1628                     {"chk_sum",CHK_SUM_KEY}, /* set rvm_chk_sum */
1629                     {"chk_vm",VM_KEY},      /* test vm againt segment */
1630                     {"time_tests",TIME_KEY},  /* time the test cycles */
1631                     {"ranges",RANGES_KEY}, /* max number of ranges/trans */
1632                     {"trans",TRANS_KEY}, /* max number of trans/modify */
1633                     {"cycles",CYCLES_KEY}, /* number of cycles */
1634                     {"operations",OPS_KEY}, /* number of operations/cycle */
1635                     {"ops",OPS_KEY},    /* number of operations/cycle */
1636                     {"optimizations",OPT_KEY}, /* set optimizations */
1637                     {"opts",OPT_KEY},   /* set optimizations */
1638                     {"show_parmeters",PARMS_KEY},   /* show test parameters */
1639                     {"parmeters",PARMS_KEY},   /* show test parameters */
1640                     {"parms",PARMS_KEY},   /* show test parameters */
1641                     {"priority",PRIORITY_KEY}, /* set tests priority */
1642                     {"read_length",MAX_READ_KEY}, /* set maximum read length */
1643                     {"rec_buf",REC_BUF_KEY}, /* set recovery buffer length */
1644                     {"run",RUN_KEY},    /* start tests */
1645                     {"seed",SEED_KEY},  /* random num gen seed */
1646                     {"threads",THREADS_KEY}, /* number of threads */
1647                     {"truncate_frac",TRUNC_KEY}, /* set truncation threshold */
1648                     {"big_range",MOBY_KEY}, /* test moby ranges */
1649                     {"max_big_range",MOBY_MAX_KEY}, /* set maximum moby range size */
1650                     {"quit",QUIT_KEY}, /* quit test program */
1651                     {"plumber",PLUMBER_KEY}, /* plumber file setup */
1652                     {"pre_allocate",PRE_ALLOC_KEY}, /* number blocks preallocated */
1653                     {"pre_allocate_trunc",PRE_ALLOC_TRUNC_KEY}, /* truncate
1654                                                                    after preallocation */
1655                     {"show_break_point",BRK_KEY}, /* print break point */
1656                     {"break_point",BRK_KEY}, /* print break point */
1657     /* version dependent commands */
1658 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1659                     {"epoch_truncate_frac",EPOCH_TRUNC_KEY}, /* set epoch trunc threshold */
1660                     {"incr_trunc_time",INCR_TRUNC_TIME_KEY}, /* set incr trunc
1661                                                                 time slice */
1662                     {"chk_range_frac",CHK_RANGE_KEY}, /* set % of ranges to check */
1663                     {"no_yield",NO_YIELD_KEY}, /* set no yield mode */
1664                     {"vm_protect",VM_PROT_KEY}, /* setvm buffer protect mode */
1665 #endif /* VERSION_TEST */
1666                     {"map_private",VM_MAP_PRIV}, /* option RVM_MAP_PRIVATE */
1667                     {"",(key_id_t)NULL} /* end mark, do not delete */
1668                     };
1669 
main(argc,argv)1670 int main(argc, argv)
1671     int argc;
1672     char **argv;
1673     {
1674     rvm_options_t       *options;       /* options descriptor ptr */
1675     rvm_return_t	ret;
1676     char		*addr, string[80];
1677     int 		err, i;
1678 
1679     if (argc == 2) {		/* input parameters from file */
1680       para_file = fopen(argv[1], "r");
1681       if (! para_file) {
1682 	fprintf(stderr, "open parameter files failed. Basher not started\n");
1683 	exit(-1);
1684       }
1685     } else {
1686       para_file = stdin;
1687     }
1688 
1689     /* initializations */
1690     cthread_init();
1691     cmd_line[0] = '\0';
1692     cmd_cur=cmd_line;
1693     chk_block = rvm_false;
1694     chk_sum_sw = rvm_false;
1695     no_yield_sw = rvm_false;
1696     vm_protect_sw = rvm_false;
1697     show_brk = rvm_false;
1698     do_private_map = rvm_false;
1699     blk_cnt = 0;
1700     mutex_init(&init_lock);
1701     condition_init(&init_cv);
1702     mutex_init(&alloc_list_lock);
1703     init_list_head(&alloc_list);
1704     mutex_init(&chk_lock);
1705     condition_init(&blk_code);
1706     condition_init(&chk_code);
1707     mutex_init(&thread_lock);
1708     condition_init(&thread_exit_code);
1709     LogFileName[0] = '\0';
1710     DataFileName[0] = '\0';
1711     PlumberFileName[0] = '\0';
1712     cycle = 1;
1713 
1714     /* set defaults */
1715     max_cycles = CYCLES_DEFAULT;
1716     max_op_cnt = OP_CNT_DEFAULT;
1717     max_trans = TRANS_DEFAULT;
1718     max_ranges = RANGES_DEFAULT;
1719     max_block_size = BLOCK_SIZE_DEFAULT;
1720     max_mod_size = MOD_SIZE_DEFAULT;
1721     max_moby_size = MOBY_MOD_SIZE_DEFAULT;
1722     num_pre_alloc = PRE_ALLOC_DEFAULT;
1723     nthreads = THREADS_DEFAULT;
1724     flush_frac = FLUSH_DEFAULT;
1725     restore_frac = RESTORE_DEFAULT;
1726     abort_frac = ABORT_DEFAULT;
1727     optimizations = RVM_ALL_OPTIMIZATIONS;
1728     trunc_frac = TRUNCATE;
1729     seed = SEED_DEFAULT;
1730     chk_alloc = CHK_ALLOC_DEFAULT;
1731     max_read_len = MAX_READ_LEN;
1732     flush_buf_len = FLUSH_BUF_LEN;
1733     rec_buf_len = RECOVERY_BUF_LEN;
1734     pre_alloc_trunc = rvm_false;
1735 /* version specific defaults */
1736 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1737     epoch_trunc_frac = EPOCH_TRUNCATE;
1738     incr_trunc_time = INCR_TRUNC_TIME;
1739     chk_range_frac = CHK_RANGE_DEFAULT;
1740 #endif /* VERSION_TEST */
1741 
1742     /* scan test commands */
1743     while (rvm_true)
1744         {
1745         read_prompt_line("*",rvm_false);
1746 
1747         /* ignore comment lines */
1748         skip_white(&cmd_cur);
1749         if (*cmd_cur == '#')
1750             {
1751             *cmd_cur = '\0';
1752             continue;
1753             }
1754 
1755         /* scan command name */
1756         (void)scan_str(string,80);
1757         i = lookup_str_name(string,cmd_vec,"command");
1758         if (i == (int)UNKNOWN)          /* error */
1759             {
1760             *cmd_cur = '\0';
1761             continue;
1762             }
1763         /* dispatch commands */
1764         switch (cmd_vec[i].key)
1765             {
1766           case LOG_KEY:                 /* get name of log file */
1767             set_log_file();
1768             continue;
1769           case DATA_KEY:                /* get name of data file */
1770             set_data_file();
1771             continue;
1772           case SEED_KEY:                /* set random number seed */
1773             seed = scan_int(0,100000000,SEED_DEFAULT,"seed",
1774                             "?  Bad seed");
1775             srandom(seed);
1776             continue;
1777           case THREADS_KEY:             /* get number of threads to run */
1778             nthreads = scan_int(1,1000,THREADS_DEFAULT,"thread",
1779                                 "?  Bad thread count");
1780             continue;
1781           case OPS_KEY:                 /* set operation count */
1782             max_op_cnt = scan_int(1,10000,OP_CNT_DEFAULT,"operations",
1783                                   "?  Bad operation count");
1784             continue;
1785           case CYCLES_KEY:              /* set number of test cycles */
1786             max_cycles = scan_int(1,1000000000,CYCLES_DEFAULT,"cycles",
1787                                   "?  Bad cycle count");
1788             continue;
1789           case VM_KEY:                  /* test vm against segment */
1790             vm_test = rvm_true;
1791             continue;
1792           case TIME_KEY:                /* time stamp the test cycles */
1793             time_tests = rvm_true;
1794             continue;
1795           case MOBY_KEY:                /* test very large ranges */
1796             moby_test = rvm_true;
1797             continue;
1798           case MOBY_MAX_KEY:
1799             max_moby_size = scan_int(0,10000000,SEED_DEFAULT,"big range size",
1800                                      "?  Bad large modification size");
1801             continue;
1802           case ALL_KEY:                 /* do all test options */
1803             vm_test = rvm_true;
1804             time_tests = rvm_true;
1805             moby_test = rvm_true;
1806             continue;
1807           case ABORT_KEY:               /* set abort fraction */
1808             abort_frac = scan_int(0,100,ABORT_DEFAULT,"abort fraction",
1809                                   "?  Bad abort percentage");
1810             continue;
1811           case RESTORE_KEY:             /* set restore fraction */
1812             restore_frac = scan_int(0,100,RESTORE_DEFAULT,
1813                                     "restore fraction",
1814                                     "?  Bad restore percentage");
1815             continue;
1816           case FLUSH_KEY:               /* set flush fraction */
1817             flush_frac = scan_int(0,100,FLUSH_DEFAULT,"flush fraction",
1818                                   "?  Bad flush percentage");
1819             continue;
1820           case TRUNC_KEY:               /* set truncation fraction */
1821             trunc_frac = scan_int(0,100,TRUNCATE,
1822                                   "truncation fraction",
1823                                   "?  Bad truncation percentage");
1824             continue;
1825           case RANGES_KEY:              /* set max number ranges/trans */
1826             max_ranges = scan_int(0,1000000,RANGES_DEFAULT,
1827                                   "max ranges",
1828                                   "?  Bad maximum number of ranges");
1829             continue;
1830           case TRANS_KEY:              /* set max number trans/modify */
1831             max_trans = scan_int(0,100000,TRANS_DEFAULT,"max trans",
1832                                   "?  Bad maximum number of transactions");
1833             continue;
1834           case PARMS_KEY:               /* print test parameters */
1835             show_test_parms();
1836             continue;
1837           case PRE_ALLOC_KEY:           /* number of blocks to preallocate */
1838             num_pre_alloc = scan_int(1,100000,PRE_ALLOC_DEFAULT,
1839                                      "pre_alloc",
1840                                      "?  Bad block preallocation count");
1841             continue;
1842           case PRE_ALLOC_TRUNC_KEY:     /* truncate after preallocation */
1843             pre_alloc_trunc = rvm_true;
1844             continue;
1845           case RUN_KEY:
1846             printf("\n");
1847             break;
1848           case PRIORITY_KEY:            /* set execution priority */
1849             set_priority();
1850             continue;
1851           case QUIT_KEY:                /* exit program */
1852             exit(0);
1853           case OPT_KEY:                 /* set optimization flags */
1854             set_flags();
1855             continue;
1856           case NO_YIELD_KEY:            /* set no_yield option */
1857             no_yield_sw = rvm_true;
1858             continue;
1859           case REC_BUF_KEY:
1860             rec_buf_len = scan_int(MIN_RECOVERY_BUF_LEN,1000*RVM_PAGE_SIZE,
1861                                    RECOVERY_BUF_LEN,"rec_buf",
1862                                    "?  Bad recovery buffer length");
1863             continue;
1864           case FLUSH_BUF_KEY:
1865             flush_buf_len = scan_int(MIN_FLUSH_BUF_LEN,1000*RVM_PAGE_SIZE,
1866                                      FLUSH_BUF_LEN,"flush_buf",
1867                                      "?  Bad flush buffer length");
1868             continue;
1869           case BLOCK_SIZE_KEY:          /* set max allocation block size */
1870             max_block_size = scan_int(sizeof(rvm_length_t),100000,
1871                                       BLOCK_SIZE_DEFAULT,"block size",
1872                                       "?  Bad maximum allocation size");
1873             continue;
1874           case MOD_SIZE_KEY:            /* set max modification range size */
1875             max_mod_size = scan_int(1,10000000,MOD_SIZE_DEFAULT,
1876                                     "mod size",
1877                                     "?  Bad maximum modification size");
1878             continue;
1879           case MAX_READ_KEY:            /* set maximum read length */
1880             max_read_len = scan_int(RVM_PAGE_SIZE,1000*RVM_PAGE_SIZE,
1881                                     MAX_READ_LEN,"read_length",
1882                                     "?  Bad maximum read length");
1883             continue;
1884           case BRK_KEY:                 /* show break point */
1885             show_brk = rvm_true;
1886             continue;
1887 /* version specific commands */
1888 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1889           case CHK_SUM_KEY:            /* set rvm_chk_sum switch */
1890             chk_sum_sw = rvm_true;
1891             continue;
1892           case CHK_RANGE_KEY:           /* set range check fraction */
1893             chk_range_frac = scan_int(0,100,CHK_RANGE_DEFAULT,
1894                                       "chk_range_frac",
1895                                       "? Bad chk_range fraction");
1896             continue;
1897           case VM_PROT_KEY:             /* set vm protection option */
1898             vm_protect_sw = rvm_true;
1899             continue;
1900           case INCR_TRUNC_TIME_KEY:     /* set incr trunc time slice */
1901             incr_trunc_time = scan_int(0,1000000,INCR_TRUNC_TIME,
1902                                        "incr trunc time slice",
1903                                        "?  Bad time slice size");
1904             continue;
1905           case EPOCH_TRUNC_KEY:         /* set epoch truncation fraction */
1906             epoch_trunc_frac = scan_int(trunc_frac,100,EPOCH_TRUNCATE,
1907                                   "epoch truncation fraction",
1908                                   "?  Bad epoch truncation percentage");
1909             continue;
1910 #endif /* VERSION_TEST */
1911 
1912 /* LWP specific commands */
1913           case CHK_ALLOC_KEY:           /* get allocator check level */
1914             chk_alloc = scan_int(0,5,CHK_ALLOC_DEFAULT,
1915                                  "check_alloc",
1916                                  "?  Bad allocation checker level");
1917 #ifndef RVM_USELWP
1918             printf("W  Allocation checking not available with Cthreads\n");
1919 #endif /* RVM_USELWP */
1920             continue;
1921           case PLUMBER_KEY:             /* open plumber file */
1922             setup_plumber_file();
1923 #ifndef RVM_USELWP
1924             printf("W  Allocation checking not available with Cthreads\n");
1925 #endif /* RVM_USELWP */
1926             continue;
1927 
1928           case VM_MAP_PRIV:             /* Map private ... */
1929 	    do_private_map = rvm_true;
1930             continue;
1931 
1932           default:  CODA_ASSERT(rvm_false);
1933             }
1934         /* check that all necessary parameters have been speced */
1935         if (strlen(LogFileName) == 0)
1936             {
1937             printf("\n?  Log file name must be specified\n");
1938             continue;
1939             }
1940         if ((strlen(DataFileName) == 0) && (show_brk == rvm_false))
1941             {
1942             printf("\n?  Data file name must be specified\n");
1943             continue;
1944             }
1945         break;
1946         }
1947 
1948     /* Check for good data. */
1949     if (RVM_OFFSET_TO_LENGTH(DataLen) < max_moby_size)
1950       {
1951 	fprintf (stderr, "Basher: Maximum big modification range size too big.\n");
1952 	exit(-1);
1953       }
1954 
1955     /* set LWP options */
1956 #ifdef RVM_USELWP
1957 #ifdef HAS_PLUMBER
1958     SetMallocCheckLevel(chk_alloc);
1959 #endif
1960 #elif !defined(RVM_USEPT)
1961     if (nthreads > 1) {
1962 	fprintf(stderr, "Nonthreaded basher, ignoring request for multiple threads\n");
1963 	nthreads = 1;
1964     }
1965 #endif
1966 
1967     /* esatblish RVM options */
1968     options = rvm_malloc_options();
1969     options->log_dev = LogFileName;
1970     options->flags &= ~RVM_ALL_OPTIMIZATIONS;
1971     options->flags |= optimizations;
1972     if (do_private_map)
1973       options->flags |= RVM_MAP_PRIVATE;
1974     options->truncate = trunc_frac;
1975     options->flush_buf_len = flush_buf_len;
1976     options->recovery_buf_len = rec_buf_len;
1977     options->max_read_len = max_read_len;
1978 
1979 #if ((RVM_MAJOR_VERSION >= 2) && (RVM_MINOR_VERSION >= 0))
1980     options->epoch_truncate = epoch_trunc_frac;
1981     options->incr_trunc_time = incr_trunc_time;
1982     if (chk_sum_sw)
1983         options->flags |= RVM_CHK_SUM;
1984     if (no_yield_sw)
1985         options->flags |= RVM_NO_YIELD;
1986     if (chk_range_frac != 0)
1987         options->flags |= RVM_CHK_RANGE;
1988     if (vm_protect_sw)
1989         options->flags |= RVM_VM_PROTECT;
1990 #endif /* VERSION_TEST */
1991     /* initialize RVM */
1992     ret = RVM_INIT(options);
1993     if  (ret != RVM_SUCCESS)
1994         {
1995 	printf("? rvm_initialize failed, code: %s\n",rvm_return(ret));
1996         exit(-1);
1997         }
1998     else
1999 	printf("rvm_initialize succeeded.\n");
2000     /* print break point if requested */
2001     if (show_brk) show_break();
2002 
2003     /* Load the data segment */
2004     rds_testsw = rvm_true;
2005     rds_load_heap(DataFileName, DataLen, &addr, &err);
2006     if (err == SUCCESS)
2007 	printf("rds_start_heap successful\n");
2008     else
2009         {
2010         if (err > SUCCESS)
2011             printf("rds_start_heap = %s\n",
2012                    /* rvm_return((rvm_return_t *)err)); XXX BOGUS JET */
2013                    rvm_return((rvm_return_t)err));
2014         else
2015             printf("rds_start_heap = %d\n", err);
2016         CODA_ASSERT(rvm_false);
2017         }
2018 
2019     /* preload alloc_list */
2020     printf("Preallocating test blocks\n");
2021     for (i=num_pre_alloc; i>=0; i--)
2022         do_malloc(0);
2023     if (pre_alloc_trunc)
2024         {
2025         ret = rvm_truncate();
2026         if  (ret != RVM_SUCCESS)
2027             {
2028             printf("? rvm_truncate failed, code: %s\n",
2029                    rvm_return(ret));
2030             CODA_ASSERT(rvm_false);
2031             }
2032         }
2033 
2034     /* get current time */
2035     if (gettimeofday(&init_time,NULL) < 0)
2036         {
2037         perror("?  Error getting time of day");
2038         CODA_ASSERT(rvm_false);
2039         }
2040     if (time_tests)
2041         printf("\nTests started: %s\n",ctime(&init_time.tv_sec));
2042 
2043     /* start test run with input parameters */
2044     op_cnt = max_op_cnt;
2045     threads = (cthread_t *)malloc(sizeof(cthread_t) * nthreads);
2046     last = (int *)malloc(sizeof(int)*nthreads);
2047 
2048     /* fork the testing threads and run the tests */
2049     if (nthreads == 1)
2050         {
2051 	int arg = 0;
2052         last[0] = 0;
2053         worker(&arg);
2054         }
2055     else
2056         {
2057         for (i = 0; i < nthreads; i++)
2058 	    CRITICAL(init_lock,
2059 		last[i] = 0;
2060 		threads[i] = cthread_fork(worker, &i);
2061 		condition_wait(&init_cv, &init_lock);
2062 	    );
2063 
2064         /* wait for all threads to terminate */
2065         CRITICAL(thread_lock, {
2066             while (nthreads > 0)
2067                 condition_wait(&thread_exit_code,&thread_lock);
2068         });
2069         cthread_yield();                /* let the last one out */
2070         }
2071     printf("\n All threads have exited\n");
2072 
2073     /* cleanup */
2074     if ((ret=rvm_terminate()) != RVM_SUCCESS)
2075         {
2076 	printf("? rvm_terminate failed, code: %s\n",rvm_return(ret));
2077         CODA_ASSERT(rvm_false);
2078         }
2079     return 0;
2080     }
2081 
2082