os161-1.99
 All Data Structures
dirconc.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Concurrent directory operations test.
00032  *
00033  * Your system should survive this (without leaving a corrupted file
00034  * system behind) once the file system assignment is complete.
00035  */
00036 
00037 #include <sys/types.h>
00038 #include <sys/wait.h>
00039 #include <sys/stat.h>
00040 #include <errno.h>
00041 #include <stdio.h>
00042 #include <unistd.h>
00043 #include <stdlib.h>
00044 #include <stdarg.h>
00045 #include <string.h>
00046 
00047 #define NTRIES    100   /* loop count */
00048 #define NPROCS    5     /* actually totals 4x this +1 processes */
00049 
00050 #define TESTDIR   "dirconc"
00051 #define NNAMES    4
00052 #define NAMESIZE  32
00053 
00054 ////////////////////////////////////////////////////////////
00055 
00056 static const char *const names[NNAMES] = {
00057         "aaaa", 
00058         "bbbb",
00059         "cccc", 
00060         "dddd",
00061 };
00062 
00063 static
00064 void
00065 choose_name(char *buf, size_t len)
00066 {
00067         const char *a, *b, *c;
00068 
00069         a = names[random()%NNAMES];
00070         if (random()%2==0) {
00071                 snprintf(buf, len, "%s", a);
00072                 return;
00073         }
00074         b = names[random()%NNAMES];
00075         if (random()%2==0) {
00076                 snprintf(buf, len, "%s/%s", a, b);
00077                 return;
00078         }
00079         c = names[random()%NNAMES];
00080         snprintf(buf, len, "%s/%s/%s", a, b, c);
00081 }
00082 
00083 ////////////////////////////////////////////////////////////
00084 
00085 /*
00086  * The purpose of this is to be atomic. In our world, straight
00087  * printf tends not to be.
00088  */
00089 static
00090 void
00091 #ifdef __GNUC__
00092         __attribute__((__format__(__printf__, 1, 2)))
00093 #endif
00094 say(const char *fmt, ...)
00095 {
00096         char buf[512];
00097         va_list ap;
00098         va_start(ap, fmt);
00099         vsnprintf(buf, sizeof(buf), fmt, ap);
00100         va_end(ap);
00101         write(STDOUT_FILENO, buf, strlen(buf));
00102 }
00103 
00104 ////////////////////////////////////////////////////////////
00105 
00106 static
00107 void
00108 dorename(const char *name1, const char *name2)
00109 {
00110         if (rename(name1, name2) < 0) {
00111                 switch (errno) {
00112                     case ENOENT:
00113                     case ENOTEMPTY:
00114                     case EINVAL:
00115                         break;
00116                     default:
00117                         say("pid %d: rename %s -> %s: %s\n", 
00118                             getpid(), name1, name2, strerror(errno));
00119                         break;
00120                 }
00121         }
00122 }
00123 
00124 static
00125 void
00126 domkdir(const char *name)
00127 {
00128         if (mkdir(name, 0775)<0) {
00129                 switch (errno) {
00130                     case ENOENT:
00131                     case EEXIST:
00132                         break;
00133                     default:
00134                         say("pid %d: mkdir %s: %s\n",
00135                             getpid(), name, strerror(errno));
00136                         break;
00137                 }
00138         }
00139 }
00140 
00141 static
00142 void
00143 dormdir(const char *name)
00144 {
00145         if (rmdir(name)<0) {
00146                 switch (errno) {
00147                     case ENOENT:
00148                     case ENOTEMPTY:
00149                         break;
00150                     default:
00151                         say("pid %d: rmdir %s: %s\n",
00152                             getpid(), name, strerror(errno));
00153                         break;
00154                 }
00155         }
00156 }
00157 
00158 static
00159 void
00160 cleanup_rmdir(const char *name)
00161 {
00162         if (rmdir(name)<0) {
00163                 switch (errno) {
00164                     case ENOENT:
00165                         break;
00166                     default:
00167                         say("cleanup (pid %d): rmdir %s: %s\n",
00168                             getpid(), name, strerror(errno));
00169                         break;
00170                 }
00171         }
00172 }
00173 
00174 ////////////////////////////////////////////////////////////
00175 
00176 static
00177 void
00178 rename_proc(void)
00179 {
00180         char name1[NAMESIZE], name2[NAMESIZE];
00181         int ct;
00182         
00183         for (ct=0; ct<NTRIES; ct++) {
00184                 choose_name(name1, sizeof(name1));
00185                 choose_name(name2, sizeof(name2));
00186                 say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
00187                 dorename(name1, name2);
00188         }
00189 }
00190 
00191 static
00192 void
00193 mkdir_proc(void)
00194 {
00195         char name[NAMESIZE];
00196         int ct;
00197         
00198         for (ct=0; ct<NTRIES; ct++) {
00199                 choose_name(name, sizeof(name));
00200                 say("pid %2d: mkdir  %s\n", (int)getpid(), name);
00201                 domkdir(name);
00202         }
00203 }
00204 
00205 static
00206 void
00207 rmdir_proc(void)
00208 {
00209         char name[NAMESIZE];
00210         int ct;
00211 
00212         for (ct=0; ct<NTRIES; ct++) {
00213                 choose_name(name, sizeof(name));
00214                 say("pid %2d: rmdir  %s\n", (int)getpid(), name);
00215                 dormdir(name);
00216         }
00217 }
00218 
00219 ////////////////////////////////////////////////////////////
00220 
00221 static
00222 pid_t
00223 dofork(void (*func)(void))
00224 {
00225         pid_t pid;
00226 
00227         pid = fork();
00228         if (pid < 0) {
00229                 say("fork: %s\n", strerror(errno));
00230                 return -1;
00231         }
00232         if (pid == 0) {
00233                 /* child */
00234                 func();
00235                 exit(0);
00236         }
00237         return pid;
00238 }
00239 
00240 static
00241 void
00242 run(void)
00243 {
00244         pid_t pids[NPROCS*4], wp;
00245         int i, status;
00246 
00247         for (i=0; i<NPROCS; i++) {
00248                 pids[i*4] = dofork(mkdir_proc);
00249                 pids[i*4+1] = dofork(mkdir_proc);
00250                 pids[i*4+2] = dofork(rename_proc);
00251                 pids[i*4+3] = dofork(rmdir_proc);
00252         }
00253         
00254         for (i=0; i<NPROCS*4; i++) {
00255                 if (pids[i]>=0) {
00256                         wp = waitpid(pids[i], &status, 0);
00257                         if (wp<0) {
00258                                 say("waitpid %d: %s\n", (int) pids[i], 
00259                                     strerror(errno));
00260                         }
00261                         else if (WIFSIGNALED(status)) {
00262                                 say("pid %d: signal %d\n", (int) pids[i],
00263                                     WTERMSIG(status));
00264                         }
00265                         else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
00266                                 say("pid %d: exit %d\n", (int) pids[i], 
00267                                     WEXITSTATUS(status));
00268                         }
00269                 }
00270         }
00271 }
00272 
00273 ////////////////////////////////////////////////////////////
00274 
00275 static
00276 void
00277 setup(const char *fs)
00278 {
00279         if (chdir(fs)<0) {
00280                 say("chdir: %s: %s\n", fs, strerror(errno));
00281                 exit(1);
00282         }
00283         if (mkdir(TESTDIR, 0775)<0) {
00284                 say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
00285                 exit(1);
00286         }
00287         if (chdir(TESTDIR)<0) {
00288                 say("chdir: %s: %s\n", TESTDIR, strerror(errno));
00289                 exit(1);
00290         }
00291 }
00292 
00293 static
00294 void
00295 recursive_cleanup(const char *sofar, int depth)
00296 {
00297         char buf[NAMESIZE*32];
00298         int i;
00299         
00300         for (i=0; i<NNAMES; i++) {
00301                 snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
00302                 if (rmdir(buf)<0) {
00303                         if (errno==ENOTEMPTY) {
00304                                 recursive_cleanup(buf, depth+1);
00305                                 cleanup_rmdir(buf);
00306                         }
00307                         else if (errno!=ENOENT) {
00308                                 say("cleanup (pid %d): rmdir %s: %s\n", 
00309                                     getpid(), buf, strerror(errno));
00310                         }
00311                 }
00312         }
00313 }
00314 
00315 static
00316 void
00317 cleanup(void)
00318 {
00319         recursive_cleanup(".", 0);
00320         
00321         chdir("..");
00322         cleanup_rmdir(TESTDIR);
00323 }
00324 
00325 ////////////////////////////////////////////////////////////
00326 
00327 int
00328 main(int argc, char *argv[])
00329 {
00330         const char *fs;
00331         long seed = 0;
00332         
00333         say("Concurrent directory ops test\n");
00334         
00335         if (argc==0 || argv==NULL) {
00336                 say("Warning: argc is 0 - assuming you mean to run on lhd1: "
00337                     "with seed 0\n");
00338                 fs = "lhd1:";
00339         }
00340         else if (argc==2) {
00341                 fs = argv[1];
00342         }
00343         else if (argc==3) {
00344                 fs = argv[1];
00345                 seed = atoi(argv[2]);
00346         }
00347         else {
00348                 say("Usage: dirconc filesystem [random-seed]\n");
00349                 exit(1);
00350         }
00351         
00352         srandom(seed);
00353         setup(fs);
00354         say("Starting in %s/%s\n", fs, TESTDIR);
00355         
00356         run();
00357         
00358         say("Cleaning up\n");
00359         cleanup();
00360         
00361         return 0;
00362 }
 All Data Structures