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