mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Add more apis to redbean unix module
- Document unix.fcntl() - Add POSIX Advisory Locks - Add mask parameter to unix.poll() - Add lowest parameter to unix.dup()
This commit is contained in:
parent
ce588dd56b
commit
a1aaf23dc1
16 changed files with 432 additions and 102 deletions
|
@ -110,8 +110,9 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||||
if (cmd == F_GETFL) {
|
if (cmd == F_GETFL) {
|
||||||
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
|
return g_fds.p[fd].flags &
|
||||||
O_NOATIME | O_NONBLOCK);
|
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||||
|
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||||
} else if (cmd == F_SETFL) {
|
} else if (cmd == F_SETFL) {
|
||||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||||
// O_NONBLOCK might require we start doing all i/o in threads
|
// O_NONBLOCK might require we start doing all i/o in threads
|
||||||
|
@ -131,7 +132,7 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (cmd == F_SETLK || cmd == F_SETLKW) {
|
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||||
|
|
|
@ -74,14 +74,12 @@ void flock2cosmo(uintptr_t memory) {
|
||||||
l_pid = u->linux.l_pid;
|
l_pid = u->linux.l_pid;
|
||||||
l_type = u->linux.l_type;
|
l_type = u->linux.l_type;
|
||||||
l_whence = u->linux.l_whence;
|
l_whence = u->linux.l_whence;
|
||||||
l_sysid = 0;
|
|
||||||
} else if (IsXnu()) {
|
} else if (IsXnu()) {
|
||||||
l_start = u->xnu.l_start;
|
l_start = u->xnu.l_start;
|
||||||
l_len = u->xnu.l_len;
|
l_len = u->xnu.l_len;
|
||||||
l_pid = u->xnu.l_pid;
|
l_pid = u->xnu.l_pid;
|
||||||
l_type = u->xnu.l_type;
|
l_type = u->xnu.l_type;
|
||||||
l_whence = u->xnu.l_whence;
|
l_whence = u->xnu.l_whence;
|
||||||
l_sysid = 0;
|
|
||||||
} else if (IsFreebsd()) {
|
} else if (IsFreebsd()) {
|
||||||
l_start = u->freebsd.l_start;
|
l_start = u->freebsd.l_start;
|
||||||
l_len = u->freebsd.l_len;
|
l_len = u->freebsd.l_len;
|
||||||
|
@ -89,20 +87,19 @@ void flock2cosmo(uintptr_t memory) {
|
||||||
l_type = u->freebsd.l_type;
|
l_type = u->freebsd.l_type;
|
||||||
l_whence = u->freebsd.l_whence;
|
l_whence = u->freebsd.l_whence;
|
||||||
l_sysid = u->freebsd.l_sysid;
|
l_sysid = u->freebsd.l_sysid;
|
||||||
|
u->cosmo.l_sysid = l_sysid;
|
||||||
} else if (IsOpenbsd()) {
|
} else if (IsOpenbsd()) {
|
||||||
l_start = u->openbsd.l_start;
|
l_start = u->openbsd.l_start;
|
||||||
l_len = u->openbsd.l_len;
|
l_len = u->openbsd.l_len;
|
||||||
l_pid = u->openbsd.l_pid;
|
l_pid = u->openbsd.l_pid;
|
||||||
l_type = u->openbsd.l_type;
|
l_type = u->openbsd.l_type;
|
||||||
l_whence = u->openbsd.l_whence;
|
l_whence = u->openbsd.l_whence;
|
||||||
l_sysid = 0;
|
|
||||||
} else if (IsNetbsd()) {
|
} else if (IsNetbsd()) {
|
||||||
l_start = u->netbsd.l_start;
|
l_start = u->netbsd.l_start;
|
||||||
l_len = u->netbsd.l_len;
|
l_len = u->netbsd.l_len;
|
||||||
l_pid = u->netbsd.l_pid;
|
l_pid = u->netbsd.l_pid;
|
||||||
l_type = u->netbsd.l_type;
|
l_type = u->netbsd.l_type;
|
||||||
l_whence = u->netbsd.l_whence;
|
l_whence = u->netbsd.l_whence;
|
||||||
l_sysid = 0;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +108,6 @@ void flock2cosmo(uintptr_t memory) {
|
||||||
u->cosmo.l_pid = l_pid;
|
u->cosmo.l_pid = l_pid;
|
||||||
u->cosmo.l_type = l_type;
|
u->cosmo.l_type = l_type;
|
||||||
u->cosmo.l_whence = l_whence;
|
u->cosmo.l_whence = l_whence;
|
||||||
u->cosmo.l_sysid = l_sysid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmo2flock(uintptr_t memory) {
|
void cosmo2flock(uintptr_t memory) {
|
||||||
|
|
|
@ -61,17 +61,22 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
struct sys_pollfd_nt sockfds[64];
|
struct sys_pollfd_nt sockfds[64];
|
||||||
int pipeindices[ARRAYLEN(pipefds)];
|
int pipeindices[ARRAYLEN(pipefds)];
|
||||||
int sockindices[ARRAYLEN(sockfds)];
|
int sockindices[ARRAYLEN(sockfds)];
|
||||||
int i, sn, pn, failed, gotinvals, gotpipes, gotsocks, waitfor;
|
int i, rc, sn, pn, gotinvals, gotpipes, gotsocks, waitfor;
|
||||||
|
|
||||||
// check for interrupts early before doing work
|
// check for interrupts early before doing work
|
||||||
if (sigmask && __sig_mask(SIG_SETMASK, sigmask, &oldmask)) return -1;
|
if (sigmask) {
|
||||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||||
|
}
|
||||||
|
if (_check_interrupts(false, g_fds.p)) {
|
||||||
|
rc = eintr();
|
||||||
|
goto ReturnPath;
|
||||||
|
}
|
||||||
|
|
||||||
// do the planning
|
// do the planning
|
||||||
// we need to read static variables
|
// we need to read static variables
|
||||||
// we might need to spawn threads and open pipes
|
// we might need to spawn threads and open pipes
|
||||||
__fds_lock();
|
__fds_lock();
|
||||||
for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) {
|
for (gotinvals = rc = sn = pn = i = 0; i < nfds; ++i) {
|
||||||
if (fds[i].fd < 0) continue;
|
if (fds[i].fd < 0) continue;
|
||||||
if (__isfdopen(fds[i].fd)) {
|
if (__isfdopen(fds[i].fd)) {
|
||||||
if (__isfdkind(fds[i].fd, kFdSocket)) {
|
if (__isfdkind(fds[i].fd, kFdSocket)) {
|
||||||
|
@ -85,7 +90,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
++sn;
|
++sn;
|
||||||
} else {
|
} else {
|
||||||
// too many socket fds
|
// too many socket fds
|
||||||
failed = enomem();
|
rc = enomem();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (pn < ARRAYLEN(pipefds)) {
|
} else if (pn < ARRAYLEN(pipefds)) {
|
||||||
|
@ -109,7 +114,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
++pn;
|
++pn;
|
||||||
} else {
|
} else {
|
||||||
// too many non-socket fds
|
// too many non-socket fds
|
||||||
failed = enomem();
|
rc = enomem();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,9 +122,9 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__fds_unlock();
|
__fds_unlock();
|
||||||
if (failed) {
|
if (rc) {
|
||||||
// failed to create a polling solution
|
// failed to create a polling solution
|
||||||
return failed;
|
goto ReturnPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform the i/o and sleeping and looping
|
// perform the i/o and sleeping and looping
|
||||||
|
@ -164,7 +169,8 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
|
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
|
||||||
#endif
|
#endif
|
||||||
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
||||||
return __winsockerr();
|
rc = __winsockerr();
|
||||||
|
goto ReturnPath;
|
||||||
}
|
}
|
||||||
*ms -= waitfor;
|
*ms -= waitfor;
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,7 +194,8 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
// otherwise loop limitlessly for timeout to elapse while
|
// otherwise loop limitlessly for timeout to elapse while
|
||||||
// checking for signal delivery interrupts, along the way
|
// checking for signal delivery interrupts, along the way
|
||||||
if (_check_interrupts(false, g_fds.p)) {
|
if (_check_interrupts(false, g_fds.p)) {
|
||||||
return eintr();
|
rc = eintr();
|
||||||
|
goto ReturnPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,5 +216,11 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally return
|
// and finally return
|
||||||
return gotinvals + gotpipes + gotsocks;
|
rc = gotinvals + gotpipes + gotsocks;
|
||||||
|
|
||||||
|
ReturnPath:
|
||||||
|
if (sigmask) {
|
||||||
|
__sig_mask(SIG_SETMASK, &oldmask, 0);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ struct flock { /* cosmopolitan abi */
|
||||||
int16_t l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
int16_t l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||||
int16_t l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
int16_t l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||||
int64_t l_start; /* starting offset */
|
int64_t l_start; /* starting offset */
|
||||||
int64_t l_len; /* 0 means until end of file */
|
int64_t l_len; /* no. bytes (0 means to end of file) */
|
||||||
int32_t l_pid; /* lock owner */
|
int32_t l_pid; /* lock owner */
|
||||||
int32_t l_sysid; /* remote system id or zero for local */
|
int32_t l_sysid; /* remote system id or zero for local */
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,6 +61,7 @@ kOpenFlags:
|
||||||
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
||||||
.e O_COMPRESSED,"COMPRESSED" // windows
|
.e O_COMPRESSED,"COMPRESSED" // windows
|
||||||
.e O_INDEXED,"INDEXED" // windows
|
.e O_INDEXED,"INDEXED" // windows
|
||||||
|
.e O_LARGEFILE,"LARGEFILE" //
|
||||||
.long MAGNUM_TERMINATOR
|
.long MAGNUM_TERMINATOR
|
||||||
.endobj kOpenFlags,globl,hidden
|
.endobj kOpenFlags,globl,hidden
|
||||||
.overrun
|
.overrun
|
||||||
|
|
|
@ -52,7 +52,7 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||||
struct timeval tv, *tvp;
|
struct timeval tv, *tvp;
|
||||||
struct timespec ts, *tsp;
|
struct timespec ts, *tsp;
|
||||||
struct {
|
struct {
|
||||||
sigset_t *s;
|
const sigset_t *s;
|
||||||
size_t n;
|
size_t n;
|
||||||
} ss;
|
} ss;
|
||||||
if (nfds < 0) {
|
if (nfds < 0) {
|
||||||
|
|
|
@ -213,7 +213,7 @@ syscon open O_VERIFY 0 0 0x00200000 0 0 0 #
|
||||||
syscon open O_SHLOCK 0 0x00000010 0x00000010 0x00000010 0x00000010 0 #
|
syscon open O_SHLOCK 0 0x00000010 0x00000010 0x00000010 0x00000010 0 #
|
||||||
syscon open O_EXLOCK 0 0x00000020 0x00000020 0x00000020 0x00000020 0 #
|
syscon open O_EXLOCK 0 0x00000020 0x00000020 0x00000020 0x00000020 0 #
|
||||||
syscon open O_TTY_INIT 0 0 0x00080000 0 0 0 #
|
syscon open O_TTY_INIT 0 0 0x00080000 0 0 0 #
|
||||||
syscon compat O_LARGEFILE 0 0 0 0 0 0 #
|
syscon compat O_LARGEFILE 0100000 0 0 0 0 0 #
|
||||||
|
|
||||||
# mmap() flags
|
# mmap() flags
|
||||||
# the revolutionary praxis of malloc()
|
# the revolutionary praxis of malloc()
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
#include "libc/sysv/consts/syscon.internal.h"
|
||||||
.syscon compat,O_LARGEFILE,0,0,0,0,0,0
|
.syscon compat,O_LARGEFILE,0100000,0,0,0,0,0
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/flock.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -25,15 +28,12 @@
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
char testlib_enable_tmp_setup_teardown;
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
void SetUpOnce(void) {
|
|
||||||
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr", 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(fcntl_getfl, testRemembersAccessMode) {
|
TEST(fcntl_getfl, testRemembersAccessMode) {
|
||||||
int fd;
|
int fd;
|
||||||
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
||||||
|
@ -71,3 +71,149 @@ TEST(fcntl, getfd) {
|
||||||
ASSERT_SYS(0, 0, close(4));
|
ASSERT_SYS(0, 0, close(4));
|
||||||
ASSERT_SYS(0, 0, close(3));
|
ASSERT_SYS(0, 0, close(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnSig(int sig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(posixAdvisoryLocks, oneProcess_unlockedFromOwnPerspectiveHuh) {
|
||||||
|
struct flock lock;
|
||||||
|
ASSERT_SYS(0, 3, open("foo", O_RDWR | O_CREAT | O_TRUNC, 0644));
|
||||||
|
ASSERT_SYS(0, 5, write(3, "hello", 5));
|
||||||
|
|
||||||
|
// set lock
|
||||||
|
lock.l_type = F_WRLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 1;
|
||||||
|
lock.l_len = 3;
|
||||||
|
lock.l_pid = -2;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(3, F_SETLK, &lock));
|
||||||
|
EXPECT_EQ(F_WRLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(1, lock.l_start);
|
||||||
|
EXPECT_EQ(3, lock.l_len);
|
||||||
|
EXPECT_EQ(-2, lock.l_pid);
|
||||||
|
|
||||||
|
ASSERT_SYS(0, 4, open("foo", O_RDWR));
|
||||||
|
|
||||||
|
// try lock
|
||||||
|
lock.l_type = F_WRLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 0;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -1;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(4, F_SETLK, &lock));
|
||||||
|
EXPECT_EQ(F_WRLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(0, lock.l_start);
|
||||||
|
EXPECT_EQ(0, lock.l_len);
|
||||||
|
EXPECT_EQ(-1, lock.l_pid);
|
||||||
|
|
||||||
|
// get lock information
|
||||||
|
if (!IsWindows()) {
|
||||||
|
lock.l_type = F_RDLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 0;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -7;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(4, F_GETLK, &lock));
|
||||||
|
EXPECT_EQ(F_UNLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(0, lock.l_start);
|
||||||
|
EXPECT_EQ(0, lock.l_len);
|
||||||
|
EXPECT_EQ(-7, lock.l_pid); // doesn't change due to F_UNLCK
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_SYS(0, 0, close(4));
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(posixAdvisoryLocks, twoProcesses) {
|
||||||
|
if (IsWindows()) return; // due to signals
|
||||||
|
|
||||||
|
int ws, pid;
|
||||||
|
struct flock lock;
|
||||||
|
sigset_t ss, oldss;
|
||||||
|
struct sigaction oldsa;
|
||||||
|
struct sigaction sa = {.sa_handler = OnSig};
|
||||||
|
ASSERT_SYS(0, 0, sigemptyset(&ss));
|
||||||
|
ASSERT_SYS(0, 0, sigaddset(&ss, SIGUSR1));
|
||||||
|
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &ss, &oldss));
|
||||||
|
ASSERT_SYS(0, 0, sigdelset(&ss, SIGUSR1));
|
||||||
|
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &sa, &oldsa));
|
||||||
|
ASSERT_NE(-1, (pid = fork()));
|
||||||
|
if (!pid) {
|
||||||
|
ASSERT_SYS(0, 3, open("foo", O_RDWR | O_CREAT | O_TRUNC, 0644));
|
||||||
|
ASSERT_SYS(0, 5, write(3, "hello", 5));
|
||||||
|
lock.l_type = F_WRLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 1;
|
||||||
|
lock.l_len = 3;
|
||||||
|
lock.l_pid = -2;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(3, F_SETLK, &lock));
|
||||||
|
EXPECT_EQ(F_WRLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(1, lock.l_start);
|
||||||
|
EXPECT_EQ(3, lock.l_len);
|
||||||
|
EXPECT_EQ(-2, lock.l_pid);
|
||||||
|
ASSERT_SYS(0, 0, kill(getppid(), SIGUSR1));
|
||||||
|
ASSERT_SYS(EINTR, -1, sigsuspend(&ss));
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
ASSERT_SYS(EINTR, -1, sigsuspend(&ss));
|
||||||
|
ASSERT_SYS(0, 3, open("foo", O_RDWR));
|
||||||
|
|
||||||
|
// try lock
|
||||||
|
lock.l_type = F_RDLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 0;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -1;
|
||||||
|
ASSERT_SYS(EAGAIN, -1, fcntl(3, F_SETLK, &lock));
|
||||||
|
|
||||||
|
// get lock information
|
||||||
|
lock.l_type = F_RDLCK;
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_start = 0;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -1;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(3, F_GETLK, &lock));
|
||||||
|
EXPECT_EQ(F_WRLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(1, lock.l_start);
|
||||||
|
EXPECT_EQ(3, lock.l_len);
|
||||||
|
EXPECT_EQ(pid, lock.l_pid);
|
||||||
|
|
||||||
|
// get lock information
|
||||||
|
lock.l_type = F_RDLCK;
|
||||||
|
lock.l_whence = SEEK_END;
|
||||||
|
lock.l_start = -3;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -1;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(3, F_GETLK, &lock));
|
||||||
|
EXPECT_EQ(F_WRLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_SET, lock.l_whence);
|
||||||
|
EXPECT_EQ(1, lock.l_start);
|
||||||
|
EXPECT_EQ(3, lock.l_len);
|
||||||
|
EXPECT_EQ(pid, lock.l_pid);
|
||||||
|
|
||||||
|
// get lock information
|
||||||
|
lock.l_type = F_RDLCK;
|
||||||
|
lock.l_whence = SEEK_END;
|
||||||
|
lock.l_start = -1;
|
||||||
|
lock.l_len = 0;
|
||||||
|
lock.l_pid = -1;
|
||||||
|
ASSERT_SYS(0, 0, fcntl(3, F_GETLK, &lock));
|
||||||
|
EXPECT_EQ(F_UNLCK, lock.l_type);
|
||||||
|
EXPECT_EQ(SEEK_END, lock.l_whence);
|
||||||
|
EXPECT_EQ(-1, lock.l_start);
|
||||||
|
EXPECT_EQ(0, lock.l_len);
|
||||||
|
EXPECT_EQ(-1, lock.l_pid);
|
||||||
|
|
||||||
|
ASSERT_SYS(0, 0, kill(pid, SIGUSR1));
|
||||||
|
EXPECT_NE(-1, wait(&ws));
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
ASSERT_SYS(0, 0, sigaction(SIGUSR1, &oldsa, 0));
|
||||||
|
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &oldss, 0));
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,9 @@ o/$(MODE)/test/libc/calls/ioctl_siocgifconf_test.com.runs: \
|
||||||
o/$(MODE)/test/libc/calls/poll_test.com.runs: \
|
o/$(MODE)/test/libc/calls/poll_test.com.runs: \
|
||||||
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
|
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
|
||||||
|
|
||||||
|
o/$(MODE)/test/libc/calls/fcntl_test.com.runs: \
|
||||||
|
private .PLEDGE = stdio rpath wpath cpath fattr proc flock
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/calls
|
.PHONY: o/$(MODE)/test/libc/calls
|
||||||
o/$(MODE)/test/libc/calls: \
|
o/$(MODE)/test/libc/calls: \
|
||||||
$(TEST_LIBC_CALLS_BINS) \
|
$(TEST_LIBC_CALLS_BINS) \
|
||||||
|
|
75
third_party/lua/lunix.c
vendored
75
third_party/lua/lunix.c
vendored
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/bpf.h"
|
#include "libc/calls/struct/bpf.h"
|
||||||
#include "libc/calls/struct/dirent.h"
|
#include "libc/calls/struct/dirent.h"
|
||||||
|
#include "libc/calls/struct/flock.h"
|
||||||
#include "libc/calls/struct/itimerval.h"
|
#include "libc/calls/struct/itimerval.h"
|
||||||
#include "libc/calls/struct/rlimit.h"
|
#include "libc/calls/struct/rlimit.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
|
@ -704,27 +705,64 @@ static int LuaUnixWait(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.fcntl(fd:int, cmd:int[, arg:int])
|
// unix.fcntl(fd:int, cmd:int[, ...])
|
||||||
// ├─→ true, ...
|
// ├─→ ...
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixFcntl(lua_State *L) {
|
static int LuaUnixFcntl(lua_State *L) {
|
||||||
int olderr = errno;
|
struct flock lock;
|
||||||
|
int rc, fd, cmd, olderr = errno;
|
||||||
|
fd = luaL_checkinteger(L, 1);
|
||||||
|
cmd = luaL_checkinteger(L, 2);
|
||||||
|
if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||||
|
lock.l_type = luaL_optinteger(L, 3, F_RDLCK);
|
||||||
|
lock.l_start = luaL_optinteger(L, 4, 0);
|
||||||
|
lock.l_len = luaL_optinteger(L, 5, 0);
|
||||||
|
lock.l_whence = luaL_optinteger(L, 6, SEEK_SET);
|
||||||
|
}
|
||||||
|
if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||||
|
return SysretBool(L, "fcntl(F_SETLK*)", olderr, fcntl(fd, cmd, &lock));
|
||||||
|
} else if (cmd == F_GETLK) {
|
||||||
|
if (fcntl(fd, cmd, &lock) != -1) {
|
||||||
|
if (lock.l_type == F_UNLCK) {
|
||||||
|
lua_pushinteger(L, F_UNLCK);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushinteger(L, lock.l_type);
|
||||||
|
lua_pushinteger(L, lock.l_start);
|
||||||
|
lua_pushinteger(L, lock.l_len);
|
||||||
|
lua_pushinteger(L, lock.l_whence);
|
||||||
|
lua_pushinteger(L, lock.l_pid);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return LuaUnixSysretErrno(L, "fcntl(F_GETLK)", olderr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return SysretBool(L, "fcntl", olderr,
|
return SysretBool(L, "fcntl", olderr,
|
||||||
fcntl(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2),
|
fcntl(fd, cmd, luaL_optinteger(L, 3, 0)));
|
||||||
luaL_optinteger(L, 3, 0)));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.dup(oldfd:int[, newfd:int[, flags:int]])
|
// unix.dup(oldfd:int[, newfd:int[, flags:int[, lowest:int]]])
|
||||||
// ├─→ newfd:int
|
// ├─→ newfd:int
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixDup(lua_State *L) {
|
static int LuaUnixDup(lua_State *L) {
|
||||||
int rc, oldfd, newfd, flags, olderr;
|
int rc, oldfd, newfd, flags, lowno, olderr;
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
oldfd = luaL_checkinteger(L, 1);
|
oldfd = luaL_checkinteger(L, 1);
|
||||||
newfd = luaL_optinteger(L, 2, -1);
|
newfd = luaL_optinteger(L, 2, -1);
|
||||||
flags = luaL_optinteger(L, 3, 0);
|
flags = luaL_optinteger(L, 3, 0);
|
||||||
if (newfd == -1) {
|
lowno = luaL_optinteger(L, 4, 0);
|
||||||
|
if (newfd < 0) {
|
||||||
|
if (!flags && !lowno) {
|
||||||
rc = dup(oldfd);
|
rc = dup(oldfd);
|
||||||
|
} else if (!flags) {
|
||||||
|
rc = fcntl(oldfd, F_DUPFD, lowno);
|
||||||
|
} else if (flags == O_CLOEXEC) {
|
||||||
|
rc = fcntl(oldfd, F_DUPFD_CLOEXEC, lowno);
|
||||||
|
} else {
|
||||||
|
rc = einval();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = dup3(oldfd, newfd, flags);
|
rc = dup3(oldfd, newfd, flags);
|
||||||
}
|
}
|
||||||
|
@ -1444,15 +1482,27 @@ static int LuaUnixAccept(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.poll({[fd:int]=events:int, ...}[, timeoutms:int])
|
// unix.poll({[fd:int]=events:int, ...}[, timeoutms:int[, mask:unix.Sigset]])
|
||||||
// ├─→ {[fd:int]=revents:int, ...}
|
// ├─→ {[fd:int]=revents:int, ...}
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixPoll(lua_State *L) {
|
static int LuaUnixPoll(lua_State *L) {
|
||||||
size_t nfds;
|
size_t nfds;
|
||||||
|
struct sigset *mask;
|
||||||
|
struct timespec ts, *tsp;
|
||||||
struct pollfd *fds, *fds2;
|
struct pollfd *fds, *fds2;
|
||||||
int i, fd, events, timeoutms, olderr = errno;
|
int i, fd, events, olderr = errno;
|
||||||
timeoutms = luaL_optinteger(L, 2, -1);
|
|
||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
if (!lua_isnoneornil(L, 2)) {
|
||||||
|
ts = _timespec_frommillis(luaL_checkinteger(L, 2));
|
||||||
|
tsp = &ts;
|
||||||
|
} else {
|
||||||
|
tsp = 0;
|
||||||
|
}
|
||||||
|
if (!lua_isnoneornil(L, 3)) {
|
||||||
|
mask = luaL_checkudata(L, 3, "unix.Sigset");
|
||||||
|
} else {
|
||||||
|
mask = 0;
|
||||||
|
}
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
for (fds = 0, nfds = 0; lua_next(L, 1);) {
|
for (fds = 0, nfds = 0; lua_next(L, 1);) {
|
||||||
if (lua_isinteger(L, -2)) {
|
if (lua_isinteger(L, -2)) {
|
||||||
|
@ -1471,7 +1521,7 @@ static int LuaUnixPoll(lua_State *L) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
if ((events = poll(fds, nfds, timeoutms)) != -1) {
|
if ((events = ppoll(fds, nfds, tsp, mask)) != -1) {
|
||||||
lua_createtable(L, events, 0);
|
lua_createtable(L, events, 0);
|
||||||
for (i = 0; i < nfds; ++i) {
|
for (i = 0; i < nfds; ++i) {
|
||||||
if (fds[i].revents && fds[i].fd >= 0) {
|
if (fds[i].revents && fds[i].fd >= 0) {
|
||||||
|
@ -2703,6 +2753,7 @@ int LuaUnix(lua_State *L) {
|
||||||
LuaSetIntField(L, "F_WRLCK", F_WRLCK);
|
LuaSetIntField(L, "F_WRLCK", F_WRLCK);
|
||||||
LuaSetIntField(L, "F_SETLK", F_SETLK);
|
LuaSetIntField(L, "F_SETLK", F_SETLK);
|
||||||
LuaSetIntField(L, "F_SETLKW", F_SETLKW);
|
LuaSetIntField(L, "F_SETLKW", F_SETLKW);
|
||||||
|
LuaSetIntField(L, "F_GETLK", F_GETLK);
|
||||||
LuaSetIntField(L, "FD_CLOEXEC", FD_CLOEXEC);
|
LuaSetIntField(L, "FD_CLOEXEC", FD_CLOEXEC);
|
||||||
|
|
||||||
// access() mode
|
// access() mode
|
||||||
|
|
12
third_party/make/config.h
vendored
12
third_party/make/config.h
vendored
|
@ -507,21 +507,11 @@
|
||||||
#define MAKE_HOST "x86_64-cosmopolitan"
|
#define MAKE_HOST "x86_64-cosmopolitan"
|
||||||
|
|
||||||
/* Define to 1 to enable job server support in GNU make. */
|
/* Define to 1 to enable job server support in GNU make. */
|
||||||
/*
|
#define MAKE_JOBSERVER 1
|
||||||
* TODO(jart): Why does job server not work? We don't need it, since the
|
|
||||||
* last thing we'd ever want is a recursive make, however it
|
|
||||||
* would be nice to confirm it's not a bug in our libc impl.
|
|
||||||
*/
|
|
||||||
/* #define MAKE_JOBSERVER 1 */
|
|
||||||
|
|
||||||
/* Define to 1 to enable symbolic link timestamp checking. */
|
/* Define to 1 to enable symbolic link timestamp checking. */
|
||||||
#define MAKE_SYMLINKS 1
|
#define MAKE_SYMLINKS 1
|
||||||
|
|
||||||
/* Use GNU style printf and scanf. */
|
|
||||||
#ifndef __USE_MINGW_ANSI_STDIO
|
|
||||||
#define __USE_MINGW_ANSI_STDIO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define to 1 if the nlist n_name member is a pointer */
|
/* Define to 1 if the nlist n_name member is a pointer */
|
||||||
/* #undef N_NAME_POINTER */
|
/* #undef N_NAME_POINTER */
|
||||||
|
|
||||||
|
|
11
third_party/make/posixos.c
vendored
11
third_party/make/posixos.c
vendored
|
@ -16,6 +16,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "third_party/make/makeint.inc"
|
#include "third_party/make/makeint.inc"
|
||||||
/**/
|
/**/
|
||||||
|
#include "libc/sock/select.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
@ -231,17 +232,15 @@ unsigned int jobserver_acquire(int timeout) {
|
||||||
FD_SET(job_fds[0], &readfds);
|
FD_SET(job_fds[0], &readfds);
|
||||||
|
|
||||||
r = pselect(job_fds[0] + 1, &readfds, NULL, NULL, specp, &empty);
|
r = pselect(job_fds[0] + 1, &readfds, NULL, NULL, specp, &empty);
|
||||||
if (r < 0) switch (errno) {
|
if (r < 0)
|
||||||
case EINTR:
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
/* SIGCHLD will show up as an EINTR. */
|
/* SIGCHLD will show up as an EINTR. */
|
||||||
return 0;
|
return 0;
|
||||||
|
if (errno == EBADF)
|
||||||
case EBADF:
|
|
||||||
/* Someone closed the jobs pipe.
|
/* Someone closed the jobs pipe.
|
||||||
That shouldn't happen but if it does we're done. */
|
That shouldn't happen but if it does we're done. */
|
||||||
O(fatal, NILF, _("job server shut down"));
|
O(fatal, NILF, _("job server shut down"));
|
||||||
|
|
||||||
default:
|
|
||||||
pfatal_with_name(_("pselect jobs pipe"));
|
pfatal_with_name(_("pselect jobs pipe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,23 +195,13 @@
|
||||||
(or (file-name-directory
|
(or (file-name-directory
|
||||||
(file-relative-name this root))
|
(file-relative-name this root))
|
||||||
""))))
|
""))))
|
||||||
((eq kind 'run-win7)
|
|
||||||
(format
|
|
||||||
(cosmo-join
|
|
||||||
" && "
|
|
||||||
`("m=%s; f=o/$m/%s.com"
|
|
||||||
,(concat "make -j12 -O $f MODE=$m")
|
|
||||||
"scp $f $f.dbg win7:"
|
|
||||||
"ssh win7 ./%s.com"))
|
|
||||||
mode name (file-name-nondirectory name)))
|
|
||||||
((eq kind 'run-win10)
|
((eq kind 'run-win10)
|
||||||
(format
|
(format
|
||||||
(cosmo-join
|
(cosmo-join
|
||||||
" && "
|
" && "
|
||||||
`("m=%s; f=o/$m/%s.com"
|
`("m=%s; f=o/$m/%s.com"
|
||||||
,(concat "make -j12 -O $f MODE=$m")
|
,(concat "make -j12 -O $f MODE=$m")
|
||||||
"scp $f $f.dbg win10:"
|
"scp $f $f.dbg win10:; ssh win10 ./%s.com"))
|
||||||
"ssh win10 ./%s.com"))
|
|
||||||
mode name (file-name-nondirectory name)))
|
mode name (file-name-nondirectory name)))
|
||||||
((eq kind 'run-xnu)
|
((eq kind 'run-xnu)
|
||||||
(format
|
(format
|
||||||
|
@ -653,22 +643,6 @@
|
||||||
('t
|
('t
|
||||||
(error "cosmo-run: unknown major mode")))))))
|
(error "cosmo-run: unknown major mode")))))))
|
||||||
|
|
||||||
(defun cosmo-run-win7 (arg)
|
|
||||||
(interactive "P")
|
|
||||||
(let* ((this (or (buffer-file-name) dired-directory))
|
|
||||||
(proj (locate-dominating-file this "Makefile"))
|
|
||||||
(root (or proj default-directory))
|
|
||||||
(file (file-relative-name this root)))
|
|
||||||
(when root
|
|
||||||
(let ((default-directory root))
|
|
||||||
(save-buffer)
|
|
||||||
(cond ((memq major-mode '(c-mode c++-mode asm-mode fortran-mode))
|
|
||||||
(let* ((mode (cosmo--make-mode arg ""))
|
|
||||||
(compile-command (cosmo--compile-command this root 'run-win7 mode "" "" "")))
|
|
||||||
(compile compile-command)))
|
|
||||||
('t
|
|
||||||
(error "cosmo-run: unknown major mode")))))))
|
|
||||||
|
|
||||||
(defun cosmo-run-win10 (arg)
|
(defun cosmo-run-win10 (arg)
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let* ((this (or (buffer-file-name) dired-directory))
|
(let* ((this (or (buffer-file-name) dired-directory))
|
||||||
|
|
|
@ -2590,19 +2590,30 @@ UNIX MODULE
|
||||||
`EAGAIN` is returned if you've enforced a max number of
|
`EAGAIN` is returned if you've enforced a max number of
|
||||||
processes using `setrlimit(RLIMIT_NPROC)`.
|
processes using `setrlimit(RLIMIT_NPROC)`.
|
||||||
|
|
||||||
unix.dup(oldfd:int[, newfd:int[, flags:int]])
|
unix.dup(oldfd:int[, newfd:int[, flags:int[, lowest:int]]])
|
||||||
├─→ newfd:int
|
├─→ newfd:int
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
Duplicates file descriptor.
|
Duplicates file descriptor.
|
||||||
|
|
||||||
`newfd` defaults to the lowest number available file descriptor.
|
`newfd` may be specified to choose a specific number for the new
|
||||||
If the new number is specified and it's already open, then it'll
|
file descriptor. If it's already open, then the preexisting one will
|
||||||
be silently closed before the duplication happens.
|
be silently closed. `EINVAL` is returned if `newfd` equals `oldfd`.
|
||||||
|
|
||||||
`flags` can have `O_CLOEXEC` which means the returned file
|
`flags` can have `O_CLOEXEC` which means the returned file
|
||||||
descriptors will be automatically closed upon execve().
|
descriptors will be automatically closed upon execve().
|
||||||
|
|
||||||
|
`lowest` defaults to zero and defines the lowest numbered file
|
||||||
|
descriptor that's acceptable to use. If `newfd` is specified then
|
||||||
|
`lowest` is ignored. For example, if you wanted to duplicate
|
||||||
|
standard input, then:
|
||||||
|
|
||||||
|
stdin2 = assert(unix.dup(0, nil, unix.O_CLOEXEC, 3))
|
||||||
|
|
||||||
|
Will ensure that, in the rare event standard output or standard
|
||||||
|
error are closed, you won't accidentally duplicate standard input to
|
||||||
|
those numbers.
|
||||||
|
|
||||||
unix.pipe([flags:int])
|
unix.pipe([flags:int])
|
||||||
├─→ reader:int, writer:int
|
├─→ reader:int, writer:int
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
@ -2992,18 +3003,147 @@ UNIX MODULE
|
||||||
|
|
||||||
`path` is the file or directory path you wish to destroy.
|
`path` is the file or directory path you wish to destroy.
|
||||||
|
|
||||||
unix.fcntl(fd:int, cmd:int, ...)
|
unix.fcntl(fd:int, unix.F_GETFD)
|
||||||
├─→ ...
|
├─→ flags:int
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
Manipulates file descriptor.
|
Returns file descriptor flags.
|
||||||
|
|
||||||
Setting `cmd` to `F_GETFD`, `F_SETFD`, `F_GETFL` or `F_SETFL`
|
The returned `flags` may include any of:
|
||||||
lets you query and/or change the status of file descriptors. For
|
|
||||||
example, it's possible using this to change `FD_CLOEXEC`.
|
|
||||||
|
|
||||||
[work in progress] POSIX advisory locks can be controlled by setting
|
- `unix.FD_CLOEXEC` if `fd` was opened with `unix.O_CLOEXEC`.
|
||||||
`cmd` to `F_UNLCK`, `F_RDLCK`, `F_WRLCK`, `F_SETLK`, or `F_SETLKW`.
|
|
||||||
|
Returns `EBADF` if `fd` isn't open.
|
||||||
|
|
||||||
|
unix.fcntl(fd:int, unix.F_SETFD, flags:int)
|
||||||
|
├─→ true
|
||||||
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
Sets file descriptor flags.
|
||||||
|
|
||||||
|
`flags` may include any of:
|
||||||
|
|
||||||
|
- `unix.FD_CLOEXEC` to re-open `fd` with `unix.O_CLOEXEC`.
|
||||||
|
|
||||||
|
Returns `EBADF` if `fd` isn't open.
|
||||||
|
|
||||||
|
unix.fcntl(fd:int, unix.F_GETFL)
|
||||||
|
├─→ flags:int
|
||||||
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
Returns file descriptor status flags.
|
||||||
|
|
||||||
|
`flags & unix.O_ACCMODE` includes one of:
|
||||||
|
|
||||||
|
- `O_RDONLY`
|
||||||
|
- `O_WRONLY`
|
||||||
|
- `O_RDWR`
|
||||||
|
|
||||||
|
Examples of values `flags & ~unix.O_ACCMODE` may include:
|
||||||
|
|
||||||
|
- `O_NONBLOCK`
|
||||||
|
- `O_APPEND`
|
||||||
|
- `O_SYNC`
|
||||||
|
- `O_ASYNC`
|
||||||
|
- `O_NOATIME` on Linux
|
||||||
|
- `O_RANDOM` on Windows
|
||||||
|
- `O_SEQUENTIAL` on Windows
|
||||||
|
- `O_DIRECT` on Linux/FreeBSD/NetBSD/Windows
|
||||||
|
|
||||||
|
Examples of values `flags & ~unix.O_ACCMODE` won't include:
|
||||||
|
|
||||||
|
- `O_CREAT`
|
||||||
|
- `O_TRUNC`
|
||||||
|
- `O_EXCL`
|
||||||
|
- `O_NOCTTY`
|
||||||
|
|
||||||
|
Returns `EBADF` if `fd` isn't open.
|
||||||
|
|
||||||
|
unix.fcntl(fd:int, unix.F_SETFL, flags:int)
|
||||||
|
├─→ true
|
||||||
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
Changes file descriptor status flags.
|
||||||
|
|
||||||
|
Examples of values `flags` may include:
|
||||||
|
|
||||||
|
- `O_NONBLOCK`
|
||||||
|
- `O_APPEND`
|
||||||
|
- `O_SYNC`
|
||||||
|
- `O_ASYNC`
|
||||||
|
- `O_NOATIME` on Linux
|
||||||
|
- `O_RANDOM` on Windows
|
||||||
|
- `O_SEQUENTIAL` on Windows
|
||||||
|
- `O_DIRECT` on Linux/FreeBSD/NetBSD/Windows
|
||||||
|
|
||||||
|
These values should be ignored:
|
||||||
|
|
||||||
|
- `O_RDONLY`, `O_WRONLY`, `O_RDWR`
|
||||||
|
- `O_CREAT`, `O_TRUNC`, `O_EXCL`
|
||||||
|
- `O_NOCTTY`
|
||||||
|
|
||||||
|
Returns `EBADF` if `fd` isn't open.
|
||||||
|
|
||||||
|
unix.fcntl(fd:int, unix.F_SETLK[, type[, start[, len[, whence]]]])
|
||||||
|
unix.fcntl(fd:int, unix.F_SETLKW[, type[, start[, len[, whence]]]])
|
||||||
|
├─→ true
|
||||||
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
Acquires lock on file interval.
|
||||||
|
|
||||||
|
POSIX Advisory Locks allow multiple processes to leave voluntary
|
||||||
|
hints to each other about which portions of a file they're using.
|
||||||
|
|
||||||
|
The command may be:
|
||||||
|
|
||||||
|
- `F_SETLK` to acquire lock if possible
|
||||||
|
- `F_SETLKW` to wait for lock if necessary
|
||||||
|
|
||||||
|
`fd` is file descriptor of open() file.
|
||||||
|
|
||||||
|
`type` may be one of:
|
||||||
|
|
||||||
|
- `F_RDLCK` for read lock (default)
|
||||||
|
- `F_WRLCK` for read/write lock
|
||||||
|
- `F_UNLCK` to unlock
|
||||||
|
|
||||||
|
`start` is 0-indexed byte offset into file. The default is zero.
|
||||||
|
|
||||||
|
`len` is byte length of interval. Zero is the default and it means
|
||||||
|
until the end of the file.
|
||||||
|
|
||||||
|
`whence` may be one of:
|
||||||
|
|
||||||
|
- `SEEK_SET` start from beginning (default)
|
||||||
|
- `SEEK_CUR` start from current position
|
||||||
|
- `SEEK_END` start from end
|
||||||
|
|
||||||
|
Returns `EAGAIN` if lock couldn't be acquired. POSIX says this
|
||||||
|
theoretically could also be `EACCES` but we haven't seen this
|
||||||
|
behavior on any of our supported platforms.
|
||||||
|
|
||||||
|
Returns `EBADF` if `fd` wasn't open.
|
||||||
|
|
||||||
|
unix.fcntl(fd:int, unix.F_GETLK[, type[, start[, len[, whence]]]])
|
||||||
|
├─→ unix.F_UNLCK
|
||||||
|
├─→ type, start, len, whence, pid
|
||||||
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
Acquires information about POSIX advisory lock on file.
|
||||||
|
|
||||||
|
This function accepts the same parameters as fcntl(F_SETLK) and
|
||||||
|
tells you if the lock acquisition would be successful for a given
|
||||||
|
range of bytes. If locking would have succeeded, then F_UNLCK is
|
||||||
|
returned. If the lock would not have succeeded, then information
|
||||||
|
about a conflicting lock is returned.
|
||||||
|
|
||||||
|
Returned `type` may be `F_RDLCK` or `F_WRLCK`.
|
||||||
|
|
||||||
|
Returned `pid` is the process id of the current lock owner.
|
||||||
|
|
||||||
|
This function is currently not supported on Windows.
|
||||||
|
|
||||||
|
Returns `EBADF` if `fd` wasn't open.
|
||||||
|
|
||||||
unix.getsid(pid:int)
|
unix.getsid(pid:int)
|
||||||
├─→ sid:int
|
├─→ sid:int
|
||||||
|
@ -3477,7 +3617,7 @@ UNIX MODULE
|
||||||
`OnServerListen` hook to enable SYN saving in your Redbean. When the
|
`OnServerListen` hook to enable SYN saving in your Redbean. When the
|
||||||
`TCP_SAVE_SYN` option isn't used, this may return empty string.
|
`TCP_SAVE_SYN` option isn't used, this may return empty string.
|
||||||
|
|
||||||
unix.poll({[fd:int]=events:int, ...}[, timeoutms:int])
|
unix.poll({[fd:int]=events:int, ...}[, timeoutms:int[, mask:unix.Sigset]])
|
||||||
├─→ {[fd:int]=revents:int, ...}
|
├─→ {[fd:int]=revents:int, ...}
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
@ -3504,9 +3644,25 @@ UNIX MODULE
|
||||||
peer closed its end of the channel.
|
peer closed its end of the channel.
|
||||||
- `POLLNVAL` (revents): Invalid request.
|
- `POLLNVAL` (revents): Invalid request.
|
||||||
|
|
||||||
`timeoutms` is the number of milliseconds to block. If this is set to
|
`timeoutms` is the number of milliseconds to block. The default is
|
||||||
-1 then that means block as long as it takes until there's an event
|
-1 which means block indefinitely until there's an event or an
|
||||||
or an interrupt. If the timeout expires, an empty table is returned.
|
interrupt. If the timeout elapses without any such events, an empty
|
||||||
|
table is returned. A timeout of zero means non-blocking.
|
||||||
|
|
||||||
|
`mask` serves the purpose of enabling poll to listen for both file
|
||||||
|
descriptor events and signals. It's equivalent to saying:
|
||||||
|
|
||||||
|
oldmask = unix.sigprocmask(unix.SIG_SETMASK, mask);
|
||||||
|
unix.poll(fds, timeout);
|
||||||
|
unix.sigprocmask(unix.SIG_SETMASK, oldmask);
|
||||||
|
|
||||||
|
Except it'll happen atomically on supported platforms. The only
|
||||||
|
exceptions are MacOS and NetBSD where this behavior is simulated by
|
||||||
|
the polyfill. Atomicity is helpful for unit testing signal behavior.
|
||||||
|
|
||||||
|
`EINTR` is returned if the kernel decided to deliver a signal to a
|
||||||
|
signal handler instead during your call. This is a @norestart system
|
||||||
|
call that always returns `EINTR` even if `SA_RESTART` is in play.
|
||||||
|
|
||||||
unix.gethostname()
|
unix.gethostname()
|
||||||
├─→ host:str
|
├─→ host:str
|
||||||
|
|
Loading…
Reference in a new issue