[project @ 1999-02-04 12:13:15 by sof]
authorsof <unknown>
Thu, 4 Feb 1999 12:13:16 +0000 (12:13 +0000)
committersof <unknown>
Thu, 4 Feb 1999 12:13:16 +0000 (12:13 +0000)
- relax the restriction that just the one open writeable handle on
  *the same file* may exist when dealing with the standard handles,
  stdout and stderr.

  Reason: the following invocation of a Haskell program,

      foo >log 2>&1

  should be acceptable.

ghc/lib/std/cbits/getLock.c
ghc/lib/std/cbits/openFile.c
ghc/lib/std/cbits/stgio.h

index a0d93ad..be6acb4 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: getLock.c,v 1.3 1998/12/02 13:27:41 simonm Exp $
+ * $Id: getLock.c,v 1.4 1999/02/04 12:13:15 sof Exp $
  *
  * stdin/stout/stderr Runtime Support
  */
@@ -42,8 +42,9 @@ static int readLocks = 0;
 static int writeLocks = 0;
 
 int
-lockFile(fd, exclusive)
+lockFile(fd, for_writing, exclusive)
 int fd;
+int for_writing;
 int exclusive;
 {
     int i;
@@ -59,31 +60,55 @@ 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) {
            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;
-    }
-
-    for (i = 0; i < readLocks; i++)
-       if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
+        }          
+      }
+      /* 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) {
+            errno = EAGAIN;
+            return -1;
+         }
+        }
+      }
+      /* 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) {
            errno = EAGAIN;
            return -1;
-       }           
+        }
+      }
+      /* 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;
+    }
 
-    i = writeLocks++;
-    writeLock[i].device = sb.st_dev;
-    writeLock[i].inode = sb.st_ino;
-    writeLock[i].fd = fd;
-    return 0;
 }
 
 int
@@ -111,12 +136,13 @@ int fd;
     return 1;
 }
 
+/* getLock() is used when opening the standard file descriptors */
 StgInt
-getLock(fd, exclusive)
+getLock(fd, for_writing)
 StgInt fd;
-StgInt exclusive;
+StgInt for_writing;
 {
-    if (lockFile(fd, exclusive) < 0) {
+    if (lockFile(fd, for_writing, 0) < 0) {
        if (errno == EBADF)
            return 0;
        else {
index 2d5afe5..7d3b217 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: openFile.c,v 1.5 1999/01/23 17:44:40 sof Exp $
+ * $Id: openFile.c,v 1.6 1999/02/04 12:13:15 sof Exp $
  *
  * openFile Runtime Support
  */
 #include <fcntl.h>
 #endif
 
+#ifdef mingw32_TARGET_OS
+#define O_NOCTTY 0
+#endif
+
 IOFileObject*
 openStdFile(fd,flags,rd)
 StgInt fd;
@@ -63,7 +67,7 @@ StgInt flags;
     FILE *fp;
     int fd;
     int oflags;
-    int exclusive;
+    int for_writing;
     int created = 0;
     struct stat sb;
     IOFileObject* fo;
@@ -76,19 +80,19 @@ StgInt flags;
     switch (how) {
       case OPENFILE_APPEND:
         oflags = O_WRONLY | O_NOCTTY | O_APPEND; 
-       exclusive = 1;
+       for_writing = 1;
        break;
       case OPENFILE_WRITE:
        oflags = O_WRONLY | O_NOCTTY;
-       exclusive = 1;
+       for_writing = 1;
        break;
     case OPENFILE_READ_ONLY:
         oflags = O_RDONLY | O_NOCTTY;
-       exclusive = 0;
+       for_writing = 0;
        break;
     case OPENFILE_READ_WRITE:
        oflags = O_RDWR | O_NOCTTY;
-       exclusive = 0;
+       for_writing = 1;
        break;
     default:
        fprintf(stderr, "openFile: unknown mode `%d'\n", how);
@@ -110,12 +114,14 @@ StgInt flags;
                return NULL;
            } else {
                /* If it is a dangling symlink, break off now, too. */
+#ifndef mingw32_TARGET_OS
                struct stat st;
                if ( lstat(file,&st) == 0) {
                   ghc_errtype = ERR_NOSUCHTHING;
                   ghc_errstr = "dangling symlink";
                   return NULL;
                }
+#endif
             }
            /* Now try to create it */
            while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
@@ -186,7 +192,7 @@ StgInt flags;
     }
     /* Use our own personal locking */
 
-    if (lockFile(fd, exclusive) < 0) {
+    if (lockFile(fd, for_writing, 1/*enforce single-writer, if needs be.*/) < 0) {
        cvtErrno();
        switch (ghc_errno) {
        default:
@@ -268,11 +274,13 @@ StgInt fd;
 StgInt oflags;
 StgInt flags;
 {
-    int exclusive;
+    int for_writing;
     FILE* fp;
     IOFileObject* fo;
 
-    if (lockFile(fd, exclusive) < 0) {
+    for_writing = ( ((oflags & O_WRONLY) || (oflags & O_RDWR)) ? 1 : 0);
+
+    if (lockFile(fd, for_writing, 1/* enforce single-writer */ ) < 0) {
        cvtErrno();
        switch (ghc_errno) {
        default:
index 68a0979..9631807 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: stgio.h,v 1.9 1999/01/15 17:54:23 sof Exp $
+ * $Id: stgio.h,v 1.10 1999/02/04 12:13:16 sof Exp $
  *
  * Helper code for GHC's IO subsystem.
  */
@@ -146,7 +146,7 @@ StgAddr getCurrentDirectory(void);
 StgAddr getDirectoryContents (StgByteArray);
 
 /* getLock.c */
-int     lockFile    (int, int);
+int     lockFile    (int, int, int);
 int     unlockFile  (int);
 StgInt getLock     (StgInt, StgInt);