mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
|
||||
O_NOATIME | O_NONBLOCK);
|
||||
return g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||
// 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;
|
||||
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);
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
|
|
|
@ -74,14 +74,12 @@ void flock2cosmo(uintptr_t memory) {
|
|||
l_pid = u->linux.l_pid;
|
||||
l_type = u->linux.l_type;
|
||||
l_whence = u->linux.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsXnu()) {
|
||||
l_start = u->xnu.l_start;
|
||||
l_len = u->xnu.l_len;
|
||||
l_pid = u->xnu.l_pid;
|
||||
l_type = u->xnu.l_type;
|
||||
l_whence = u->xnu.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsFreebsd()) {
|
||||
l_start = u->freebsd.l_start;
|
||||
l_len = u->freebsd.l_len;
|
||||
|
@ -89,20 +87,19 @@ void flock2cosmo(uintptr_t memory) {
|
|||
l_type = u->freebsd.l_type;
|
||||
l_whence = u->freebsd.l_whence;
|
||||
l_sysid = u->freebsd.l_sysid;
|
||||
u->cosmo.l_sysid = l_sysid;
|
||||
} else if (IsOpenbsd()) {
|
||||
l_start = u->openbsd.l_start;
|
||||
l_len = u->openbsd.l_len;
|
||||
l_pid = u->openbsd.l_pid;
|
||||
l_type = u->openbsd.l_type;
|
||||
l_whence = u->openbsd.l_whence;
|
||||
l_sysid = 0;
|
||||
} else if (IsNetbsd()) {
|
||||
l_start = u->netbsd.l_start;
|
||||
l_len = u->netbsd.l_len;
|
||||
l_pid = u->netbsd.l_pid;
|
||||
l_type = u->netbsd.l_type;
|
||||
l_whence = u->netbsd.l_whence;
|
||||
l_sysid = 0;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -111,7 +108,6 @@ void flock2cosmo(uintptr_t memory) {
|
|||
u->cosmo.l_pid = l_pid;
|
||||
u->cosmo.l_type = l_type;
|
||||
u->cosmo.l_whence = l_whence;
|
||||
u->cosmo.l_sysid = l_sysid;
|
||||
}
|
||||
|
||||
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];
|
||||
int pipeindices[ARRAYLEN(pipefds)];
|
||||
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
|
||||
if (sigmask && __sig_mask(SIG_SETMASK, sigmask, &oldmask)) return -1;
|
||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
||||
if (sigmask) {
|
||||
__sig_mask(SIG_SETMASK, sigmask, &oldmask);
|
||||
}
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
rc = eintr();
|
||||
goto ReturnPath;
|
||||
}
|
||||
|
||||
// do the planning
|
||||
// we need to read static variables
|
||||
// we might need to spawn threads and open pipes
|
||||
__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 (__isfdopen(fds[i].fd)) {
|
||||
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;
|
||||
} else {
|
||||
// too many socket fds
|
||||
failed = enomem();
|
||||
rc = enomem();
|
||||
break;
|
||||
}
|
||||
} else if (pn < ARRAYLEN(pipefds)) {
|
||||
|
@ -109,7 +114,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
++pn;
|
||||
} else {
|
||||
// too many non-socket fds
|
||||
failed = enomem();
|
||||
rc = enomem();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -117,9 +122,9 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
|
|||
}
|
||||
}
|
||||
__fds_unlock();
|
||||
if (failed) {
|
||||
if (rc) {
|
||||
// failed to create a polling solution
|
||||
return failed;
|
||||
goto ReturnPath;
|
||||
}
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
||||
return __winsockerr();
|
||||
rc = __winsockerr();
|
||||
goto ReturnPath;
|
||||
}
|
||||
*ms -= waitfor;
|
||||
} 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
|
||||
// checking for signal delivery interrupts, along the way
|
||||
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
|
||||
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_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
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_sysid; /* remote system id or zero for local */
|
||||
};
|
||||
|
|
|
@ -61,6 +61,7 @@ kOpenFlags:
|
|||
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
||||
.e O_COMPRESSED,"COMPRESSED" // windows
|
||||
.e O_INDEXED,"INDEXED" // windows
|
||||
.e O_LARGEFILE,"LARGEFILE" //
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kOpenFlags,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -52,7 +52,7 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|||
struct timeval tv, *tvp;
|
||||
struct timespec ts, *tsp;
|
||||
struct {
|
||||
sigset_t *s;
|
||||
const sigset_t *s;
|
||||
size_t n;
|
||||
} ss;
|
||||
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_EXLOCK 0 0x00000020 0x00000020 0x00000020 0x00000020 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
|
||||
# the revolutionary praxis of malloc()
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -25,15 +28,12 @@
|
|||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr", 0));
|
||||
}
|
||||
|
||||
TEST(fcntl_getfl, testRemembersAccessMode) {
|
||||
int fd;
|
||||
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(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: \
|
||||
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
|
||||
o/$(MODE)/test/libc/calls: \
|
||||
$(TEST_LIBC_CALLS_BINS) \
|
||||
|
|
79
third_party/lua/lunix.c
vendored
79
third_party/lua/lunix.c
vendored
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/bpf.h"
|
||||
#include "libc/calls/struct/dirent.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/rlimit.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])
|
||||
// ├─→ true, ...
|
||||
// unix.fcntl(fd:int, cmd:int[, ...])
|
||||
// ├─→ ...
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixFcntl(lua_State *L) {
|
||||
int olderr = errno;
|
||||
return SysretBool(L, "fcntl", olderr,
|
||||
fcntl(luaL_checkinteger(L, 1), luaL_checkinteger(L, 2),
|
||||
luaL_optinteger(L, 3, 0)));
|
||||
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,
|
||||
fcntl(fd, cmd, 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
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixDup(lua_State *L) {
|
||||
int rc, oldfd, newfd, flags, olderr;
|
||||
int rc, oldfd, newfd, flags, lowno, olderr;
|
||||
olderr = errno;
|
||||
oldfd = luaL_checkinteger(L, 1);
|
||||
newfd = luaL_optinteger(L, 2, -1);
|
||||
flags = luaL_optinteger(L, 3, 0);
|
||||
if (newfd == -1) {
|
||||
rc = dup(oldfd);
|
||||
lowno = luaL_optinteger(L, 4, 0);
|
||||
if (newfd < 0) {
|
||||
if (!flags && !lowno) {
|
||||
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 {
|
||||
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, ...}
|
||||
// └─→ nil, unix.Errno
|
||||
static int LuaUnixPoll(lua_State *L) {
|
||||
size_t nfds;
|
||||
struct sigset *mask;
|
||||
struct timespec ts, *tsp;
|
||||
struct pollfd *fds, *fds2;
|
||||
int i, fd, events, timeoutms, olderr = errno;
|
||||
timeoutms = luaL_optinteger(L, 2, -1);
|
||||
int i, fd, events, olderr = errno;
|
||||
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);
|
||||
for (fds = 0, nfds = 0; lua_next(L, 1);) {
|
||||
if (lua_isinteger(L, -2)) {
|
||||
|
@ -1471,7 +1521,7 @@ static int LuaUnixPoll(lua_State *L) {
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
olderr = errno;
|
||||
if ((events = poll(fds, nfds, timeoutms)) != -1) {
|
||||
if ((events = ppoll(fds, nfds, tsp, mask)) != -1) {
|
||||
lua_createtable(L, events, 0);
|
||||
for (i = 0; i < nfds; ++i) {
|
||||
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_SETLK", F_SETLK);
|
||||
LuaSetIntField(L, "F_SETLKW", F_SETLKW);
|
||||
LuaSetIntField(L, "F_GETLK", F_GETLK);
|
||||
LuaSetIntField(L, "FD_CLOEXEC", FD_CLOEXEC);
|
||||
|
||||
// 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 to 1 to enable job server support in GNU make. */
|
||||
/*
|
||||
* 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 MAKE_JOBSERVER 1
|
||||
|
||||
/* Define to 1 to enable symbolic link timestamp checking. */
|
||||
#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 */
|
||||
/* #undef N_NAME_POINTER */
|
||||
|
||||
|
|
13
third_party/make/posixos.c
vendored
13
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 "libc/sock/select.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
@ -231,18 +232,16 @@ unsigned int jobserver_acquire(int timeout) {
|
|||
FD_SET(job_fds[0], &readfds);
|
||||
|
||||
r = pselect(job_fds[0] + 1, &readfds, NULL, NULL, specp, &empty);
|
||||
if (r < 0) switch (errno) {
|
||||
case EINTR:
|
||||
if (r < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
/* SIGCHLD will show up as an EINTR. */
|
||||
return 0;
|
||||
|
||||
case EBADF:
|
||||
if (errno == EBADF)
|
||||
/* Someone closed the jobs pipe.
|
||||
That shouldn't happen but if it does we're done. */
|
||||
O(fatal, NILF, _("job server shut down"));
|
||||
|
||||
default:
|
||||
pfatal_with_name(_("pselect jobs pipe"));
|
||||
pfatal_with_name(_("pselect jobs pipe"));
|
||||
}
|
||||
|
||||
if (r == 0) /* Timeout. */
|
||||
|
|
|
@ -195,23 +195,13 @@
|
|||
(or (file-name-directory
|
||||
(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)
|
||||
(format
|
||||
(cosmo-join
|
||||
" && "
|
||||
`("m=%s; f=o/$m/%s.com"
|
||||
,(concat "make -j12 -O $f MODE=$m")
|
||||
"scp $f $f.dbg win10:"
|
||||
"ssh win10 ./%s.com"))
|
||||
"scp $f $f.dbg win10:; ssh win10 ./%s.com"))
|
||||
mode name (file-name-nondirectory name)))
|
||||
((eq kind 'run-xnu)
|
||||
(format
|
||||
|
@ -653,22 +643,6 @@
|
|||
('t
|
||||
(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)
|
||||
(interactive "P")
|
||||
(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
|
||||
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
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
Duplicates file descriptor.
|
||||
|
||||
`newfd` defaults to the lowest number available file descriptor.
|
||||
If the new number is specified and it's already open, then it'll
|
||||
be silently closed before the duplication happens.
|
||||
`newfd` may be specified to choose a specific number for the new
|
||||
file descriptor. If it's already open, then the preexisting one will
|
||||
be silently closed. `EINVAL` is returned if `newfd` equals `oldfd`.
|
||||
|
||||
`flags` can have `O_CLOEXEC` which means the returned file
|
||||
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])
|
||||
├─→ reader:int, writer:int
|
||||
└─→ nil, unix.Errno
|
||||
|
@ -2992,18 +3003,147 @@ UNIX MODULE
|
|||
|
||||
`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
|
||||
|
||||
Manipulates file descriptor.
|
||||
Returns file descriptor flags.
|
||||
|
||||
Setting `cmd` to `F_GETFD`, `F_SETFD`, `F_GETFL` or `F_SETFL`
|
||||
lets you query and/or change the status of file descriptors. For
|
||||
example, it's possible using this to change `FD_CLOEXEC`.
|
||||
The returned `flags` may include any of:
|
||||
|
||||
[work in progress] POSIX advisory locks can be controlled by setting
|
||||
`cmd` to `F_UNLCK`, `F_RDLCK`, `F_WRLCK`, `F_SETLK`, or `F_SETLKW`.
|
||||
- `unix.FD_CLOEXEC` if `fd` was opened with `unix.O_CLOEXEC`.
|
||||
|
||||
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)
|
||||
├─→ sid:int
|
||||
|
@ -3477,7 +3617,7 @@ UNIX MODULE
|
|||
`OnServerListen` hook to enable SYN saving in your Redbean. When the
|
||||
`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, ...}
|
||||
└─→ nil, unix.Errno
|
||||
|
||||
|
@ -3504,9 +3644,25 @@ UNIX MODULE
|
|||
peer closed its end of the channel.
|
||||
- `POLLNVAL` (revents): Invalid request.
|
||||
|
||||
`timeoutms` is the number of milliseconds to block. If this is set to
|
||||
-1 then that means block as long as it takes until there's an event
|
||||
or an interrupt. If the timeout expires, an empty table is returned.
|
||||
`timeoutms` is the number of milliseconds to block. The default is
|
||||
-1 which means block indefinitely until there's an event or an
|
||||
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()
|
||||
├─→ host:str
|
||||
|
|
Loading…
Reference in a new issue