[project @ 2001-03-01 12:25:32 by rrt]
[ghc-hetmet.git] / ghc / lib / std / cbits / getLock.c
index c2b4762..143da77 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: getLock.c,v 1.1 1998/04/10 10:54:39 simonm Exp $
+ * $Id: getLock.c,v 1.8 2001/03/01 12:25:33 rrt Exp $
  *
  * stdin/stout/stderr Runtime Support
  */
@@ -42,14 +42,24 @@ static int readLocks = 0;
 static int writeLocks = 0;
 
 int
-lockFile(int fd, int exclusive)
+lockFile(fd, for_writing, exclusive)
+int fd;
+int for_writing;
+int exclusive;
 {
     int i;
-    struct stat sb;
+    struct Stat sb;
 
-    while (fstat(fd, &sb) < 0) {
+    while (Fstat(fd, &sb) < 0) {
        if (errno != EINTR) {
+#ifndef _WIN32
            return -1;
+#else
+           /* fstat()ing socket fd's seems to fail with CRT's fstat(),
+              so let's just silently return and hope for the best..
+           */
+           return 0;
+#endif
        }
     }
 
@@ -57,37 +67,74 @@ lockFile(int fd, int exclusive)
     if (!S_ISREG(sb.st_mode))
        return 0;
     
-    for (i = 0; i < writeLocks; i++)
-       if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
+    if (for_writing) {
+      /* opening a file for writing, check to see whether
+         we don't have any read locks on it already.. */
+      for (i = 0; i < readLocks; i++) {
+        if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
+#ifndef __MINGW32__
            errno = EAGAIN;
            return -1;
-       }
-
-    if (!exclusive) {
-       i = readLocks++;
-       readLock[i].device = sb.st_dev;
-       readLock[i].inode = sb.st_ino;
-       readLock[i].fd = fd;
-       return 0;
+#else
+           break;    
+#endif
+        }          
+      }
+      /* If we're determined that there is only a single
+         writer to the file, check to see whether the file
+        hasn't already been opened for writing..
+      */
+      if (exclusive) {
+       for (i = 0; i < writeLocks; i++) {
+         if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
+#ifndef __MINGW32__
+            errno = EAGAIN;
+            return -1;
+#else
+            break;
+#endif
+         }
+        }
+      }
+      /* OK, everything is cool lock-wise, record it and leave. */
+      i = writeLocks++;
+      writeLock[i].device = sb.st_dev;
+      writeLock[i].inode = sb.st_ino;
+      writeLock[i].fd = fd;
+      return 0;
+    } else { 
+      /* For reading, it's simpler - just check to see
+         that there's no-one writing to the underlying file. */
+      for (i = 0; i < writeLocks; i++) {
+       if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
+#ifndef __MINGW32__
+            errno = EAGAIN;
+            return -1;
+#else
+            break;
+#endif
+        }
+      }
+      /* Fit in new entry, reusing an existing table entry, if possible. */
+      for (i = 0; i < readLocks; i++) {
+        if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
+          return 0;
+        }
+      }
+      i = readLocks++;
+      readLock[i].device = sb.st_dev;
+      readLock[i].inode = sb.st_ino;
+      readLock[i].fd = fd;
+      return 0;
     }
 
-    for (i = 0; i < readLocks; i++)
-       if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
-           errno = EAGAIN;
-           return -1;
-       }           
-
-    i = writeLocks++;
-    writeLock[i].device = sb.st_dev;
-    writeLock[i].inode = sb.st_ino;
-    writeLock[i].fd = fd;
-    return 0;
 }
 
 int
-unlockFile(int fd)
+unlockFile(fd)
+int fd;
 {
-    int i, rc;
+    int i;
 
     for (i = 0; i < readLocks; i++)
        if (readLock[i].fd == fd) {
@@ -108,10 +155,13 @@ unlockFile(int fd)
     return 1;
 }
 
+/* getLock() is used when opening the standard file descriptors */
 StgInt
-getLock(StgAddr fp, StgInt exclusive)
+getLock(fd, for_writing)
+StgInt fd;
+StgInt for_writing;
 {
-    if (lockFile(fileno((FILE *) fp), exclusive) < 0) {
+    if (lockFile(fd, for_writing, 0) < 0) {
        if (errno == EBADF)
            return 0;
        else {
@@ -126,10 +176,11 @@ getLock(StgAddr fp, StgInt exclusive)
                ghc_errstr = "file is locked";
                break;
            }
-           (void) fclose((FILE *) fp);
+           /* Not so sure we want to do this, since getLock() 
+           is only called on the standard file descriptors.. */
+           /*(void) close(fd); */
            return -1;
        }
     }
     return 1;
 }
-