File: lockFile.c

package info (click to toggle)
ghc-cvs 20040725-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 68,484 kB
  • ctags: 19,658
  • sloc: haskell: 251,945; ansic: 109,709; asm: 24,961; sh: 12,825; perl: 5,786; makefile: 5,334; xml: 3,884; python: 682; yacc: 650; lisp: 477; cpp: 337; ml: 76; fortran: 24; csh: 18
file content (143 lines) | stat: -rw-r--r-- 3,248 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* 
 * (c) The GRASP/AQUA Project, Glasgow University, 1994-2004
 *
 * $Id: lockFile.c,v 1.3 2004/06/02 12:35:11 simonmar Exp $
 *
 * stdin/stout/stderr Runtime Support
 */

#include "HsBase.h"
#include "Rts.h"
#include "../../ghc/rts/RtsUtils.h" // for barf()

#ifdef mingw32_TARGET_OS
   // The Win32 C runtime has a max of 2048 file descriptors (see
   // _NHANDLE_ in the crt sources), but mingw defines FD_SETSIZE to
   // 64.
#  define NUM_FDS 2048
#else
#  ifndef FD_SETSIZE
#    error No FD_SETSIZE defined!
#  else
#    define NUM_FDS FD_SETSIZE
#  endif
#endif

typedef struct {
    dev_t device;
    ino_t inode;
    int fd;
} Lock;

static Lock readLock[NUM_FDS];
static Lock writeLock[NUM_FDS];

static int readLocks = 0;
static int writeLocks = 0;

int
lockFile(int fd, int for_writing, int exclusive)
{
    struct stat sb;
    int i;

    if (fd > NUM_FDS) {
	barf("lockFile: fd out of range");
    }

    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
	}
    }

    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__
	    return -1;
#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__
	     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__
	     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;
    }

}

int
unlockFile(int fd)
{
    int i;

    for (i = 0; i < readLocks; i++)
	if (readLock[i].fd == fd) {
	    while (++i < readLocks)
		readLock[i - 1] = readLock[i];
	    readLocks--;
	    return 0;
	}

    for (i = 0; i < writeLocks; i++)
	if (writeLock[i].fd == fd) {
	    while (++i < writeLocks)
		writeLock[i - 1] = writeLock[i];
	    writeLocks--;
	    return 0;
	}
     /* Signal that we did not find an entry */
    return 1;
}