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-1993 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 00028 extern "C" { 00029 #include <stdio.h> 00030 #include <string.h> 00031 #include <signal.h> 00032 #include <sys/types.h> 00033 #include <sys/time.h> 00034 #include <sys/socket.h> 00035 #include <sys/file.h> 00036 #include <sys/un.h> 00037 #include <sys/mman.h> 00038 #ifdef HOST_i386 00039 #include <sys/time.h> 00040 #endif 00041 #ifdef HOST_SPARC 00042 #include <sys/time.h> 00043 #endif 00044 #ifdef HOST_SVR4 00045 #include <fcntl.h> 00046 #endif 00047 00048 // UNIX routines called by procedures in this file 00049 00050 #if defined(HOST_SNAKE) || defined(HOST_SVR4) 00051 // int creat(char *name, unsigned short mode); 00052 // int open(const char *name, int flags, ...); 00053 #else 00054 int creat(const char *name, unsigned short mode); 00055 int open(const char *name, int flags, ...); 00056 // void signal(int sig, VoidFunctionPtr func); -- this may work now! 00057 #ifdef HOST_i386 00058 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 00059 struct timeval *timeout); 00060 #else 00061 int select(int numBits, void *readFds, void *writeFds, void *exceptFds, 00062 struct timeval *timeout); 00063 #endif 00064 #endif 00065 00066 int unlink(char *name); 00067 int read(int filedes, char *buf, int numBytes); 00068 int write(int filedes, char *buf, int numBytes); 00069 int lseek(int filedes, int offset, int whence); 00070 int tell(int filedes); 00071 int close(int filedes); 00072 int unlink(char *name); 00073 00074 // definition varies slightly from platform to platform, so don't 00075 // define unless gcc complains 00076 // extern int recvfrom(int s, void *buf, int len, int flags, void *from, int *fromlen); 00077 // extern int sendto(int s, void *msg, int len, int flags, void *to, int tolen); 00078 00079 void srand(unsigned seed); 00080 int rand(void); 00081 unsigned sleep(unsigned); 00082 void abort(); 00083 void exit(); 00084 #if !defined(HOST_SVR4) 00085 int mprotect(char *addr, int len, int prot); 00086 #endif 00087 00088 #if !defined(HOST_SVR4) 00089 int socket(int, int, int); 00090 int bind (int, const void*, int); 00091 // int recvfrom (int, void*, int, int, void*, int *); 00092 // int sendto (int, const void*, int, int, void*, int); 00093 int getpagesize(); 00094 #else 00095 int socket(int, int, int); 00096 int bind(int, const struct sockaddr *, unsigned int); 00097 // int recvfrom(int, char *, int, int, struct sockaddr *, int *); 00098 // int sendto(int, const char *, int, int, struct sockaddr *, int); 00099 int getpagesize(); 00100 #endif 00101 } 00102 00103 #include "interrupt.h" 00104 #include "system.h" 00105 00106 //---------------------------------------------------------------------- 00107 // PollFile 00108 // Check open file or open socket to see if there are any 00109 // characters that can be read immediately. If so, read them 00110 // in, and return TRUE. 00111 // 00112 // In the network case, if there are no threads for us to run, 00113 // and no characters to be read, 00114 // we need to give the other side a chance to get our host's CPU 00115 // (otherwise, we'll go really slowly, since UNIX time-slices 00116 // infrequently, and this would be like busy-waiting). So we 00117 // delay for a short fixed time, before allowing ourselves to be 00118 // re-scheduled (sort of like a Yield, but cast in terms of UNIX). 00119 // 00120 // "fd" -- the file descriptor of the file to be polled 00121 //---------------------------------------------------------------------- 00122 00123 bool 00124 PollFile(int fd) 00125 { 00126 int rfd = (1 << fd), wfd = 0, xfd = 0, retVal; 00127 struct timeval pollTime; 00128 00129 // decide how long to wait if there are no characters on the file 00130 pollTime.tv_sec = 0; 00131 if (interrupt->getStatus() == IdleMode) 00132 pollTime.tv_usec = 20000; // delay to let other nachos run 00133 else 00134 pollTime.tv_usec = 0; // no delay 00135 00136 // poll file or socket 00137 #if defined(HOST_i386) || defined(HOST_SVR4) 00138 retVal = select(32, (fd_set*)&rfd, (fd_set*)&wfd, (fd_set*)&xfd, &pollTime); 00139 #else 00140 retVal = select(32, &rfd, &wfd, &xfd, &pollTime); 00141 #endif 00142 00143 ASSERT((retVal == 0) || (retVal == 1)); 00144 if (retVal == 0) 00145 return FALSE; // no char waiting to be read 00146 return TRUE; 00147 } 00148 00149 //---------------------------------------------------------------------- 00150 // OpenForWrite 00151 // Open a file for writing. Create it if it doesn't exist; truncate it 00152 // if it does already exist. Return the file descriptor. 00153 // 00154 // "name" -- file name 00155 //---------------------------------------------------------------------- 00156 00157 int 00158 OpenForWrite(char *name) 00159 { 00160 int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666); 00161 00162 ASSERT(fd >= 0); 00163 return fd; 00164 } 00165 00166 //---------------------------------------------------------------------- 00167 // OpenForReadWrite 00168 // Open a file for reading or writing. 00169 // Return the file descriptor, or error if it doesn't exist. 00170 // 00171 // "name" -- file name 00172 //---------------------------------------------------------------------- 00173 00174 int 00175 OpenForReadWrite(char *name, bool crashOnError) 00176 { 00177 int fd = open(name, O_RDWR, 0); 00178 00179 ASSERT(!crashOnError || fd >= 0); 00180 return fd; 00181 } 00182 00183 //---------------------------------------------------------------------- 00184 // Read 00185 // Read characters from an open file. Abort if read fails. 00186 //---------------------------------------------------------------------- 00187 00188 void 00189 Read(int fd, char *buffer, int nBytes) 00190 { 00191 int retVal = read(fd, buffer, nBytes); 00192 ASSERT(retVal == nBytes); 00193 } 00194 00195 //---------------------------------------------------------------------- 00196 // ReadPartial 00197 // Read characters from an open file, returning as many as are 00198 // available. 00199 //---------------------------------------------------------------------- 00200 00201 int 00202 ReadPartial(int fd, char *buffer, int nBytes) 00203 { 00204 return read(fd, buffer, nBytes); 00205 } 00206 00207 00208 //---------------------------------------------------------------------- 00209 // WriteFile 00210 // Write characters to an open file. Abort if write fails. 00211 //---------------------------------------------------------------------- 00212 00213 void 00214 WriteFile(int fd, char *buffer, int nBytes) 00215 { 00216 int retVal = write(fd, buffer, nBytes); 00217 ASSERT(retVal == nBytes); 00218 } 00219 00220 //---------------------------------------------------------------------- 00221 // Lseek 00222 // Change the location within an open file. Abort on error. 00223 //---------------------------------------------------------------------- 00224 00225 void 00226 Lseek(int fd, int offset, int whence) 00227 { 00228 int retVal = lseek(fd, offset, whence); 00229 ASSERT(retVal >= 0); 00230 } 00231 00232 //---------------------------------------------------------------------- 00233 // Tell 00234 // Report the current location within an open file. 00235 //---------------------------------------------------------------------- 00236 00237 int 00238 Tell(int fd) 00239 { 00240 #ifdef HOST_i386 00241 return lseek(fd,0,SEEK_CUR); // 386BSD doesn't have the tell() system call 00242 #else 00243 return tell(fd); 00244 #endif 00245 } 00246 00247 00248 //---------------------------------------------------------------------- 00249 // Close 00250 // Close a file. Abort on error. 00251 //---------------------------------------------------------------------- 00252 00253 void 00254 Close(int fd) 00255 { 00256 int retVal = close(fd); 00257 ASSERT(retVal >= 0); 00258 } 00259 00260 //---------------------------------------------------------------------- 00261 // Unlink 00262 // Delete a file. 00263 //---------------------------------------------------------------------- 00264 00265 bool 00266 Unlink(char *name) 00267 { 00268 return unlink(name); 00269 } 00270 00271 //---------------------------------------------------------------------- 00272 // OpenSocket 00273 // Open an interprocess communication (IPC) connection. For now, 00274 // just open a datagram port where other Nachos (simulating 00275 // workstations on a network) can send messages to this Nachos. 00276 //---------------------------------------------------------------------- 00277 00278 int 00279 OpenSocket() 00280 { 00281 int sockID; 00282 00283 sockID = socket(AF_UNIX, SOCK_DGRAM, 0); 00284 ASSERT(sockID >= 0); 00285 00286 return sockID; 00287 } 00288 00289 //---------------------------------------------------------------------- 00290 // CloseSocket 00291 // Close the IPC connection. 00292 //---------------------------------------------------------------------- 00293 00294 void 00295 CloseSocket(int sockID) 00296 { 00297 (void) close(sockID); 00298 } 00299 00300 //---------------------------------------------------------------------- 00301 // InitSocketName 00302 // Initialize a UNIX socket address -- magical! 00303 //---------------------------------------------------------------------- 00304 00305 static void 00306 InitSocketName(struct sockaddr_un *uname, char *name) 00307 { 00308 uname->sun_family = AF_UNIX; 00309 strcpy(uname->sun_path, name); 00310 } 00311 00312 //---------------------------------------------------------------------- 00313 // AssignNameToSocket 00314 // Give a UNIX file name to the IPC port, so other instances of Nachos 00315 // can locate the port. 00316 //---------------------------------------------------------------------- 00317 00318 void 00319 AssignNameToSocket(char *socketName, int sockID) 00320 { 00321 struct sockaddr_un uName; 00322 int retVal; 00323 00324 (void) unlink(socketName); // in case it's still around from last time 00325 00326 InitSocketName(&uName, socketName); 00327 retVal = bind(sockID, (struct sockaddr *) &uName, sizeof(uName)); 00328 ASSERT(retVal >= 0); 00329 DEBUG('n', "Created socket %s\n", socketName); 00330 } 00331 00332 //---------------------------------------------------------------------- 00333 // DeAssignNameToSocket 00334 // Delete the UNIX file name we assigned to our IPC port, on cleanup. 00335 //---------------------------------------------------------------------- 00336 void 00337 DeAssignNameToSocket(char *socketName) 00338 { 00339 (void) unlink(socketName); 00340 } 00341 00342 //---------------------------------------------------------------------- 00343 // PollSocket 00344 // Return TRUE if there are any messages waiting to arrive on the 00345 // IPC port. 00346 //---------------------------------------------------------------------- 00347 bool 00348 PollSocket(int sockID) 00349 { 00350 return PollFile(sockID); // on UNIX, socket ID's are just file ID's 00351 } 00352 00353 //---------------------------------------------------------------------- 00354 // ReadFromSocket 00355 // Read a fixed size packet off the IPC port. Abort on error. 00356 //---------------------------------------------------------------------- 00357 void 00358 ReadFromSocket(int sockID, char *buffer, int packetSize) 00359 { 00360 int retVal; 00361 extern int errno; 00362 struct sockaddr_un uName; 00363 int size = sizeof(uName); 00364 00365 retVal = recvfrom(sockID, buffer, packetSize, 0, 00366 (struct sockaddr *) &uName, &size); 00367 00368 if (retVal != packetSize) { 00369 perror("in recvfrom"); 00370 printf("called: %x, got back %d, %d\n", (unsigned int) buffer, 00371 retVal, errno); 00372 } 00373 ASSERT(retVal == packetSize); 00374 } 00375 00376 //---------------------------------------------------------------------- 00377 // SendToSocket 00378 // Transmit a fixed size packet to another Nachos' IPC port. 00379 // Abort on error. 00380 //---------------------------------------------------------------------- 00381 void 00382 SendToSocket(int sockID, char *buffer, int packetSize, char *toName) 00383 { 00384 struct sockaddr_un uName; 00385 int retVal; 00386 00387 InitSocketName(&uName, toName); 00388 retVal = sendto(sockID, buffer, packetSize, 0, 00389 #ifdef HOST_SVR4 00390 (sockaddr *) &uName, 00391 #else 00392 (char *) &uName, 00393 #endif /* HOST_SVR4 */ 00394 sizeof(uName)); 00395 ASSERT(retVal == packetSize); 00396 } 00397 00398 00399 //---------------------------------------------------------------------- 00400 // CallOnUserAbort 00401 // Arrange that "func" will be called when the user aborts (e.g., by 00402 // hitting ctl-C. 00403 //---------------------------------------------------------------------- 00404 00405 void 00406 CallOnUserAbort(VoidNoArgFunctionPtr func) 00407 { 00408 (void)signal(SIGINT, (VoidFunctionPtr) func); 00409 } 00410 00411 //---------------------------------------------------------------------- 00412 // Sleep 00413 // Put the UNIX process running Nachos to sleep for x seconds, 00414 // to give the user time to start up another invocation of Nachos 00415 // in a different UNIX shell. 00416 //---------------------------------------------------------------------- 00417 00418 void 00419 Delay(int seconds) 00420 { 00421 (void) sleep((unsigned) seconds); 00422 } 00423 00424 //---------------------------------------------------------------------- 00425 // Abort 00426 // Quit and drop core. 00427 //---------------------------------------------------------------------- 00428 00429 void 00430 Abort() 00431 { 00432 abort(); 00433 } 00434 00435 //---------------------------------------------------------------------- 00436 // Exit 00437 // Quit without dropping core. 00438 //---------------------------------------------------------------------- 00439 00440 void 00441 Exit(int exitCode) 00442 { 00443 exit(exitCode); 00444 } 00445 00446 //---------------------------------------------------------------------- 00447 // RandomInit 00448 // Initialize the pseudo-random number generator. We use the 00449 // now obsolete "srand" and "rand" because they are more portable! 00450 //---------------------------------------------------------------------- 00451 00452 void 00453 RandomInit(unsigned seed) 00454 { 00455 srand(seed); 00456 } 00457 00458 //---------------------------------------------------------------------- 00459 // Random 00460 // Return a pseudo-random number. 00461 //---------------------------------------------------------------------- 00462 00463 int 00464 Random() 00465 { 00466 return rand(); 00467 } 00468 00469 //---------------------------------------------------------------------- 00470 // AllocBoundedArray 00471 // Return an array, with the two pages just before 00472 // and after the array unmapped, to catch illegal references off 00473 // the end of the array. Particularly useful for catching overflow 00474 // beyond fixed-size thread execution stacks. 00475 // 00476 // Note: Just return the useful part! 00477 // 00478 // "size" -- amount of useful space needed (in bytes) 00479 //---------------------------------------------------------------------- 00480 00481 char * 00482 AllocBoundedArray(int size) 00483 { 00484 int pgSize = getpagesize(); 00485 char *ptr = new char[pgSize * 2 + size]; 00486 00487 mprotect(ptr, pgSize, 0); 00488 mprotect(ptr + pgSize + size, pgSize, 0); 00489 return ptr + pgSize; 00490 } 00491 00492 //---------------------------------------------------------------------- 00493 // DeallocBoundedArray 00494 // Deallocate an array of integers, unprotecting its two boundary pages. 00495 // 00496 // "ptr" -- the array to be deallocated 00497 // "size" -- amount of useful space in the array (in bytes) 00498 //---------------------------------------------------------------------- 00499 00500 void 00501 DeallocBoundedArray(char *ptr, int size) 00502 { 00503 int pgSize = getpagesize(); 00504 00505 mprotect(ptr - pgSize, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC); 00506 mprotect(ptr + size, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC); 00507 delete [] (ptr - pgSize); 00508 }
1.2.14 written by Dimitri van Heesch,
© 1997-2002