[project @ 1999-02-04 12:13:15 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / getLock.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: getLock.c,v 1.4 1999/02/04 12:13:15 sof Exp $
5  *
6  * stdin/stout/stderr Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h>
22 #endif
23
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27
28 #ifndef FD_SETSIZE
29 #define FD_SETSIZE 256
30 #endif
31
32 typedef struct {
33     dev_t device;
34     ino_t inode;
35     int fd;
36 } Lock;
37
38 static Lock readLock[FD_SETSIZE];
39 static Lock writeLock[FD_SETSIZE];
40
41 static int readLocks = 0;
42 static int writeLocks = 0;
43
44 int
45 lockFile(fd, for_writing, exclusive)
46 int fd;
47 int for_writing;
48 int exclusive;
49 {
50     int i;
51     struct stat sb;
52
53     while (fstat(fd, &sb) < 0) {
54         if (errno != EINTR) {
55             return -1;
56         }
57     }
58
59     /* Only lock regular files */
60     if (!S_ISREG(sb.st_mode))
61         return 0;
62     
63     if (for_writing) {
64       /* opening a file for writing, check to see whether
65          we don't have any read locks on it already.. */
66       for (i = 0; i < readLocks; i++) {
67          if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
68             errno = EAGAIN;
69             return -1;
70          }          
71       }
72       /* If we're determined that there is only a single
73          writer to the file, check to see whether the file
74          hasn't already been opened for writing..
75       */
76       if (exclusive) {
77         for (i = 0; i < writeLocks; i++) {
78           if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
79              errno = EAGAIN;
80              return -1;
81           }
82         }
83       }
84       /* OK, everything is cool lock-wise, record it and leave. */
85       i = writeLocks++;
86       writeLock[i].device = sb.st_dev;
87       writeLock[i].inode = sb.st_ino;
88       writeLock[i].fd = fd;
89       return 0;
90     } else { 
91       /* For reading, it's simpler - just check to see
92          that there's no-one writing to the underlying file. */
93       for (i = 0; i < writeLocks; i++) {
94         if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
95             errno = EAGAIN;
96             return -1;
97         }
98       }
99       /* Fit in new entry, reusing an existing table entry, if possible. */
100       for (i = 0; i < readLocks; i++) {
101          if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
102            return 0;
103          }
104       }
105       i = readLocks++;
106       readLock[i].device = sb.st_dev;
107       readLock[i].inode = sb.st_ino;
108       readLock[i].fd = fd;
109       return 0;
110     }
111
112 }
113
114 int
115 unlockFile(fd)
116 int fd;
117 {
118     int i, rc;
119
120     for (i = 0; i < readLocks; i++)
121         if (readLock[i].fd == fd) {
122             while (++i < readLocks)
123                 readLock[i - 1] = readLock[i];
124             readLocks--;
125             return 0;
126         }
127
128     for (i = 0; i < writeLocks; i++)
129         if (writeLock[i].fd == fd) {
130             while (++i < writeLocks)
131                 writeLock[i - 1] = writeLock[i];
132             writeLocks--;
133             return 0;
134         }
135      /* Signal that we did not find an entry */
136     return 1;
137 }
138
139 /* getLock() is used when opening the standard file descriptors */
140 StgInt
141 getLock(fd, for_writing)
142 StgInt fd;
143 StgInt for_writing;
144 {
145     if (lockFile(fd, for_writing, 0) < 0) {
146         if (errno == EBADF)
147             return 0;
148         else {
149             cvtErrno();
150             switch (ghc_errno) {
151             default:
152                 stdErrno();
153                 break;
154             case GHC_EACCES:
155             case GHC_EAGAIN:
156                 ghc_errtype = ERR_RESOURCEBUSY;
157                 ghc_errstr = "file is locked";
158                 break;
159             }
160             /* Not so sure we want to do this, since getLock() 
161             is only called on the standard file descriptors.. */
162             /*(void) close(fd); */
163             return -1;
164         }
165     }
166     return 1;
167 }