aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/libical/filelock.c
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/libical/filelock.c')
-rw-r--r--libical/src/libical/filelock.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/libical/src/libical/filelock.c b/libical/src/libical/filelock.c
new file mode 100644
index 0000000000..0376bc2bec
--- /dev/null
+++ b/libical/src/libical/filelock.c
@@ -0,0 +1,143 @@
+
+/*
+ I Stole this from:
+ http://www.cis.temple.edu/~ingargio/old/cis307s96/readings/rwlockexample.html
+
+ CIS 307: An example using Read/Write File Locks
+ [fcntl.h], [fcntl.c], [fcntlmain.c]
+
+In Stevens "Advanced Programming in the Unix Environment" we see ways to use
+the Unix service fcntl to lock portions of a file for reading and writing in
+the manner stated in the Reader and Writer problem [any number of readers at
+a time, but writers must operate alone]. Here we have three files that adapt
+and use the code from Stevens:
+
+*fcntl.h: Specification of the locking functions.
+*fcntl.c: Implementation of the locking functions.
+*fcntlmain.c: Driver that does a simple test of the locking functions.
+
+WARNING: A file lock request which is blocked can be interrupted by a
+signal. In this case the lock operation returns EINTR. Thus we may think we
+got a lock when we really don't. A solution is to block signals when
+locking. Another solution is to test the value returned by the lock
+operation and relock if the value is EINTR. Another solution, which we adopt
+here, is to do nothing about it.
+
+/* fcntl.c -- Defines mutexes in terms of read/write locks on files.
+ * (code is mostly from Stevens: Advanced Programming in the
+ * Unix environment. See from page 367 on.
+ * filerwlock, filerwlockCreate, filerwlockDelete,
+ * filerwreadlock, filerwlongreadlock, filerwlongunlock,
+ * filerwlockUnlock
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int lock_reg(int, int, int, off_t, int, off_t);
+
+#define read_lock(fd, offset, whence, len) \
+ lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
+
+#define readw_lock(fd, offset, whence, len) \
+ lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len)
+
+#define write_lock(fd, offset, whence, len) \
+ lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
+
+#define writew_lock(fd, offset, whence, len) \
+ lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)
+
+#define un_lock(fd, offset, whence, len) \
+ lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)
+
+pid_t lock_test(int, int , off_t , int , off_t );
+
+#define is_readlock(fd, offset, whence, len) \
+ lock_test(fd, F_RDLCK, offset, whence, len)
+
+#define is_writelock(fd, offset, whence, len) \
+ lock_test(fd, F_WRLCK, offset, whence, len)
+
+int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
+{
+ struct flock lock;
+ lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
+ lock.l_start = offset; /* byte offset relative to l_whence */
+ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
+ lock.l_len = len; /* #bytes (0 means to EOF) */
+ return (fcntl(fd, cmd, &lock));
+}
+
+pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len)
+{
+ struct flock lock;
+ lock.l_type = type; /* F_RDLCK or F_WRLCK */
+ lock.l_start = offset; /* byte offset relative to l_whence */
+ lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
+ lock.l_len = len; /* #bytes (0 means to EOF) */
+ if (fcntl(fd,F_GETLK,&lock) < 0){
+ perror("fcntl"); exit(1);}
+ if (lock.l_type == F_UNLCK)
+ return (0); /* false, region is not locked by another process */
+ return (lock.l_pid); /* true, return pid of lock owner */
+}
+
+typedef struct {
+ int fd;
+ int n;} filerwlock;
+
+/* Create N read/write locks and returns the id of this cluster of locks. */
+filerwlock * filerwlockCreate(char *filename, int n) {
+ filerwlock *fl = (filerwlock *)malloc(sizeof(filerwlock));
+ if (((fl->fd) = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR)) < 0) {
+ perror("open");
+ exit(1);}
+ fl->n = n;
+ return fl;
+ }
+
+/* Delete the cluster of read/write locks associated with fl. */
+int filerwlockDelete(filerwlock *fl) {
+ if (close(fl->fd) < 0) {
+ perror("close");
+ exit(1);}
+ return free(fl);
+ }
+
+/* Given the read/write lock cluster fl, lock its ith element */
+int filerwreadlock(filerwlock *fl, int i) {
+ if ((i < 0) | (i >= fl->n)) {
+ printf("filerwlockLock needs i in range 0 .. %d\n", (fl->n)-1);
+ exit(0);}
+ readw_lock(fl->fd, i, SEEK_SET, 1);
+ }
+
+int filerwwritelock(filerwlock *fl, int i) {
+ if ((i < 0) | (i >= fl->n)) {
+ printf("filerwlockLock needs i in range 0 .. %d\n", (fl->n)-1);
+ exit(0);}
+ writew_lock(fl->fd, i, SEEK_SET, 1);
+ }
+
+/* Given the lock cluster fl, unlock its ith element */
+int filerwunlock(filerwlock *fl, int i){
+
+ if ((i < 0) | (i >= fl->n)) {
+ printf("filerwlockUnlock needs i in range 0 .. %d\n", (fl->n)-1);
+ exit(0);}
+ un_lock(fl->fd, i, SEEK_SET, 1);
+ }
+
+/* Given the lock cluster fl, it read locks all its elements */
+int filerwlongreadlock(filerwlock *fl) {
+ readw_lock(fl->fd, 0, SEEK_SET, fl->n);
+}
+
+/* Given the lock cluster fl, it unlocks all its elements */
+int filerwlongunlock(filerwlock *fl) {
+ un_lock(fl->fd, 0, SEEK_SET, fl->n);
+}
+