00001 // sysdep.cc 00002 // Implementation of system-dependent interface. Nachos uses the 00003 // routines defined here, rather than directly calling the UNIX library, 00004 // to simplify porting between versions of UNIX, and even to 00005 // other systems, such as MSDOS. 00006 // 00007 // On UNIX, almost all of these routines are simple wrappers 00008 // for the underlying UNIX system calls. 00009 // 00010 // NOTE: all of these routines refer to operations on the underlying 00011 // host machine (e.g., the DECstation, SPARC, etc.), supporting the 00012 // Nachos simulation code. Nachos implements similar operations, 00013 // (such as opening a file), but those are implemented in terms 00014 // of hardware devices, which are simulated by calls to the underlying 00015 // routines in the host workstation OS. 00016 // 00017 // This file includes lots of calls to C routines. C++ requires 00018 // us to wrap all C definitions with a "extern "C" block". 00019 // This prevents the internal forms of the names from being 00020 // changed by the C++ compiler. 00021 // 00022 // Copyright (c) 1992-1996 The Regents of the University of California. 00023 // All rights reserved. See copyright.h for copyright notice and limitation 00024 // of liability and disclaimer of warranty provisions. 00025 00026 #include "copyright.h" 00027 #include "debug.h" 00028 #include "sysdep.h" 00029 #include "stdlib.h" 00030 #include "unistd.h" 00031 #include "sys/time.h" 00032 #include "sys/file.h" 00033 #include <sys/socket.h> 00034 #include <sys/un.h> 00035 00036 #ifdef SOLARIS 00037 // KMS 00038 // for open() 00039 #include <fcntl.h> 00040 #endif 00041 00042 #ifdef LINUX // at this point, linux doesn't support mprotect 00043 #define NO_MPROT 00044 #endif 00045 #ifdef DOS // neither does DOS 00046 #define NO_MPROT 00047 #endif 00048 00049 extern "C" { 00050 #include <signal.h> 00051 #include <sys/types.h> 00052 00053 #ifndef NO_MPROT 00054 #include <sys/mman.h> 00055 #endif 00056 00057 // UNIX routines called by procedures in this file 00058 00059 #if defined CYGWIN 00060 size_t getpagesize(void); 00061 #else 00062 int getpagesize(void); 00063 #endif 00064 unsigned sleep(unsigned); 00065 //#ifdef SOLARIS 00066 //int usleep(useconds_t); 00067 //#else 00068 //void usleep(unsigned int); // rcgood - to avoid spinning processes. 00069 //#endif 00070 00071 00072 #ifndef NO_MPROT 00073 00074 #ifdef OSF 00075 #define OSF_OR_AIX 00076 #endif 00077 #ifdef AIX 00078 #define OSF_OR_AIX 00079 #endif 00080 00081 #ifdef OSF_OR_AIX 00082 int mprotect(const void *, long unsigned int, int); 00083 #else 00084 int mprotect(char *, unsigned int, int); 00085 #endif 00086 #endif 00087 00088 #if defined(BSD) || defined(SOLARIS) || defined(LINUX) 00089 //KMS 00090 // added Solaris and LINUX 00091 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 00092 struct timeval *timeout); 00093 #else 00094 int select(int numBits, void *readFds, void *writeFds, void *exceptFds, 00095 struct timeval *timeout); 00096 #endif 00097 00098 int socket(int, int, int); 00099 00100 #if defined(SUNOS) || defined(ULTRIX) 00101 long tell(int); 00102 int bind (int, const void*, int); 00103 int recvfrom (int, void*, int, int, void*, int *); 00104 int sendto (int, const void*, int, int, void*, int); 00105 #endif 00106 00107 } 00108 00109 //---------------------------------------------------------------------- 00110 // CallOnUserAbort 00111 // Arrange that "func" will be called when the user aborts (e.g., by 00112 // hitting ctl-C. 00113 //---------------------------------------------------------------------- 00114 00115 void 00116 CallOnUserAbort(void (*func)(int)) 00117 { 00118 (void)signal(SIGINT, func); 00119 } 00120 00121 //---------------------------------------------------------------------- 00122 // RegisterSignal 00123 // Arrange that "func" will be called when NachOS get a signal from 00124 // the host operating system. 00125 //---------------------------------------------------------------------- 00126 00127 void 00128 RegisterSignalHandler(void (*func)(int), int sig) 00129 { 00130 (void)signal(sig, func); 00131 } 00132 00133 //---------------------------------------------------------------------- 00134 // Delay 00135 // Put the UNIX process running Nachos to sleep for x seconds, 00136 // to give the user time to start up another invocation of Nachos 00137 // in a different UNIX shell. 00138 //---------------------------------------------------------------------- 00139 00140 void 00141 Delay(int seconds) 00142 { 00143 (void) sleep((unsigned) seconds); 00144 } 00145 00146 //---------------------------------------------------------------------- 00147 // UDelay 00148 // Put the UNIX process running Nachos to sleep for x microseconds, 00149 // to prevent an idle Nachos process from spinning... 00150 //---------------------------------------------------------------------- 00151 00152 void 00153 UDelay(unsigned int useconds) 00154 { 00155 //#ifdef SOLARIS 00156 // usleep(useconds_t useconds); 00157 //#else 00158 // usleep(useconds); 00159 //#endif /* SOLARIS */ 00160 00161 } 00162 00163 //---------------------------------------------------------------------- 00164 // Abort 00165 // Quit and drop core. 00166 //---------------------------------------------------------------------- 00167 00168 void 00169 Abort() 00170 { 00171 abort(); 00172 } 00173 00174 //---------------------------------------------------------------------- 00175 // Exit 00176 // Quit without dropping core. 00177 //---------------------------------------------------------------------- 00178 00179 void 00180 Exit(int exitCode) 00181 { 00182 exit(exitCode); 00183 } 00184 00185 //---------------------------------------------------------------------- 00186 // RandomInit 00187 // Initialize the pseudo-random number generator. We use the 00188 // now obsolete "srand" and "rand" because they are more portable! 00189 //---------------------------------------------------------------------- 00190 00191 void 00192 RandomInit(unsigned seed) 00193 { 00194 srand(seed); 00195 } 00196 00197 //---------------------------------------------------------------------- 00198 // RandomNumber 00199 // Return a pseudo-random number. 00200 //---------------------------------------------------------------------- 00201 00202 unsigned int 00203 RandomNumber() 00204 { 00205 return rand(); 00206 } 00207 00208 //---------------------------------------------------------------------- 00209 // AllocBoundedArray 00210 // Return an array, with the two pages just before 00211 // and after the array unmapped, to catch illegal references off 00212 // the end of the array. Particularly useful for catching overflow 00213 // beyond fixed-size thread execution stacks. 00214 // 00215 // Note: Just return the useful part! 00216 // 00217 // "size" -- amount of useful space needed (in bytes) 00218 //---------------------------------------------------------------------- 00219 00220 char * 00221 AllocBoundedArray(int size) 00222 { 00223 #ifdef NO_MPROT 00224 return new char[size]; 00225 #else 00226 int pgSize = getpagesize(); 00227 char *ptr = new char[pgSize * 2 + size]; 00228 00229 mprotect(ptr, pgSize, 0); 00230 mprotect(ptr + pgSize + size, pgSize, 0); 00231 return ptr + pgSize; 00232 #endif 00233 } 00234 00235 //---------------------------------------------------------------------- 00236 // DeallocBoundedArray 00237 // Deallocate an array of integers, unprotecting its two boundary pages. 00238 // 00239 // "ptr" -- the array to be deallocated 00240 // "size" -- amount of useful space in the array (in bytes) 00241 //---------------------------------------------------------------------- 00242 00243 #ifdef NO_MPROT 00244 void 00245 DeallocBoundedArray(char *ptr, int /* size */) 00246 { 00247 delete [] ptr; 00248 } 00249 #else 00250 void 00251 DeallocBoundedArray(char *ptr, int size) 00252 { 00253 int pgSize = getpagesize(); 00254 00255 mprotect(ptr - pgSize, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC); 00256 mprotect(ptr + size, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC); 00257 delete [] (ptr - pgSize); 00258 } 00259 #endif 00260 00261 //---------------------------------------------------------------------- 00262 // PollFile 00263 // Check open file or open socket to see if there are any 00264 // characters that can be read immediately. If so, read them 00265 // in, and return TRUE. 00266 // 00267 // "fd" -- the file descriptor of the file to be polled 00268 //---------------------------------------------------------------------- 00269 00270 bool 00271 PollFile(int fd) 00272 { 00273 #if defined(SOLARIS) || defined(LINUX) 00274 // KMS 00275 fd_set rfd,wfd,xfd; 00276 #else 00277 int rfd = (1 << fd), wfd = 0, xfd = 0; 00278 #endif 00279 int retVal; 00280 struct timeval pollTime; 00281 00282 #if defined(SOLARIS) || defined(LINUX) 00283 // KMS 00284 FD_ZERO(&rfd); 00285 FD_ZERO(&wfd); 00286 FD_ZERO(&xfd); 00287 FD_SET(fd,&rfd); 00288 #endif 00289 00290 // don't wait if there are no characters on the file 00291 pollTime.tv_sec = 0; 00292 pollTime.tv_usec = 0; 00293 00294 // poll file or socket 00295 #if defined(BSD) 00296 retVal = select(32, (fd_set*)&rfd, (fd_set*)&wfd, (fd_set*)&xfd, &pollTime); 00297 #elif defined(SOLARIS) || defined(LINUX) 00298 // KMS 00299 retVal = select(32, &rfd, &wfd, &xfd, &pollTime); 00300 #else 00301 retVal = select(32, &rfd, &wfd, &xfd, &pollTime); 00302 #endif 00303 00304 ASSERT((retVal == 0) || (retVal == 1)); 00305 if (retVal == 0) 00306 return FALSE; // no char waiting to be read 00307 return TRUE; 00308 } 00309 00310 //---------------------------------------------------------------------- 00311 // OpenForWrite 00312 // Open a file for writing. Create it if it doesn't exist; truncate it 00313 // if it does already exist. Return the file descriptor. 00314 // 00315 // "name" -- file name 00316 //---------------------------------------------------------------------- 00317 00318 int 00319 OpenForWrite(char *name) 00320 { 00321 int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666); 00322 00323 ASSERT(fd >= 0); 00324 return fd; 00325 } 00326 00327 //---------------------------------------------------------------------- 00328 // OpenForReadWrite 00329 // Open a file for reading or writing. 00330 // Return the file descriptor, or error if it doesn't exist. 00331 // 00332 // "name" -- file name 00333 //---------------------------------------------------------------------- 00334 00335 int 00336 OpenForReadWrite(char *name, bool crashOnError) 00337 { 00338 int fd = open(name, O_RDWR, 0); 00339 00340 ASSERT(!crashOnError || fd >= 0); 00341 return fd; 00342 } 00343 00344 //---------------------------------------------------------------------- 00345 // Read 00346 // Read characters from an open file. Abort if read fails. 00347 //---------------------------------------------------------------------- 00348 00349 void 00350 Read(int fd, char *buffer, int nBytes) 00351 { 00352 int retVal = read(fd, buffer, nBytes); 00353 ASSERT(retVal == nBytes); 00354 } 00355 00356 //---------------------------------------------------------------------- 00357 // ReadPartial 00358 // Read characters from an open file, returning as many as are 00359 // available. 00360 //---------------------------------------------------------------------- 00361 00362 int 00363 ReadPartial(int fd, char *buffer, int nBytes) 00364 { 00365 return read(fd, buffer, nBytes); 00366 } 00367 00368 00369 //---------------------------------------------------------------------- 00370 // WriteFile 00371 // Write characters to an open file. Abort if write fails. 00372 //---------------------------------------------------------------------- 00373 00374 void 00375 WriteFile(int fd, char *buffer, int nBytes) 00376 { 00377 int retVal = write(fd, buffer, nBytes); 00378 ASSERT(retVal == nBytes); 00379 } 00380 00381 //---------------------------------------------------------------------- 00382 // Lseek 00383 // Change the location within an open file. Abort on error. 00384 //---------------------------------------------------------------------- 00385 00386 void 00387 Lseek(int fd, int offset, int whence) 00388 { 00389 int retVal = lseek(fd, offset, whence); 00390 ASSERT(retVal >= 0); 00391 } 00392 00393 //---------------------------------------------------------------------- 00394 // Tell 00395 // Report the current location within an open file. 00396 //---------------------------------------------------------------------- 00397 00398 int 00399 Tell(int fd) 00400 { 00401 #if defined(BSD) || defined(SOLARIS) || defined(LINUX) 00402 return lseek(fd,0,SEEK_CUR); // 386BSD doesn't have the tell() system call 00403 // neither do Solaris and Linux -KMS 00404 #else 00405 return tell(fd); 00406 #endif 00407 } 00408 00409 00410 //---------------------------------------------------------------------- 00411 // Close 00412 // Close a file. Abort on error. 00413 //---------------------------------------------------------------------- 00414 00415 int 00416 Close(int fd) 00417 { 00418 int retVal = close(fd); 00419 ASSERT(retVal >= 0); 00420 return retVal; 00421 } 00422 00423 //---------------------------------------------------------------------- 00424 // Unlink 00425 // Delete a file. 00426 //---------------------------------------------------------------------- 00427 00428 bool 00429 Unlink(char *name) 00430 { 00431 return unlink(name); 00432 } 00433 00434 //---------------------------------------------------------------------- 00435 // OpenSocket 00436 // Open an interprocess communication (IPC) connection. For now, 00437 // just open a datagram port where other Nachos (simulating 00438 // workstations on a network) can send messages to this Nachos. 00439 //---------------------------------------------------------------------- 00440 00441 int 00442 OpenSocket() 00443 { 00444 int sockID; 00445 00446 sockID = socket(AF_UNIX, SOCK_DGRAM, 0); 00447 ASSERT(sockID >= 0); 00448 00449 return sockID; 00450 } 00451 00452 //---------------------------------------------------------------------- 00453 // CloseSocket 00454 // Close the IPC connection. 00455 //---------------------------------------------------------------------- 00456 00457 void 00458 CloseSocket(int sockID) 00459 { 00460 (void) close(sockID); 00461 } 00462 00463 //---------------------------------------------------------------------- 00464 // InitSocketName 00465 // Initialize a UNIX socket address -- magical! 00466 //---------------------------------------------------------------------- 00467 00468 static void 00469 InitSocketName(struct sockaddr_un *uname, char *name) 00470 { 00471 uname->sun_family = AF_UNIX; 00472 strcpy(uname->sun_path, name); 00473 } 00474 00475 //---------------------------------------------------------------------- 00476 // AssignNameToSocket 00477 // Give a UNIX file name to the IPC port, so other instances of Nachos 00478 // can locate the port. 00479 //---------------------------------------------------------------------- 00480 00481 void 00482 AssignNameToSocket(char *socketName, int sockID) 00483 { 00484 struct sockaddr_un uName; 00485 int retVal; 00486 00487 (void) unlink(socketName); // in case it's still around from last time 00488 00489 InitSocketName(&uName, socketName); 00490 retVal = bind(sockID, (struct sockaddr *) &uName, sizeof(uName)); 00491 ASSERT(retVal >= 0); 00492 DEBUG(dbgNet, "Created socket " << socketName); 00493 } 00494 00495 //---------------------------------------------------------------------- 00496 // DeAssignNameToSocket 00497 // Delete the UNIX file name we assigned to our IPC port, on cleanup. 00498 //---------------------------------------------------------------------- 00499 void 00500 DeAssignNameToSocket(char *socketName) 00501 { 00502 (void) unlink(socketName); 00503 } 00504 00505 //---------------------------------------------------------------------- 00506 // PollSocket 00507 // Return TRUE if there are any messages waiting to arrive on the 00508 // IPC port. 00509 //---------------------------------------------------------------------- 00510 bool 00511 PollSocket(int sockID) 00512 { 00513 return PollFile(sockID); // on UNIX, socket ID's are just file ID's 00514 } 00515 00516 //---------------------------------------------------------------------- 00517 // ReadFromSocket 00518 // Read a fixed size packet off the IPC port. Abort on error. 00519 //---------------------------------------------------------------------- 00520 void 00521 ReadFromSocket(int sockID, char *buffer, int packetSize) 00522 { 00523 int retVal; 00524 #if defined(__GNUC__) && __GNUC__ < 3 00525 extern int errno; 00526 #endif 00527 struct sockaddr_un uName; 00528 #ifdef LINUX 00529 socklen_t size = sizeof(uName); 00530 #else 00531 int size = sizeof(uName); 00532 #endif 00533 00534 retVal = recvfrom(sockID, buffer, packetSize, 0, 00535 (struct sockaddr *) &uName, &size); 00536 00537 if (retVal != packetSize) { 00538 perror("in recvfrom"); 00539 #if defined (CYGWIN) || (__GNUC__ >= 3) 00540 cerr << "called with " << packetSize << ", got back " << retVal 00541 << ", and " << "\n"; 00542 #else 00543 cerr << "called with " << packetSize << ", got back " << retVal 00544 << ", and " << errno << "\n"; 00545 #endif 00546 } 00547 ASSERT(retVal == packetSize); 00548 } 00549 00550 //---------------------------------------------------------------------- 00551 // modified by KMS to add retry... 00552 // SendToSocket 00553 // Transmit a fixed size packet to another Nachos' IPC port. 00554 // Try 10 times with a one second delay between attempts. 00555 // This is useful, e.g., to give the other socket a chance 00556 // to get set up. 00557 // Terminate if we still fail after 10 tries. 00558 //---------------------------------------------------------------------- 00559 void 00560 SendToSocket(int sockID, char *buffer, int packetSize, char *toName) 00561 { 00562 struct sockaddr_un uName; 00563 int retVal; 00564 int retryCount; 00565 00566 InitSocketName(&uName, toName); 00567 00568 for(retryCount=0;retryCount < 10;retryCount++) { 00569 retVal = sendto(sockID, buffer, packetSize, 0, 00570 (struct sockaddr *) &uName, sizeof(uName)); 00571 if (retVal == packetSize) return; 00572 // if we did not succeed, we should see a negative 00573 // return value indicating complete failure. If we 00574 // don't, something fishy is going on... 00575 ASSERT(retVal < 0); 00576 // wait a second before trying again 00577 Delay(1); 00578 } 00579 // At this point, we have failed many times 00580 // The most common reason for this is that the target machine 00581 // has halted and its socket no longer exists. 00582 // We simply do nothing (drop the packet). 00583 // This may mask other kinds of failures, but it is the 00584 // right thing to do in the common case. 00585 }