00001 /* 00002 File locking (lockf) 00003 AUP2, Sec. 7.11.3 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 00023 /*[rec]*/ 00024 struct rec { 00025 int r_data; 00026 off_t r_next; 00027 }; 00028 /*[readrec]*/ 00029 bool readrec(int dbfd, struct rec *r, off_t off) 00030 { 00031 ssize_t nread; 00032 00033 if ((nread = pread(dbfd, r, sizeof(struct rec), off)) == 00034 sizeof(struct rec)) 00035 return true; 00036 if (nread != -1) 00037 errno = EIO; 00038 EC_FAIL 00039 return true; 00040 00041 EC_CLEANUP_BGN 00042 return false; 00043 EC_CLEANUP_END 00044 } 00045 00046 bool writerec(int dbfd, struct rec *r, off_t off) 00047 { 00048 ssize_t nwrote; 00049 00050 if ((nwrote = pwrite(dbfd, r, sizeof(struct rec), off)) == 00051 sizeof(struct rec)) 00052 return true; 00053 if (nwrote != -1) 00054 errno = EIO; 00055 EC_FAIL 00056 return true; 00057 00058 EC_CLEANUP_BGN 00059 return false; 00060 EC_CLEANUP_END 00061 } 00062 00063 bool store(int dbfd, int data) 00064 { 00065 struct rec r, rnew; 00066 off_t end, prev; 00067 00068 ec_neg1( end = lseek(dbfd, 0, SEEK_END) ) 00069 prev = 0; 00070 ec_false( readrec(dbfd, &r, prev) ) 00071 while (r.r_next != 0) { 00072 ec_false( readrec(dbfd, &r, r.r_next) ) 00073 if (r.r_data > data) 00074 break; 00075 prev = r.r_next; 00076 } 00077 /*[store]*/ 00078 ec_neg1( lseek(dbfd, 0, SEEK_SET) ) 00079 ec_neg1( lockf(dbfd, F_LOCK, 0) ) 00080 ec_false( readrec(dbfd, &r, prev) ) 00081 rnew.r_next = r.r_next; 00082 r.r_next = end; 00083 ec_false( writerec(dbfd, &r, prev) ) 00084 rnew.r_data = data; 00085 usleep(1); /* give up CPU */ 00086 ec_false( writerec(dbfd, &rnew, end) ) 00087 ec_neg1( lseek(dbfd, 0, SEEK_SET) ) 00088 ec_neg1( lockf(dbfd, F_ULOCK, 0) ) 00089 /*[]*/ 00090 return true; 00091 00092 EC_CLEANUP_BGN 00093 return false; 00094 EC_CLEANUP_END 00095 } 00096 /*[process1]*/ 00097 #define DBNAME "termdb" 00098 00099 static void process1(void) 00100 { 00101 int dbfd, data; 00102 struct rec r; 00103 00104 ec_neg1( dbfd = open(DBNAME, O_CREAT | O_TRUNC | O_RDWR, PERM_FILE) ) 00105 memset(&r, 0, sizeof(r)); 00106 ec_false( writerec(dbfd, &r, 0) ) 00107 for (data = 100; data >= 0; data--) 00108 ec_false( store(dbfd, data) ) 00109 ec_neg1( close(dbfd) ) 00110 exit(EXIT_SUCCESS); 00111 00112 EC_CLEANUP_BGN 00113 exit(EXIT_FAILURE); 00114 EC_CLEANUP_END 00115 } 00116 static void process2(void) 00117 { 00118 int try, dbfd; 00119 struct rec r1, r2; 00120 00121 for (try = 0; try < 10; try++) 00122 if ((dbfd = open(DBNAME, O_RDWR)) == -1) { 00123 if (errno == ENOENT) { 00124 continue; 00125 } 00126 else 00127 EC_FAIL 00128 } 00129 ec_neg1( dbfd ) 00130 /*[process2]*/ 00131 for (try = 0; try < 100; try++) { 00132 ec_neg1( lseek(dbfd, 0, SEEK_SET) ) 00133 ec_neg1( lockf(dbfd, F_LOCK, 0) ) 00134 ec_false( readrec(dbfd, &r1, 0) ) 00135 while (r1.r_next != 0) { 00136 ec_false( readrec(dbfd, &r2, r1.r_next) ) 00137 if (r1.r_data > r2.r_data) { 00138 printf("Found sorting error (try %d)\n", try); 00139 break; 00140 } 00141 r1 = r2; 00142 } 00143 ec_neg1( lseek(dbfd, 0, SEEK_SET) ) 00144 ec_neg1( lockf(dbfd, F_ULOCK, 0) ) 00145 } 00146 /*[]*/ 00147 ec_neg1( close(dbfd) ) 00148 return; 00149 00150 EC_CLEANUP_BGN 00151 exit(EXIT_FAILURE); 00152 EC_CLEANUP_END 00153 } 00154 /*[main]*/ 00155 int main(void) 00156 { 00157 pid_t pid; 00158 00159 ec_neg1( pid = fork() ) 00160 if (pid == 0) 00161 process1(); 00162 else { 00163 process2(); 00164 ec_neg1( waitpid(pid, NULL, 0) ) 00165 } 00166 exit(EXIT_SUCCESS); 00167 00168 EC_CLEANUP_BGN 00169 exit(EXIT_FAILURE); 00170 EC_CLEANUP_END 00171 } 00172 /*[]*/