1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 2007
5 * File locking support as required by Haskell 98
7 * ---------------------------------------------------------------------------*/
9 #include "PosixSource.h"
16 #include <sys/types.h>
24 int readers; // >0 : readers, <0 : writers
27 // Two hash tables. The first maps objects (device/inode pairs) to
28 // Lock objects containing the number of active readers or writers. The
29 // second maps file descriptors to lock objects, so that we can unlock
30 // by FD without needing to fstat() again.
31 static HashTable *obj_hash;
32 static HashTable *fd_hash;
35 static Mutex file_lock_mutex;
38 static int cmpLocks(StgWord w1, StgWord w2)
40 Lock *l1 = (Lock *)w1;
41 Lock *l2 = (Lock *)w2;
42 return (l1->device == l2->device && l1->inode == l2->inode);
45 static int hashLock(HashTable *table, StgWord w)
48 // Just xor the dev_t with the ino_t, hope this is good enough.
49 return hashWord(table, (StgWord)l->inode ^ (StgWord)l->device);
55 obj_hash = allocHashTable_(hashLock, cmpLocks);
56 fd_hash = allocHashTable(); /* ordinary word-based table */
58 initMutex(&file_lock_mutex);
71 freeHashTable(obj_hash, freeLock);
72 freeHashTable(fd_hash, NULL);
74 closeMutex(&file_lock_mutex);
79 lockFile(int fd, dev_t dev, ino_t ino, int for_writing)
83 ACQUIRE_LOCK(&file_lock_mutex);
88 lock = lookupHashTable(obj_hash, (StgWord)&key);
92 lock = stgMallocBytes(sizeof(Lock), "lockFile");
95 lock->readers = for_writing ? -1 : 1;
96 insertHashTable(obj_hash, (StgWord)lock, (void *)lock);
97 insertHashTable(fd_hash, fd, lock);
98 RELEASE_LOCK(&file_lock_mutex);
103 // single-writer/multi-reader locking:
104 if (for_writing || lock->readers < 0) {
105 RELEASE_LOCK(&file_lock_mutex);
108 insertHashTable(fd_hash, fd, lock);
110 RELEASE_LOCK(&file_lock_mutex);
120 ACQUIRE_LOCK(&file_lock_mutex);
122 lock = lookupHashTable(fd_hash, fd);
124 // errorBelch("unlockFile: fd %d not found", fd);
125 // This is normal: we didn't know when calling unlockFile
126 // whether this FD referred to a locked file or not.
127 RELEASE_LOCK(&file_lock_mutex);
131 if (lock->readers < 0) {
137 if (lock->readers == 0) {
138 removeHashTable(obj_hash, (StgWord)lock, NULL);
141 removeHashTable(fd_hash, fd, NULL);
143 RELEASE_LOCK(&file_lock_mutex);