[project @ 1999-03-17 13:19:19 by simonm]
[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.5 1999/03/01 09:11:39 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 #ifndef __MINGW32__
69             errno = EAGAIN;
70             return -1;
71 #else
72             break;    
73 #endif
74          }          
75       }
76       /* If we're determined that there is only a single
77          writer to the file, check to see whether the file
78          hasn't already been opened for writing..
79       */
80       if (exclusive) {
81         for (i = 0; i < writeLocks; i++) {
82           if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
83 #ifndef __MINGW32__
84              errno = EAGAIN;
85              return -1;
86 #else
87              break;
88 #endif
89           }
90         }
91       }
92       /* OK, everything is cool lock-wise, record it and leave. */
93       i = writeLocks++;
94       writeLock[i].device = sb.st_dev;
95       writeLock[i].inode = sb.st_ino;
96       writeLock[i].fd = fd;
97       return 0;
98     } else { 
99       /* For reading, it's simpler - just check to see
100          that there's no-one writing to the underlying file. */
101       for (i = 0; i < writeLocks; i++) {
102         if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
103 #ifndef __MINGW32__
104              errno = EAGAIN;
105              return -1;
106 #else
107              break;
108 #endif
109         }
110       }
111       /* Fit in new entry, reusing an existing table entry, if possible. */
112       for (i = 0; i < readLocks; i++) {
113          if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
114            return 0;
115          }
116       }
117       i = readLocks++;
118       readLock[i].device = sb.st_dev;
119       readLock[i].inode = sb.st_ino;
120       readLock[i].fd = fd;
121       return 0;
122     }
123
124 }
125
126 int
127 unlockFile(fd)
128 int fd;
129 {
130     int i, rc;
131
132     for (i = 0; i < readLocks; i++)
133         if (readLock[i].fd == fd) {
134             while (++i < readLocks)
135                 readLock[i - 1] = readLock[i];
136             readLocks--;
137             return 0;
138         }
139
140     for (i = 0; i < writeLocks; i++)
141         if (writeLock[i].fd == fd) {
142             while (++i < writeLocks)
143                 writeLock[i - 1] = writeLock[i];
144             writeLocks--;
145             return 0;
146         }
147      /* Signal that we did not find an entry */
148     return 1;
149 }
150
151 /* getLock() is used when opening the standard file descriptors */
152 StgInt
153 getLock(fd, for_writing)
154 StgInt fd;
155 StgInt for_writing;
156 {
157     if (lockFile(fd, for_writing, 0) < 0) {
158         if (errno == EBADF)
159             return 0;
160         else {
161             cvtErrno();
162             switch (ghc_errno) {
163             default:
164                 stdErrno();
165                 break;
166             case GHC_EACCES:
167             case GHC_EAGAIN:
168                 ghc_errtype = ERR_RESOURCEBUSY;
169                 ghc_errstr = "file is locked";
170                 break;
171             }
172             /* Not so sure we want to do this, since getLock() 
173             is only called on the standard file descriptors.. */
174             /*(void) close(fd); */
175             return -1;
176         }
177     }
178     return 1;
179 }