diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index d4ff5df379..7b63ce00ec 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -21,6 +21,12 @@ #define STDOUT_FILENO 1 #define STDERR_FILENO 2 +/* function arguments needed by lockf() */ +#define F_ULOCK 0 /* unlock locked sections */ +#define F_LOCK 1 /* lock a section for exclusive use */ +#define F_TLOCK 2 /* test and lock a section for exclusive use */ +#define F_TEST 3 /* test a section for locks by other processes */ + /* POSIX version support */ #define _POSIX_VERSION (199009L) @@ -111,7 +117,8 @@ extern int getdtablesize(void); extern long sysconf(int name); extern long fpathconf(int fd, int name); extern long pathconf(const char *path, int name); -extern size_t confstr(int name, char *buf, size_t len); +extern size_t confstr(int name, char *buf, size_t len); +extern int lockf(int fd, int function, off_t size); /* process functions */ extern pid_t fork(void); diff --git a/src/system/libroot/posix/unistd/Jamfile b/src/system/libroot/posix/unistd/Jamfile index 9a9799a3a0..54ea8dc0b0 100644 --- a/src/system/libroot/posix/unistd/Jamfile +++ b/src/system/libroot/posix/unistd/Jamfile @@ -17,6 +17,7 @@ MergeObject posix_unistd.o : hostname.cpp ioctl.c link.c + lockf.cpp lseek.c mknod.c mount.c diff --git a/src/system/libroot/posix/unistd/lockf.cpp b/src/system/libroot/posix/unistd/lockf.cpp new file mode 100644 index 0000000000..cd408bee31 --- /dev/null +++ b/src/system/libroot/posix/unistd/lockf.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2007, Vasilis Kaoutsis, kaoutsis@sch.gr. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include + + +int +lockf(int fileDescriptor, int function, off_t size) +{ + struct flock fileLock; + fileLock.l_start = 0; + fileLock.l_len = size; + fileLock.l_whence = SEEK_CUR; + + if (function == F_ULOCK) { + // unlock locked sections + fileLock.l_type = F_UNLCK; + return fcntl(fileDescriptor, F_SETLK, &fileLock); + } else if (function == F_LOCK) { + // lock a section for exclusive use + fileLock.l_type = F_WRLCK; + return fcntl(fileDescriptor, F_SETLKW, &fileLock); + } else if (function == F_TLOCK) { + // test and lock a section for exclusive use + fileLock.l_type = F_WRLCK; + return fcntl(fileDescriptor, F_SETLK, &fileLock); + } else if (function == F_TEST) { + // test a section for locks by other processes + fileLock.l_type = F_WRLCK; + if (fcntl(fileDescriptor, F_GETLK, &fileLock) == -1) + return -1; + if (fileLock.l_type == F_UNLCK) + return 0; + + errno = EAGAIN; + return -1; + } else { + errno = EINVAL; + return -1; + } + + // Notes regarding standard compliance (cf. Open Group Base Specs): + // * "The interaction between fcntl() and lockf() locks is unspecified." + // * fcntl() locking works on a per-process level. The lockf() description + // is a little fuzzy on whether it works the same way. The first quote + // seem to describe per-thread locks (though it might actually mean + // "threads of other processes"), but the others quotes are strongly + // indicating per-process locks: + // - "Calls to lockf() from other threads which attempt to lock the locked + // file section shall either return an error value or block until the + // section becomes unlocked." + // - "All the locks for a process are removed when the process + // terminates." + // - "F_TEST shall detect if a lock by another process is present on the + // specified section." + // - "The sections locked with F_LOCK or F_TLOCK may, in whole or in part, + // contain or be contained by a previously locked section for the same + // process. When this occurs, or if adjacent locked sections would + // occur, the sections shall be combined into a single locked section." + // * fcntl() and lockf() handle a 0 size argument differently. The former + // use the file size at the time of the call: + // "If the command is F_SETLKW and the process must wait for another + // process to release a lock, then the range of bytes to be locked shall + // be determined before the fcntl() function blocks. If the file size + // or file descriptor seek offset change while fcntl() is blocked, this + // shall not affect the range of bytes locked." + // lockf(), on the other hand, is supposed to create a lock whose size + // dynamically adjusts to the file size: + // "If size is 0, the section from the current offset through the largest + // possible file offset shall be locked (that is, from the current + // offset through the present or any future end-of-file)." + // * The lock release handling when closing descriptors sounds a little + // different, though might actually mean the same. + // For fcntl(): + // "All locks associated with a file for a given process shall be removed + // when a file descriptor for that file is closed by that process or the + // process holding that file descriptor terminates." + // For lockf(): + // "File locks shall be released on first close by the locking process of + // any file descriptor for the file." +}