Make important improvements

- Fix preadv() and pwritev() for old distros
- Introduce _npassert() and _unassert() macros
- Prove that file locks work properly on Windows
- Support fcntl(F_DUPFD_CLOEXEC) on more systems
This commit is contained in:
Justine Tunney 2022-09-14 21:29:50 -07:00
parent 1ad2f530f9
commit 3f49889841
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
130 changed files with 1225 additions and 431 deletions

View file

@ -152,6 +152,10 @@ CONFIG_CCFLAGS += \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
PYFLAGS += \
@ -180,6 +184,10 @@ CONFIG_CPPFLAGS += \
-DSUPPORT_VECTOR=1
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@ -212,6 +220,10 @@ CONFIG_CPPFLAGS += \
-DSUPPORT_VECTOR=113
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
@ -249,6 +261,10 @@ CONFIG_CCFLAGS += \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
endif
@ -278,6 +294,10 @@ CONFIG_CCFLAGS += \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
-S
TARGET_ARCH ?= \
-msse3
endif

56
examples/clock_getres.c Normal file
View file

@ -0,0 +1,56 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/struct/timespec.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
int n;
int shown[64];
void show(int clock) {
int i;
struct timespec ts;
if (clock == 127) return;
for (i = 0; i < n; ++i) {
if (shown[i] == clock) {
return;
}
}
shown[n++] = clock;
if (clock_getres(clock, &ts) != -1) {
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
} else {
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
}
}
int main(int argc, char *argv[]) {
show(CLOCK_REALTIME);
show(CLOCK_REALTIME_FAST);
show(CLOCK_REALTIME_PRECISE);
show(CLOCK_MONOTONIC);
show(CLOCK_MONOTONIC_RAW);
show(CLOCK_MONOTONIC_FAST);
show(CLOCK_MONOTONIC_PRECISE);
show(CLOCK_PROCESS_CPUTIME_ID);
show(CLOCK_THREAD_CPUTIME_ID);
show(CLOCK_PROF);
show(CLOCK_BOOTTIME);
show(CLOCK_REALTIME_ALARM);
show(CLOCK_BOOTTIME_ALARM);
show(CLOCK_TAI);
show(CLOCK_UPTIME);
show(CLOCK_UPTIME_PRECISE);
show(CLOCK_UPTIME_FAST);
show(CLOCK_SECOND);
}

View file

@ -7,16 +7,29 @@ extern bool __assert_disable;
void __assert_fail(const char *, const char *, int) hidden relegated;
#ifdef NDEBUG
#define assert(EXPR) ((void)0)
#define assert(x) ((void)0)
#else
#define assert(EXPR) \
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__), 0)))
#endif
#ifndef __cplusplus
#define static_assert _Static_assert
#endif
#define _unassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
unreachable; \
} \
} while (0)
#define _npassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
notpossible; \
} \
} while (0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ASSERT_H_ */

View file

@ -26,35 +26,36 @@
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_chdir_nt(const char *path) {
textwindows int sys_chdir_nt_impl(char16_t path[hasatleast PATH_MAX],
uint32_t len) {
uint32_t n;
int e, ms, err, len;
char16_t path16[PATH_MAX], var[4];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
if (len && path16[len - 1] != u'\\') {
int e, ms, err;
char16_t var[4];
if (len && path[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong();
path16[len + 0] = u'\\';
path16[len + 1] = u'\0';
path[len + 0] = u'\\';
path[len + 1] = u'\0';
}
/*
* chdir() seems flaky on windows 7
* in a similar way to rmdir() sigh
*/
for (err = errno, ms = 1;; ms *= 2) {
if (SetCurrentDirectory(path16)) {
if (SetCurrentDirectory(path)) {
/*
* Now we need to set a magic environment variable.
*/
if ((n = GetCurrentDirectory(ARRAYLEN(path16), path16))) {
if (n < ARRAYLEN(path16)) {
if (!((path16[0] == '/' && path16[1] == '/') ||
(path16[0] == '\\' && path16[1] == '\\'))) {
if ((n = GetCurrentDirectory(PATH_MAX, path))) {
if (n < PATH_MAX) {
if (!((path[0] == '/' && path[1] == '/') ||
(path[0] == '\\' && path[1] == '\\'))) {
var[0] = '=';
var[1] = path16[0];
var[1] = path[0];
var[2] = ':';
var[3] = 0;
if (!SetEnvironmentVariable(var, path16)) {
if (!SetEnvironmentVariable(var, path)) {
return __winerr();
}
}
@ -77,5 +78,13 @@ textwindows int sys_chdir_nt(const char *path) {
}
}
}
return __fix_enotdir(-1, path16);
return __fix_enotdir(-1, path);
}
textwindows int sys_chdir_nt(const char *path) {
int len;
char16_t path16[PATH_MAX];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (!len) return enoent();
return sys_chdir_nt_impl(path16, len);
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
@ -32,10 +33,9 @@
*/
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t rc, proc, handle;
// validate the api usage
if (oldfd < 0) return ebadf();
if (flags & ~O_CLOEXEC) return einval();
_unassert(oldfd >= 0);
_unassert(newfd >= -1);
_unassert(!(flags & ~O_CLOEXEC));
__fds_lock();

View file

@ -16,41 +16,52 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
#define F_DUP2FD 10
#define F_DUP2FD_CLOEXEC 18
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
static bool once;
static bool demodernize;
int olderr, how, fd;
if (!once) {
olderr = errno;
fd = __sys_dup3(oldfd, newfd, flags);
if (fd == -1 && errno == ENOSYS) {
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
demodernize = true;
once = true;
errno = olderr;
} else {
once = true;
return fd;
}
} else if (!demodernize) {
return __sys_dup3(oldfd, newfd, flags);
static struct Dup3 {
pthread_once_t once;
bool demodernize;
} g_dup3;
static void sys_dup3_test(void) {
int e = errno;
__sys_dup3(-1, -1, 0);
if ((g_dup3.demodernize = errno == ENOSYS)) {
STRACE("demodernizing %s() due to %s", "dup3", "ENOSYS");
}
if (oldfd == newfd) return einval();
if (flags & ~O_CLOEXEC) return einval();
errno = e;
}
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
int how;
_unassert(oldfd >= 0);
_unassert(newfd >= 0);
_unassert(!(flags & ~O_CLOEXEC));
if (IsFreebsd()) {
how = flags & O_CLOEXEC ? F_DUP2FD_CLOEXEC : F_DUP2FD;
if (flags & O_CLOEXEC) {
how = F_DUP2FD_CLOEXEC;
} else {
how = F_DUP2FD;
}
return __sys_fcntl(oldfd, how, newfd);
}
pthread_once(&g_dup3.once, sys_dup3_test);
if (!g_dup3.demodernize) {
return __sys_dup3(oldfd, newfd, flags);
} else {
return __fixupnewfd(sys_dup2(oldfd, newfd), flags);
}

View file

@ -18,10 +18,11 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
@ -46,14 +47,14 @@
*/
int dup3(int oldfd, int newfd, int flags) {
int rc;
if (__isfdkind(oldfd, kFdZip)) {
if (oldfd == newfd || (flags & ~O_CLOEXEC)) {
rc = einval(); // NetBSD doesn't do this
} else if (oldfd < 0 || newfd < 0) {
rc = ebadf();
} else if (__isfdkind(oldfd, kFdZip)) {
rc = eopnotsupp();
} else if (oldfd == newfd) {
rc = einval();
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
} else if (newfd < 0) {
rc = ebadf();
} else {
rc = sys_dup_nt(oldfd, newfd, flags, -1);
}

View file

@ -23,20 +23,12 @@
#include "libc/nt/files.h"
#include "libc/sysv/errfuns.h"
int sys_chdir_nt_impl(char16_t[hasatleast PATH_MAX], uint32_t);
textwindows int sys_fchdir_nt(int dirfd) {
uint32_t len;
char16_t dir[PATH_MAX];
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos);
if (len + 1 + 1 > ARRAYLEN(dir)) return enametoolong();
if (dir[len - 1] != u'\\') {
dir[len + 0] = u'\\';
dir[len + 1] = u'\0';
}
if (SetCurrentDirectory(dir)) {
return 0;
} else {
return __winerr();
}
return sys_chdir_nt_impl(
dir, GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
kNtFileNameNormalized | kNtVolumeNameDos));
}

View file

@ -24,42 +24,47 @@
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
#include "libc/errno.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/macros.internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/intrin/weaken.h"
#include "libc/log/backtrace.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
bool __force_sqlite_to_work_until_we_can_fix_it;
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
if (start < 0) return einval();
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
}
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
int e;
struct flock *l;
uint32_t flags, err;
struct NtOverlapped ov;
int64_t pos, off, len, size;
struct NtByHandleFileInformation info;
if (!GetFileInformationByHandle(f->handle, &info)) return __winerr();
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) return __winerr();
if (!GetFileInformationByHandle(f->handle, &info)) {
return __winerr();
}
pos = 0;
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
return __winerr();
}
l = (struct flock *)arg;
len = l->l_len;
off = l->l_start;
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
switch (l->l_whence) {
case SEEK_SET:
break;
@ -72,37 +77,60 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
default:
return einval();
}
if (!len) len = size - off;
if (off < 0 || len < 0) return einval();
_offset2overlap(f->handle, off, &ov);
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
flags = 0;
if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately;
/* TODO: How can we make SQLite locks on Windows to work? */
/* if (l->l_type == F_WRLCK) flags |= kNtLockfileExclusiveLock; */
if (LockFileEx(f->handle, flags, 0, len, len >> 32, &ov)) {
return 0;
} else {
err = GetLastError();
if (err == kNtErrorLockViolation) err = EAGAIN;
errno = err;
return -1;
}
} else if (l->l_type == F_UNLCK) {
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
return 0;
} else {
err = GetLastError();
if (err == kNtErrorNotLocked) {
return 0;
} else {
errno = err;
return -1;
}
}
} else {
if (!len) {
len = size - off;
}
if (off < 0 || len < 0) {
return einval();
}
bool32 ok;
struct NtOverlapped ov = {.hEvent = f->handle,
.Pointer = (void *)(uintptr_t)off};
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
flags = 0;
if (cmd != F_SETLKW) {
flags |= kNtLockfileFailImmediately;
}
if (l->l_type == F_WRLCK) {
flags |= kNtLockfileExclusiveLock;
}
ok = LockFileEx(f->handle, flags, 0, len, len >> 32, &ov);
if (cmd == F_GETLK) {
if (ok) {
l->l_type = F_UNLCK;
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
notpossible;
}
} else {
l->l_pid = -1;
ok = true;
}
}
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
return 0;
} else {
return -1;
}
}
if (l->l_type == F_UNLCK) {
if (cmd == F_GETLK) return einval();
e = errno;
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
return 0;
} else if (errno == ENOLCK) {
errno = e;
return 0;
} else {
return 0;
}
}
return einval();
}
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {

View file

@ -20,12 +20,14 @@
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
int rc;
int e, rc;
bool islock;
if ((islock = cmd == F_GETLK || //
cmd == F_SETLK || //
@ -37,9 +39,13 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
}
cosmo2flock(arg);
}
e = errno;
rc = __sys_fcntl(fd, cmd, arg);
if (islock) {
flock2cosmo(arg);
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
errno = e;
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
}
return rc;
}

View file

@ -37,11 +37,9 @@
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
*
* This function implements POSIX Advisory Locks, e.g.
*
* CHECK_NE(-1, fcntl(zfd, F_SETLKW, &(struct flock){F_WRLCK}));
* // ...
* CHECK_NE(-1, fcntl(zfd, F_SETLK, &(struct flock){F_UNLCK}));
* This function implements POSIX Advisory Locks, which let independent
* processes (and on Windows, threads too!) read/write lock byte ranges
* of files. See `test/libc/calls/lock_test.c` for an example.
*
* Please be warned that locks currently do nothing on Windows since
* figuring out how to polyfill them correctly is a work in progress.

View file

@ -16,19 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
/**
* Applies file descriptor fixups on XNU or old Linux.
* @see __fixupnewsockfd() for socket file descriptors
*/
// Applies file descriptor fixups on XNU or old Linux.
// See __fixupnewsockfd() for socket file descriptors.
int __fixupnewfd(int fd, int flags) {
if (fd != -1) {
if (flags & O_CLOEXEC) {
__sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
_npassert(!__sys_fcntl(fd, F_SETFD, FD_CLOEXEC));
}
}
return fd;

View file

@ -17,28 +17,49 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/nt/enum/filelockflags.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/lock.h"
#include "libc/sysv/errfuns.h"
#define _LOCK_SH 0
#define _LOCK_EX kNtLockfileExclusiveLock
#define _LOCK_NB kNtLockfileFailImmediately
#define _LOCK_UN 8
textwindows int sys_flock_nt(int fd, int op) {
struct NtOverlapped ov;
int64_t h;
struct NtByHandleFileInformation info;
if (!__isfdkind(fd, kFdFile)) return ebadf();
bzero(&ov, sizeof(ov));
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
((!(op & LOCK_UN) &&
LockFileEx(g_fds.p[fd].handle, op, 0, info.nFileSizeLow,
info.nFileSizeHigh, &ov)) ||
((op & LOCK_UN) && UnlockFileEx(g_fds.p[fd].handle, 0, info.nFileSizeLow,
info.nFileSizeHigh, &ov)))) {
return 0;
} else {
h = g_fds.p[fd].handle;
struct NtOverlapped ov = {.hEvent = h};
if (!GetFileInformationByHandle(h, &info)) {
return __winerr();
}
if (op & _LOCK_UN) {
if (op & ~_LOCK_UN) {
return einval();
}
if (UnlockFileEx(h, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
return 0;
} else {
return -1;
}
}
if (op & ~(_LOCK_SH | _LOCK_EX | _LOCK_NB)) {
return einval();
}
if (LockFileEx(h, op, 0, info.nFileSizeLow, info.nFileSizeHigh, &ov)) {
return 0;
} else {
return -1;
}
}

View file

@ -24,16 +24,18 @@
#include "libc/sysv/errfuns.h"
int32_t sys_pipe2(int pipefd[hasatleast 2], unsigned flags) {
int rc, olderr;
int e, rc;
if (!flags) goto OldSkool;
olderr = errno;
e = errno;
rc = __sys_pipe2(pipefd, flags);
if (rc == -1 && errno == ENOSYS) {
errno = olderr;
errno = e;
OldSkool:
if ((rc = sys_pipe(pipefd)) != -1) {
__fixupnewfd(pipefd[0], flags);
__fixupnewfd(pipefd[1], flags);
if (flags) {
__fixupnewfd(pipefd[0], flags);
__fixupnewfd(pipefd[1], flags);
}
}
}
return rc;

View file

@ -46,8 +46,11 @@
*/
ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
ssize_t rc;
if (fd == -1 || offset < 0) return einval();
if (IsAsan() && !__asan_is_valid(buf, size)) {
if (offset < 0) {
rc = einval();
} else if (fd < 0) {
rc = ebadf();
} else if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (__isfdkind(fd, kFdZip)) {
rc = _weaken(__zipos_read)(
@ -60,7 +63,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
} else {
rc = ebadf();
}
assert(rc == -1 || (size_t)rc <= size);
_npassert(rc == -1 || (size_t)rc <= size);
DATATRACE("pread(%d, [%#.*hhs%s], %'zu, %'zd) → %'zd% m", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, offset, rc);
return rc;

View file

@ -16,91 +16,104 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
static ssize_t Preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
static bool once, demodernize;
int i, err;
ssize_t rc;
size_t got, toto;
int e, i;
size_t got;
bool masked;
ssize_t rc, toto;
sigset_t mask, oldmask;
if (fd < 0) {
return ebadf();
}
if (iovlen < 0) {
return einval();
}
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
return efault();
}
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return _weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);
} else if (IsWindows()) {
}
if (IsMetal()) {
return espipe(); // must be serial or console if not zipos
}
if (IsWindows()) {
if (fd < g_fds.n) {
return sys_read_nt(g_fds.p + fd, iov, iovlen, off);
} else {
return ebadf();
}
} else if (IsMetal()) {
return enosys();
}
if (iovlen == 1) {
return sys_pread(fd, iov[0].iov_base, iov[0].iov_len, off, off);
}
/*
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
*/
if (!__vforked && !once) {
err = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) {
errno = err;
once = true;
demodernize = true;
STRACE("demodernizing %s() due to %s", "preadv", "ENOSYS");
} else {
once = true;
return rc;
}
}
if (!demodernize) {
return sys_preadv(fd, iov, iovlen, off, off);
while (iovlen && !iov->iov_len) {
--iovlen;
++iov;
}
if (!iovlen) {
return sys_pread(fd, NULL, 0, off, off);
return sys_pread(fd, 0, 0, off, off);
}
if (iovlen == 1) {
return sys_pread(fd, iov->iov_base, iov->iov_len, off, off);
}
e = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc != -1 || errno != ENOSYS) return rc;
errno = e;
for (toto = i = 0; i < iovlen; ++i) {
rc = sys_pread(fd, iov[i].iov_base, iov[i].iov_len, off, off);
if (rc == -1) {
if (toto && (errno == EINTR || errno == EAGAIN)) {
return toto;
} else {
return -1;
if (!toto) {
toto = -1;
}
break;
}
got = rc;
toto += got;
off += got;
if (got != iov[i].iov_len) {
break;
}
if (!masked) {
sigfillset(&mask);
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
masked = true;
}
}
if (masked) {
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
}
return toto;

View file

@ -19,12 +19,12 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/errfuns.h"
@ -46,9 +46,11 @@
ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
ssize_t rc;
size_t wrote;
if (fd == -1 || offset < 0) return einval();
size = MIN(size, 0x7ffff000);
if (IsAsan() && !__asan_is_valid(buf, size)) {
if (offset < 0) {
rc = einval();
} else if (fd == -1) {
rc = ebadf();
} else if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pwrite(fd, buf, size, offset, offset);
@ -59,10 +61,10 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
}
if (rc != -1) {
wrote = (size_t)rc;
if (wrote == 0) {
assert(size == 0);
if (!wrote) {
_npassert(size == 0);
} else {
assert(wrote <= size);
_npassert(wrote <= size);
}
}
DATATRACE("pwrite(%d, %#.*hhs%s, %'zu, %'zd) → %'zd% m", fd,

View file

@ -16,90 +16,105 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
static ssize_t Pwritev(int fd, const struct iovec *iov, int iovlen,
int64_t off) {
static bool once, demodernize;
int i, err;
ssize_t rc;
size_t sent, toto;
int i, e;
bool masked;
size_t sent;
ssize_t rc, toto;
sigset_t mask, oldmask;
if (fd < 0) {
return ebadf();
}
if (iovlen < 0) {
return einval();
}
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
return efault();
}
if (fd < 0) return einval();
if (iovlen < 0) return einval();
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return _weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, off);
} else if (IsWindows()) {
}
if (IsWindows()) {
if (fd < g_fds.n) {
return sys_write_nt(fd, iov, iovlen, off);
} else {
return ebadf();
}
} else if (IsMetal()) {
return enosys();
}
if (iovlen == 1) {
return sys_pwrite(fd, iov[0].iov_base, iov[0].iov_len, off, off);
if (IsMetal()) {
return espipe(); // must be serial or console if not zipos
}
/*
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
*/
if (!once) {
err = errno;
rc = sys_pwritev(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) {
errno = err;
once = true;
demodernize = true;
STRACE("demodernizing %s() due to %s", "pwritev", "ENOSYS");
} else {
once = true;
return rc;
}
}
if (!demodernize) {
return sys_pwritev(fd, iov, iovlen, off, off);
while (iovlen && !iov->iov_len) {
--iovlen;
++iov;
}
if (!iovlen) {
return sys_pwrite(fd, NULL, 0, off, off);
return sys_pwrite(fd, 0, 0, off, off);
}
if (iovlen == 1) {
return sys_pwrite(fd, iov->iov_base, iov->iov_len, off, off);
}
e = errno;
rc = sys_pwritev(fd, iov, iovlen, off, off);
if (rc != -1 || errno != ENOSYS) return rc;
errno = e;
for (toto = i = 0; i < iovlen; ++i) {
rc = sys_pwrite(fd, iov[i].iov_base, iov[i].iov_len, off, off);
if (rc == -1) {
if (toto && (errno == EINTR || errno == EAGAIN)) {
return toto;
} else {
return -1;
if (!toto) {
toto = -1;
}
break;
}
sent = rc;
toto += sent;
off += sent;
if (sent != iov[i].iov_len) {
break;
}
if (!masked) {
sigfillset(&mask);
_npassert(!sys_sigprocmask(SIG_SETMASK, &mask, &oldmask));
masked = true;
}
}
if (masked) {
_npassert(!sys_sigprocmask(SIG_SETMASK, &oldmask, 0));
}
return toto;

View file

@ -16,14 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/wincrash.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
@ -35,8 +37,10 @@
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
size_t size, ssize_t offset) {
int64_t p;
uint32_t got, avail;
struct NtOverlapped overlap;
if (GetFileType(fd->handle) == kNtFileTypePipe) {
for (;;) {
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
@ -52,10 +56,20 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
}
POLLTRACE("sys_read_nt ready to read");
}
if (offset != -1) {
// windows changes the file pointer even if overlapped is passed
_npassert(SetFilePointerEx(fd->handle, 0, &p, SEEK_CUR));
}
if (ReadFile(fd->handle, data, _clampio(size), &got,
_offset2overlap(fd->handle, offset, &overlap))) {
if (offset != -1) {
_npassert(SetFilePointerEx(fd->handle, p, 0, SEEK_SET));
}
return got;
}
switch (GetLastError()) {
case kNtErrorBrokenPipe: // broken pipe
case kNtErrorNoData: // closing named pipe
@ -73,6 +87,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
ssize_t rc;
uint32_t size;
size_t i, total;
if (opt_offset < -1) return einval();
if (_check_interrupts(true, fd)) return eintr();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {

View file

@ -18,7 +18,7 @@ int sys_sched_setscheduler(int, int, const struct sched_param *);
int sys_sched_yield(void) hidden;
int64_t sys_sched_getaffinity(int, uint64_t, void *) hidden;
int sys_sched_getscheduler_netbsd(int);
int sys_sched_getscheduler_netbsd(int, struct sched_param *);
int sys_sched_setparam_netbsd(int, int, int, const struct sched_param *) //
asm("sys_sched_setparam");
int sys_sched_getparam_netbsd(int, int, int *, struct sched_param *) //

View file

@ -16,11 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
@ -52,7 +54,7 @@ static textwindows int sys_sched_getaffinity_nt(int tid, size_t size,
* @param bitset receives bitset and should be uint64_t[16] in order to
* work on older versions of Linux
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on non-Linux
* @raise ENOSYS if not Linux, NetBSD, or Windows
*/
int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) {
int rc;
@ -60,6 +62,12 @@ int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) {
rc = einval();
} else if (IsWindows()) {
rc = sys_sched_getaffinity_nt(tid, size, bitset);
} else if (IsNetbsd()) {
if (!sys_sched_getaffinity_netbsd(0, tid, MIN(size, 32), bitset)) {
rc = MIN(size, 32);
} else {
rc = -1;
}
} else {
rc = sys_sched_getaffinity(tid, size, bitset);
}

View file

@ -18,13 +18,31 @@
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Gets scheduler policy parameter.
*
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on XNU, Windows
* @raise ENOSYS on XNU, Windows, OpenBSD
*/
int sched_getparam(int pid, struct sched_param *param) {
return sys_sched_getparam(pid, param);
int rc;
struct sched_param p;
if (!param || (IsAsan() && !__asan_is_valid(param, sizeof(*param)))) {
rc = efault();
} else if (IsNetbsd()) {
if (!(rc = sys_sched_getscheduler_netbsd(pid, &p))) {
*param = p;
}
} else {
rc = sys_sched_getparam(pid, param);
}
STRACE("sched_getparam(%d, [%s]) → %d% m", pid, DescribeSchedParam(param),
rc);
return rc;
}

View file

@ -20,10 +20,9 @@
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
int sys_sched_getscheduler_netbsd(int pid) {
int sys_sched_getscheduler_netbsd(int pid, struct sched_param *sp) {
int policy;
struct sched_param sp;
if (sys_sched_getparam_netbsd(pid, P_ALL_LWPS, &policy, &sp) != -1) {
if (sys_sched_getparam_netbsd(pid, P_ALL_LWPS, &policy, sp) != -1) {
return policy;
} else {
return -1;

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
/**
* Gets scheduler policy for `pid`.
@ -40,7 +40,8 @@
int sched_getscheduler(int pid) {
int rc;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
struct sched_param p;
rc = sys_sched_getscheduler_netbsd(pid, &p);
} else {
rc = sys_sched_getscheduler(pid);
}

View file

@ -18,13 +18,14 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/process.h"
@ -34,14 +35,14 @@
#include "libc/sysv/errfuns.h"
static textwindows dontinline int sys_sched_setaffinity_nt(int pid,
uint64_t bitsetsize,
uint64_t size,
const void *bitset) {
int rc;
uintptr_t mask;
int64_t handle;
uintptr_t mask;
typeof(SetThreadAffinityMask) *SetAffinityMask = SetThreadAffinityMask;
mask = 0;
memcpy(&mask, bitset, min(bitsetsize, sizeof(uintptr_t)));
memcpy(&mask, bitset, min(size, sizeof(uintptr_t)));
handle = 0;
if (!pid) pid = GetCurrentThreadId();
if (0 < pid && pid <= UINT32_MAX) {
@ -69,19 +70,21 @@ static textwindows dontinline int sys_sched_setaffinity_nt(int pid,
* Asks kernel to only schedule thread on particular CPUs.
*
* @param tid is the process or thread id (or 0 for caller)
* @param bitsetsize is byte length of bitset, which should be 128
* @param size is byte length of bitset, which should be 128
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS if not Linux or Windows
* @raise ENOSYS if not Linux, NetBSD, or Windows
*/
int sched_setaffinity(int tid, size_t bitsetsize, const cpu_set_t *bitset) {
int sched_setaffinity(int tid, size_t size, const cpu_set_t *bitset) {
int rc;
if (bitsetsize != 128) {
if (size != 128) {
rc = einval();
} else if (IsWindows()) {
rc = sys_sched_setaffinity_nt(tid, bitsetsize, bitset);
rc = sys_sched_setaffinity_nt(tid, size, bitset);
} else if (IsNetbsd()) {
rc = sys_sched_setaffinity_netbsd(0, tid, MIN(size, 32), bitset);
} else {
rc = sys_sched_setaffinity(tid, bitsetsize, bitset);
rc = sys_sched_setaffinity(tid, size, bitset);
}
STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", tid, bitsetsize, bitset);
STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", tid, size, bitset);
return rc;
}

View file

@ -18,11 +18,30 @@
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Sets scheduler policy parameter.
* @raise ENOSYS on XNU, Windows
*
* @return 0 on success, or -1 w/ errno
* @raise ENOSYS on XNU, Windows, OpenBSD
*/
int sched_setparam(int pid, const struct sched_param *param) {
return sys_sched_setparam(pid, param);
int rc, policy;
struct sched_param p;
if (!param || (IsAsan() && !__asan_is_valid(param, sizeof(*param)))) {
rc = efault();
} else if (IsNetbsd()) {
if ((rc = policy = sys_sched_getscheduler_netbsd(pid, &p)) != -1) {
rc = sys_sched_setparam_netbsd(pid, P_ALL_LWPS, policy, param);
}
} else {
rc = sys_sched_setparam(pid, param);
}
STRACE("sched_setparam(%d, %s) → %d% m", pid, DescribeSchedParam(param), rc);
return rc;
}

View file

@ -17,14 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/sched-sysv.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/calls/struct/sched_param.h"
#include "libc/calls/struct/sched_param.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/thread/tls.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
/**
* Sets scheduling policy of process, e.g.
@ -94,9 +94,10 @@
*/
int sched_setscheduler(int pid, int policy, const struct sched_param *param) {
int rc, old;
struct sched_param p;
if (IsNetbsd()) {
rc = sys_sched_getscheduler_netbsd(pid);
rc = sys_sched_getscheduler_netbsd(pid, &p);
} else {
rc = sys_sched_getscheduler(pid);
}

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.h"
@ -26,6 +28,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
@ -35,12 +38,25 @@
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
ssize_t offset) {
int64_t h, p;
uint32_t err, sent;
struct NtOverlapped overlap;
if (WriteFile(g_fds.p[fd].handle, data, _clampio(size), &sent,
_offset2overlap(g_fds.p[fd].handle, offset, &overlap))) {
h = g_fds.p[fd].handle;
if (offset != -1) {
// windows changes the file pointer even if overlapped is passed
_npassert(SetFilePointerEx(h, 0, &p, SEEK_CUR));
}
if (WriteFile(h, data, _clampio(size), &sent,
_offset2overlap(h, offset, &overlap))) {
if (offset != -1) {
_npassert(SetFilePointerEx(h, p, 0, SEEK_SET));
}
return sent;
}
switch (GetLastError()) {
// case kNtErrorInvalidHandle:
// return ebadf(); /* handled by consts.sh */
@ -68,6 +84,7 @@ textwindows ssize_t sys_write_nt(int fd, const struct iovec *iov, size_t iovlen,
size_t i, total;
uint32_t size, wrote;
struct NtOverlapped overlap;
if (opt_offset < -1) return einval();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {
for (total = i = 0; i < iovlen; ++i) {

View file

@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/fmt/bing.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Turns binary octet into unicode glyph representation.

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/fmt/fmt.internal.h"
#include "libc/fmt/internal.h"
#include "libc/intrin/bits.h"
@ -26,6 +25,7 @@
#include "libc/intrin/weaken.h"
#include "libc/str/str.h"
#include "libc/str/strwidth.h"
#include "libc/str/tab.internal.h"
#include "libc/str/thompike.h"
#include "libc/str/unicode.h"
#include "libc/str/utf16.h"

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes 128-bit signed integer from ASCII string.

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes intmax_t from ASCII string.

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes signed integer from ASCII string.

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes 128-bit unsigned integer from ASCII string.

View file

@ -20,6 +20,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes unsigned integer from ASCII string.

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes uintmax_t from ASCII string.

View file

@ -21,6 +21,7 @@
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
static const int kCp437iMultimappings[] = {
u'\n' << 8 | '\n', // NEWLINE

View file

@ -23,6 +23,7 @@
#include "libc/runtime/runtime.h"
#include "libc/str/oldutf16.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/str/tpdecodecb.internal.h"
#include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h"

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes 128-bit signed integer from wide string.

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes intmax_t from wide string.

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes signed long integer from wide string.

View file

@ -21,6 +21,7 @@
#include "libc/fmt/strtol.internal.h"
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes signed long long integer from wide string.

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes 128-bit unsigned integer from wide string.

View file

@ -20,6 +20,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes unsigned integer from wide string.

View file

@ -20,6 +20,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes unsigned long long integer from wide string.

View file

@ -19,6 +19,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/strtol.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Decodes uintmax_t from wide string.

View file

@ -50,6 +50,7 @@
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nr.h"

View file

@ -3,7 +3,6 @@
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asancodes.h"
#include "libc/macros.internal.h"
#include "libc/thread/thread.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -30,6 +30,7 @@ const char *DescribeNtFileFlagAttr(char[256], uint32_t);
const char *DescribeNtFileMapFlags(char[64], uint32_t);
const char *DescribeNtFileShareFlags(char[64], uint32_t);
const char *DescribeNtFiletypeFlags(char[64], uint32_t);
const char *DescribeNtLockFileFlags(char[64], uint32_t);
const char *DescribeNtMovFileInpFlags(char[256], uint32_t);
const char *DescribeNtPageFlags(char[64], uint32_t);
const char *DescribeNtPipeModeFlags(char[64], uint32_t);
@ -72,6 +73,7 @@ const char *DescribeWhence(char[12], int);
#define DescribeNtFileMapFlags(x) DescribeNtFileMapFlags(alloca(64), x)
#define DescribeNtFileShareFlags(x) DescribeNtFileShareFlags(alloca(64), x)
#define DescribeNtFiletypeFlags(x) DescribeNtFiletypeFlags(alloca(64), x)
#define DescribeNtLockFileFlags(x) DescribeNtLockFileFlags(alloca(64), x)
#define DescribeNtMovFileInpFlags(x) DescribeNtMovFileInpFlags(alloca(256), x)
#define DescribeNtPageFlags(x) DescribeNtPageFlags(alloca(64), x)
#define DescribeNtPipeModeFlags(x) DescribeNtPipeModeFlags(alloca(64), x)

View file

@ -22,6 +22,7 @@
char *DescribeMagnum(char *b, const struct MagnumStr *m, const char *p, int x) {
char *s;
if (x == 127) return "CLOCK_INVALID";
if ((s = GetMagnumStr(m, x))) {
stpcpy(stpcpy(b, p), s);
return b;

View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filelockflags.h"
static const struct DescribeFlags kNtLockFileFlags[] = {
{kNtLockfileFailImmediately, "FailImmediately"}, //
{kNtLockfileExclusiveLock, "ExclusiveLock"}, //
};
const char *(DescribeNtLockFileFlags)(char buf[64], uint32_t x) {
return DescribeFlags(buf, 64, kNtLockFileFlags, ARRAYLEN(kNtLockFileFlags),
"kNtLockfile", x);
}

View file

@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
const char *(DescribeNtOverlapped)(char b[128], struct NtOverlapped *o) {
int i = 0, n = 128;
bool gotsome = false;
if (!o) return "NULL";
i += ksnprintf(b + i, MAX(0, n - i), "{");
if (o->hEvent) {
if (gotsome) {
i += ksnprintf(b + i, MAX(0, n - i), ", ");
} else {
gotsome = true;
}
i += ksnprintf(b + i, MAX(0, n - i), ".hEvent = %ld", o->hEvent);
}
if (o->Pointer) {
if (gotsome) {
i += ksnprintf(b + i, MAX(0, n - i), ", ");
} else {
gotsome = true;
}
i += ksnprintf(b + i, MAX(0, n - i), ".Pointer = (void *)%p", o->Pointer);
}
i += ksnprintf(b + i, MAX(0, n - i), "}");
return b;
}

View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBENTOVERLAPPED_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBENTOVERLAPPED_INTERNAL_H_
#include "libc/mem/alloca.h"
#include "libc/nt/struct/overlapped.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
const char *DescribeNtOverlapped(char[128], struct NtOverlapped *);
#define DescribeNtOverlapped(x) DescribeNtOverlapped(alloca(128), x)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBENTOVERLAPPED_INTERNAL_H_ */

View file

@ -16,8 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/thunk/msabi.h"
@ -40,8 +41,9 @@ textwindows bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode,
nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
if (!ok) __winerr();
NTTRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m",
NTTRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %s) → %hhhd% m",
hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped, ok);
nOutBufferSize, lpBytesReturned, DescribeNtOverlapped(lpOverlapped),
ok);
return ok;
}

View file

@ -33,17 +33,24 @@
kClockNames:
.e CLOCK_REALTIME,"REALTIME"
.e CLOCK_REALTIME_FAST,"REALTIME_FAST"
.e CLOCK_REALTIME_PRECISE,"REALTIME_PRECISE"
.e CLOCK_MONOTONIC,"MONOTONIC"
.e CLOCK_MONOTONIC_FAST,"MONOTONIC_FAST"
.e CLOCK_MONOTONIC_RAW,"MONOTONIC_RAW"
.e CLOCK_MONOTONIC_PRECISE,"MONOTONIC_PRECISE"
.e CLOCK_REALTIME_COARSE,"REALTIME_COARSE"
.e CLOCK_MONOTONIC_COARSE,"MONOTONIC_COARSE"
.e CLOCK_PROCESS_CPUTIME_ID,"PROCESS_CPUTIME_ID"
.e CLOCK_THREAD_CPUTIME_ID,"THREAD_CPUTIME_ID"
.e CLOCK_TAI,"TAI"
.e CLOCK_PROF,"PROF"
.e CLOCK_BOOTTIME,"BOOTTIME"
.e CLOCK_REALTIME_ALARM,"REALTIME_ALARM"
.e CLOCK_BOOTTIME_ALARM,"BOOTTIME_ALARM"
.e CLOCK_UPTIME,"UPTIME"
.e CLOCK_UPTIME_FAST,"UPTIME_FAST"
.e CLOCK_UPTIME_PRECISE,"UPTIME_PRECISE"
.e CLOCK_SECOND,"SECOND"
.long MAGNUM_TERMINATOR
.endobj kClockNames,globl,hidden
.overrun

View file

@ -48,6 +48,7 @@
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"

50
libc/intrin/lockfileex.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/files.h"
__msabi extern typeof(LockFileEx) *const __imp_LockFileEx;
/**
* Locks file on the New Technology.
*
* @return handle, or -1 on failure
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
bool32 LockFileEx(int64_t hFile, uint32_t dwFlags, uint32_t dwReserved,
uint32_t nNumberOfBytesToLockLow,
uint32_t nNumberOfBytesToLockHigh,
struct NtOverlapped *lpOverlapped) {
bool32 ok;
STRACE("LockFileEx(%ld, %s, %#x, %'zu, %s) → ...", hFile,
DescribeNtLockFileFlags(dwFlags), dwReserved,
(uint64_t)nNumberOfBytesToLockHigh << 32 | nNumberOfBytesToLockLow,
DescribeNtOverlapped(lpOverlapped));
ok = __imp_LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow,
nNumberOfBytesToLockHigh, lpOverlapped);
if (!ok) __winerr();
STRACE("LockFileEx(%ld, %s, %#x, %'zu, [%s]) → %hhhd% m", hFile,
DescribeNtLockFileFlags(dwFlags), dwReserved,
(uint64_t)nNumberOfBytesToLockHigh << 32 | nNumberOfBytesToLockLow,
DescribeNtOverlapped(lpOverlapped), ok);
return ok;
}

View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/files.h"
#include "libc/str/str.h"
__msabi extern typeof(UnlockFileEx) *const __imp_UnlockFileEx;
/**
* Unlocks file on the New Technology.
*
* @return handle, or -1 on failure
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
bool32 UnlockFileEx(int64_t hFile, uint32_t dwReserved,
uint32_t nNumberOfBytesToUnlockLow,
uint32_t nNumberOfBytesToUnlockHigh,
struct NtOverlapped *lpOverlapped) {
bool32 ok;
STRACE("UnlockFileEx(%ld, %#x, %'zu, %s) → ...", hFile, dwReserved,
(uint64_t)nNumberOfBytesToUnlockHigh << 32 | nNumberOfBytesToUnlockLow,
DescribeNtOverlapped(lpOverlapped));
ok = __imp_UnlockFileEx(hFile, dwReserved, nNumberOfBytesToUnlockLow,
nNumberOfBytesToUnlockHigh, lpOverlapped);
if (!ok) __winerr();
STRACE("UnlockFileEx(%ld, %#x, %'zu, [%s]) → %hhhd% m", hFile, dwReserved,
(uint64_t)nNumberOfBytesToUnlockHigh << 32 | nNumberOfBytesToUnlockLow,
DescribeNtOverlapped(lpOverlapped), ok);
return ok;
}

View file

@ -16,10 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
@ -55,8 +56,9 @@ textwindows int WSARecv(
kprintf(STRACE_PROLOGUE "WSARecv(%lu, [", s);
DescribeIovNt(inout_lpBuffers, dwBufferCount,
rc != -1 ? NumberOfBytesRecvd : 0);
kprintf("], %u, [%'u], %p, %p, %p) → %d% lm\n", dwBufferCount,
NumberOfBytesRecvd, inout_lpFlags, opt_inout_lpOverlapped,
kprintf("], %u, [%'u], %p, %s, %p) → %d% lm\n", dwBufferCount,
NumberOfBytesRecvd, inout_lpFlags,
DescribeNtOverlapped(opt_inout_lpOverlapped),
opt_lpCompletionRoutine, rc);
}
#else

View file

@ -16,10 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/strace.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
@ -57,9 +58,10 @@ textwindows int WSARecvFrom(
kprintf(STRACE_PROLOGUE "WSARecvFrom(%lu, [", s);
DescribeIovNt(inout_lpBuffers, dwBufferCount,
rc != -1 ? NumberOfBytesRecvd : 0);
kprintf("], %u, [%'u], %p, %p, %p, %p, %p) → %d% lm\n", dwBufferCount,
kprintf("], %u, [%'u], %p, %p, %p, %s, %p) → %d% lm\n", dwBufferCount,
NumberOfBytesRecvd, opt_out_fromsockaddr, opt_inout_fromsockaddrlen,
inout_lpFlags, opt_inout_lpOverlapped, opt_lpCompletionRoutine, rc);
inout_lpFlags, DescribeNtOverlapped(opt_inout_lpOverlapped),
opt_lpCompletionRoutine, rc);
}
#else
rc = __imp_WSARecvFrom(s, inout_lpBuffers, dwBufferCount,

View file

@ -131,7 +131,7 @@
#define kNtErrorTooManyTcbs 155
#define kNtErrorSignalRefused 156
#define kNtErrorDiscarded 157
#define kNtErrorNotLocked 158
#define kNtErrorNotLocked 158 /* ENOLCK */
#define kNtErrorBadThreadidAddr 159
#define kNtErrorBadArguments 160
#define kNtErrorBadPathname 161
@ -1531,7 +1531,7 @@
#define kNtErrorLogSectorParityInvalid 6601
#define kNtErrorLogSectorRemapped 6602
#define kNtErrorLogBlockIncomplete 6603
#define kNtErrorLogInvalidRange 6604
#define kNtErrorLogInvalidRange 6604 /* ERANGE */
#define kNtErrorLogBlocksExhausted 6605
#define kNtErrorLogReadContextInvalid 6606
#define kNtErrorLogRestartInvalid 6607

View file

@ -116,13 +116,13 @@ bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode,
bool32 LockFile(int64_t hFile, uint32_t dwFileOffsetLow,
uint32_t dwFileOffsetHigh, uint32_t nNumberOfBytesToLockLow,
uint32_t nNumberOfBytesToLockHigh);
bool32 UnlockFile(int64_t hFile, uint32_t dwFileOffsetLow,
uint32_t dwFileOffsetHigh, uint32_t nNumberOfBytesToUnlockLow,
uint32_t nNumberOfBytesToUnlockHigh);
bool32 LockFileEx(int64_t hFile, uint32_t dwFlags, uint32_t dwReserved,
uint32_t nNumberOfBytesToLockLow,
uint32_t nNumberOfBytesToLockHigh,
struct NtOverlapped *lpOverlapped) paramsnonnull();
bool32 UnlockFile(int64_t hFile, uint32_t dwFileOffsetLow,
uint32_t dwFileOffsetHigh, uint32_t nNumberOfBytesToUnlockLow,
uint32_t nNumberOfBytesToUnlockHigh);
bool32 UnlockFileEx(int64_t hFile, uint32_t dwReserved,
uint32_t nNumberOfBytesToUnlockLow,
uint32_t nNumberOfBytesToUnlockHigh,

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_LockFileEx,LockFileEx,0
.text.windows
LockFileEx:
__LockFileEx:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_LockFileEx(%rip),%rax
jmp __sysv2nt6
.endfn LockFileEx,globl
.endfn __LockFileEx,globl
.previous

View file

@ -2,11 +2,11 @@
.imp kernel32,__imp_UnlockFileEx,UnlockFileEx,0
.text.windows
UnlockFileEx:
__UnlockFileEx:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_UnlockFileEx(%rip),%rax
jmp __sysv2nt6
.endfn UnlockFileEx,globl
.endfn __UnlockFileEx,globl
.previous

View file

@ -700,7 +700,6 @@ imp 'LocalUnlock' LocalUnlock kernel32 0
imp 'LocaleNameToLCID' LocaleNameToLCID kernel32 0
imp 'LocateXStateFeature' LocateXStateFeature kernel32 0
imp 'LockFile' LockFile kernel32 0 5
imp 'LockFileEx' LockFileEx kernel32 0 6
imp 'LockResource' LockResource kernel32 0 1
imp 'MapUserPhysicalPages' MapUserPhysicalPages kernel32 0
imp 'MapUserPhysicalPagesScatter' MapUserPhysicalPagesScatter kernel32 986
@ -1024,7 +1023,6 @@ imp 'UTUnRegister' UTUnRegister kernel32 1459
imp 'UmsThreadYield' UmsThreadYield kernel32 1460
imp 'UnhandledExceptionFilter' UnhandledExceptionFilter kernel32 0
imp 'UnlockFile' UnlockFile kernel32 0 5
imp 'UnlockFileEx' UnlockFileEx kernel32 0 5
imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 0 2
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 0 3
imp 'UnregisterApplicationRecoveryCallback' UnregisterApplicationRecoveryCallback kernel32 1466
@ -1120,6 +1118,7 @@ imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2
imp '__GenerateConsoleCtrlEvent' GenerateConsoleCtrlEvent kernel32 0 2
imp '__GetExitCodeProcess' GetExitCodeProcess kernel32 0 2
imp '__GetFileAttributes' GetFileAttributesW kernel32 0 1
imp '__LockFileEx' LockFileEx kernel32 0 6
imp '__MapViewOfFileEx' MapViewOfFileEx kernel32 0 6
imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7
imp '__MoveFileEx' MoveFileExW kernel32 0 3
@ -1128,6 +1127,7 @@ imp '__ReOpenFile' ReOpenFile kernel32 0 4 # TODO(jart): 6.2 and highe
imp '__RemoveDirectory' RemoveDirectoryW kernel32 0 1
imp '__SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
imp '__TerminateProcess' TerminateProcess kernel32 0 2
imp '__UnlockFileEx' UnlockFileEx kernel32 0 5
imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1
imp '__VirtualProtect' VirtualProtect kernel32 0 4
imp '__WaitForMultipleObjects' WaitForMultipleObjects kernel32 0 4

View file

@ -38,7 +38,7 @@ FILE *fdopen(int fd, const char *mode) {
f->fd = fd;
f->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
f->iomode = fopenflags(mode);
f->lock._type = PTHREAD_MUTEX_RECURSIVE;
((pthread_mutex_t *)f->lock)->_type = PTHREAD_MUTEX_RECURSIVE;
f->size = BUFSIZ;
if ((f->buf = malloc(f->size))) {
if ((f->iomode & O_ACCMODE) != O_RDONLY) {

View file

@ -23,5 +23,5 @@
* Acquires reentrant lock on stdio object, blocking if needed.
*/
void(flockfile)(FILE *f) {
pthread_mutex_lock(&f->lock);
pthread_mutex_lock((pthread_mutex_t *)f->lock);
}

View file

@ -54,7 +54,7 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
f->end = size;
f->size = size;
f->iomode = fopenflags(mode);
f->lock._type = PTHREAD_MUTEX_RECURSIVE;
((pthread_mutex_t *)f->lock)->_type = PTHREAD_MUTEX_RECURSIVE;
if (f->iomode & O_APPEND) {
if ((p = memchr(buf, '\0', size))) {
f->beg = p - (char *)buf;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/lock.internal.h"
#include "libc/stdio/stdio.h"
/**
@ -24,5 +25,5 @@
* @return 0 on success, or non-zero if another thread owns the lock
*/
int(ftrylockfile)(FILE *f) {
return pthread_mutex_trylock(&f->lock);
return pthread_mutex_trylock((pthread_mutex_t *)f->lock);
}

View file

@ -16,11 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/lock.internal.h"
#include "libc/stdio/stdio.h"
/**
* Releases lock on stdio object.
*/
void(funlockfile)(FILE *f) {
pthread_mutex_unlock(&f->lock);
pthread_mutex_unlock((pthread_mutex_t *)f->lock);
}

View file

@ -19,6 +19,6 @@
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
compatfn char *gets(char *s) {
char *gets(char *s) {
return fgets(s, INT_MAX, stdin);
}

View file

@ -1,9 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#include "libc/fmt/pflink.h"
#include "libc/thread/thread.h"
#ifndef _STDIO_H
#define _STDIO_H
#include "libc/fmt/pflink.h"
#define L_ctermid 20
#define FILENAME_MAX PATH_MAX
#define FOPEN_MAX 1000
@ -17,19 +15,19 @@ COSMOPOLITAN_C_START_
*/
typedef struct FILE {
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln; /* 0x30 */
pthread_mutex_t lock; /* 0x38 */
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln; /* 0x30 */
char lock[16]; /* 0x38 */
} FILE;
extern FILE *stdin;
@ -91,9 +89,9 @@ char *ctermid(char *);
void perror(const char *) relegated;
typedef uint64_t fpos_t;
compatfn char *gets(char *) paramsnonnull();
compatfn int fgetpos(FILE *, fpos_t *) paramsnonnull();
compatfn int fsetpos(FILE *, const fpos_t *) paramsnonnull();
char *gets(char *) paramsnonnull();
int fgetpos(FILE *, fpos_t *) paramsnonnull();
int fsetpos(FILE *, const fpos_t *) paramsnonnull();
int system(const char *);
int systemexec(const char *);
@ -195,4 +193,4 @@ int vfprintf_unlocked(FILE *, const char *, va_list)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_H_ */
#endif /* _STDIO_H */

View file

View file

@ -18,40 +18,11 @@
*/
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/bsr.h"
#include "libc/mem/alg.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
void djbsort_avx2(int32_t *, long);
static dontinline void intsort(int *x, size_t n, size_t t) {
int a, b, c;
size_t i, p, q;
for (p = t; p > 0; p >>= 1) {
for (i = 0; i < n - p; ++i) {
if (!(i & p)) {
a = x[i + 0];
b = x[i + p];
if (a > b) c = a, a = b, b = c;
x[i + 0] = a;
x[i + p] = b;
}
}
for (q = t; q > p; q >>= 1) {
for (i = 0; i < n - q; ++i) {
if (!(i & p)) {
a = x[i + p];
b = x[i + q];
if (a > b) c = a, a = b, b = c;
x[i + p] = a;
x[i + q] = b;
}
}
}
}
}
/**
* D.J. Bernstein's outrageously fast integer sorting algorithm.
*/
@ -65,7 +36,7 @@ void djbsort(int32_t *a, size_t n) {
if (X86_HAVE(AVX2)) {
djbsort_avx2(a, n);
} else {
intsort(a, n, 1ul << _bsrl(n - 1));
_intsort(a, n);
}
}
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/intrin/bits.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Compares memory case-insensitively.

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
bool _startswithi(const char *s, const char *prefix) {
for (;;) {

View file

@ -6,13 +6,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const int8_t kHexToInt[256];
extern const uint8_t gperf_downcase[256];
extern const uint8_t kToLower[256];
extern const uint8_t kToUpper[256];
extern const uint8_t kBase36[256];
extern const char16_t kCp437[256];
int isascii(int);
int isspace(int);
int isalpha(int);

View file

@ -19,6 +19,7 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Compares NUL-terminated strings ascii case-insensitively.

View file

@ -19,6 +19,7 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
/**
* Compares NUL-terminated strings case-insensitively w/ limit.

15
libc/str/tab.internal.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_STR_TAB_INTERNAL_H_
#define COSMOPOLITAN_LIBC_STR_TAB_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const int8_t kHexToInt[256];
extern const uint8_t gperf_downcase[256];
extern const uint8_t kToLower[256];
extern const uint8_t kToUpper[256];
extern const uint8_t kBase36[256];
extern const char16_t kCp437[256];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STR_TAB_INTERNAL_H_ */

View file

@ -57,11 +57,11 @@ syscon errno ESPIPE 29 29 29 29 29 25 # invalid seek; unix conse
syscon errno EROFS 30 30 30 30 30 6009 # read-only filesystem; unix consensus; kNtErrorFileReadOnly; raised by access(2), acct(2), bind(2), chmod(2), chown(2), link(2), mkdir(2), mknod(2), mount(2), open(2), rename(2), rmdir(2), symlink(2), truncate(2), unlink(2), utime(2), utimensat(2)
syscon errno EMLINK 31 31 31 31 31 1142 # too many links; unix consensus; kNtErrorTooManyLinks; raised by link(2), mkdir(2), rename(2)
syscon errno EPIPE 32 32 32 32 32 109 # broken pipe; unix consensus; kNtErrorBrokenPipe; raised by send(2), write(2), tcp(7), unix(7), ip(7)
syscon errno EDOM 33 33 33 33 33 33 # mathematics argument out of domain of function; bsd consensus; fudged on NT; returned by cos(3), fmod(3), log1p(3), sin(3), tan(3), tgamma(3)
syscon errno ERANGE 34 34 34 34 34 34 # result too large; bsd consensus; fudged on NT; raised by getxattr(2), listxattr(2), lookup_dcookie(2), prctl(2), quotactl(2), semctl(2), semop(2), setxattr(2)
syscon errno EDOM 33 33 33 33 33 20000 # mathematics argument out of domain of function; bsd consensus; made up on NT; returned by cos(3), fmod(3), log1p(3), sin(3), tan(3), tgamma(3)
syscon errno ERANGE 34 34 34 34 34 6604 # result too large; bsd consensus; kNtErrorLogInvalidRange; raised by getxattr(2), listxattr(2), lookup_dcookie(2), prctl(2), quotactl(2), semctl(2), semop(2), setxattr(2)
syscon errno EDEADLK 35 11 11 11 11 1131 # resource deadlock avoided; bsd consensus; kNtErrorPossibleDeadlock; raised by fcntl(2), keyctl(2)
syscon errno ENAMETOOLONG 36 63 63 63 63 10063 # filename too long; bsd consensus; WSAENAMETOOLONG; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), execve(2), gethostname(2), inotify_add_watch(2), link(2), lookup_dcookie(2), mkdir(2), mknod(2), mount(2), open(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), umount(2), unlink(2), utimensat(2)
syscon errno ENOLCK 37 77 77 77 77 0 # no locks available; bsd consensus; raised by fcntl(2), flock(2)
syscon errno ENOLCK 37 77 77 77 77 158 # no locks available; kNtErrorNotLocked; bsd consensus; raised by fcntl(2), flock(2)
syscon errno ENOTEMPTY 39 66 66 66 66 145 # directory not empty; bsd consensus; kNtErrorDirNotEmpty (TODO: What is WSAENOTEMPTY? 10066); raised by rmdir(2)
syscon errno ELOOP 40 62 62 62 62 1921 # too many levels of symbolic links; bsd consensus; kNtErrorCantResolveFilename; raised by access(2), acct(2), bind(2), chdir(2), chmod(2), chown(2), chroot(2), epoll_ctl(2), execve(2), execveat(2), keyctl(2), link(2), mkdir(2), mknod(2), mount(2), open(2), open_by_handle_at(2), openat2(2), readlink(2), rename(2), rmdir(2), spu_create(2), stat(2), statfs(2), statx(2), symlink(2), truncate(2), unlink(2), utimensat(2)
syscon errno ENOMSG 42 91 83 90 83 0 # raised by msgop(2)
@ -328,10 +328,10 @@ syscon access R_OK 4 4 4 4 4 0x80000000 # unix consensus and kNtG
# flock() flags
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon lock LOCK_SH 1 1 1 1 1 0 # shared [unix consensus]
syscon lock LOCK_SH 1 1 1 1 1 0 # shared [unix consensus]; hard-coded into flock-nt.c too
syscon lock LOCK_EX 2 2 2 2 2 2 # exclusive [consensus!] a.k.a. kNtLockfileExclusiveLock
syscon lock LOCK_NB 4 4 4 4 4 1 # non-blocking [unix consensus] a.k.a. kNtLockfileFailImmediately
syscon lock LOCK_UN 8 8 8 8 8 8 # unlock [unix consensus & faked NT]
syscon lock LOCK_UN 8 8 8 8 8 8 # unlock [unix consensus & faked NT]; hard-coded into flock-nt.c too
# waitpid() / wait4() options
#

View file

@ -1,2 +1,3 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,EAGAIN,11,35,35,35,35,10035
.yoink kDos2Errno.EAGAIN

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,EDOM,33,33,33,33,33,33
.syscon errno,EDOM,33,33,33,33,33,20000

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ENOLCK,37,77,77,77,77,0
.syscon errno,ENOLCK,37,77,77,77,77,158

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/consts/syscon.internal.inc"
.syscon errno,ERANGE,34,34,34,34,34,34
.syscon errno,ERANGE,34,34,34,34,34,6604

View file

@ -129,7 +129,7 @@ dos kNtErrorInvalidFunction EINVAL
dos kNtErrorInvalidNetname EADDRNOTAVAIL
dos kNtErrorInvalidUserBuffer EMSGSIZE
dos kNtErrorIoPending EINPROGRESS
dos kNtErrorLockViolation EACCES
dos kNtErrorLockViolation EAGAIN
dos kNtErrorMoreData EMSGSIZE
dos kNtErrorNetnameDeleted ECONNABORTED
dos kNtErrorNetworkAccessDenied EACCES
@ -139,7 +139,6 @@ dos kNtErrorNonpagedSystemResources ENOMEM
dos kNtErrorNotEnoughMemory ENOMEM
dos kNtErrorNotEnoughQuota ENOMEM
dos kNtErrorNotFound ENOENT
dos kNtErrorNotLocked EACCES
dos kNtErrorNotReady EACCES
dos kNtErrorNotSupported ENOTSUP
dos kNtErrorNoMoreFiles ENOENT

View file

@ -13,9 +13,7 @@ kDos2Errno.EACCES:
.e kNtErrorCannotMake,EACCES
.e kNtErrorCrc,EACCES
.e kNtErrorGenFailure,EACCES
.e kNtErrorLockViolation,EACCES
.e kNtErrorNetworkAccessDenied,EACCES
.e kNtErrorNotLocked,EACCES
.e kNtErrorNotReady,EACCES
.e kNtErrorOutOfPaper,EACCES
.e kNtErrorSectorNotFound,EACCES

View file

@ -0,0 +1,11 @@
// generated by libc/sysv/dos2errno.sh
#include "libc/nt/errors.h"
.macro .e doscode systemv
.short \doscode
.long \systemv
.endm
.section .sort.rodata.dos2errno.2,"a",@progbits
.globl kDos2Errno.EAGAIN
.type kDos2Errno.EAGAIN,@object
kDos2Errno.EAGAIN:
.e kNtErrorLockViolation,EAGAIN

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/testlib/testlib.h"
/**

View file

@ -18,6 +18,7 @@
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "net/http/escape.h"
#include "net/http/url.h"

View file

@ -21,6 +21,7 @@
#include "libc/intrin/bswap.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "net/http/http.h"
static const struct ContentTypeExtension {

View file

@ -33,6 +33,7 @@
#line 1 "gethttpheader.gperf"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "gethttpheader.gperf"

View file

@ -33,6 +33,7 @@
#line 1 "gethttpmethod.gperf"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "gethttpmethod.gperf"

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "net/http/http.h"
/**

View file

@ -20,6 +20,7 @@
#include "libc/limits.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/url.h"

View file

@ -18,6 +18,7 @@
*/
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/sysv/errfuns.h"
#include "net/http/escape.h"
#include "net/http/http.h"

View file

@ -30,8 +30,29 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/x/x.h"
int Lock(int fd, int type, long start, long len) {
int e;
struct flock lock = {
.l_type = type,
.l_whence = SEEK_SET,
.l_start = start,
.l_len = len,
};
e = errno;
while (fcntl(fd, F_SETLK, &lock)) {
if (errno == EAGAIN || errno == EACCES) {
errno = e;
continue;
} else {
return -1;
}
}
return 0;
}
char testlib_enable_tmp_setup_teardown;
TEST(fcntl_getfl, testRemembersAccessMode) {
@ -70,59 +91,15 @@ TEST(fcntl, getfd) {
ASSERT_SYS(0, 0, close(3));
}
void OnSig(int sig) {
TEST(fcntl, F_DUPFD_CLOEXEC) {
ASSERT_SYS(0, 3, open("/dev/null", O_RDWR));
ASSERT_SYS(0, 5, fcntl(3, F_DUPFD_CLOEXEC, 5));
ASSERT_SYS(0, FD_CLOEXEC, fcntl(5, F_GETFD));
ASSERT_SYS(0, 0, close(5));
ASSERT_SYS(0, 0, close(3));
}
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));
void OnSig(int sig) {
}
TEST(posixAdvisoryLocks, twoProcesses) {

186
test/libc/calls/lock_test.c Normal file
View file

@ -0,0 +1,186 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/flock.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
/**
* @fileoverview POSIX Advisory Locks Test
*/
#define PROCESSES 8
#define THREADS (IsWindows() ? 8 : 0)
#define RATIO 3
#define ITERATIONS 10
char testlib_enable_tmp_setup_teardown;
_Thread_local const char *kind;
void Log(const char *fmt, ...) {
#if 0
va_list va;
char b[512];
int i, n = sizeof(b);
va_start(va, fmt);
i = ksnprintf(b, n, "%s pid=%d tid=%d ", kind, getpid(), gettid());
i += kvsnprintf(b + i, MAX(0, n - i), fmt, va);
i += ksnprintf(b + i, MAX(0, n - i), "\n");
write(2, b, MIN(i, n));
va_end(va);
#endif
}
void Lock(int fd, int type, long start, long len) {
int e;
struct flock lock = {
.l_type = type,
.l_whence = SEEK_SET,
.l_start = start,
.l_len = len,
};
e = errno;
while (fcntl(fd, F_SETLK, &lock)) {
ASSERT_TRUE(errno == EAGAIN || errno == EACCES);
errno = e;
Log("flock spinning on %d", fd);
}
}
void WriteLock(int fd, long start, long len) {
Lock(fd, F_WRLCK, start, len);
Log("acquired write lock on %d", fd);
}
void ReadLock(int fd, long start, long len) {
Lock(fd, F_RDLCK, start, len);
Log("acquired read lock on %d", fd);
}
void Unlock(int fd, long start, long len) {
Lock(fd, F_UNLCK, start, len);
Log("released lock on %d", fd);
}
void *Reader(void *arg) {
int i, j, fd;
char buf[10];
kind = arg;
ASSERT_NE(-1, (fd = open("db", O_RDONLY)));
for (j = 0; j < ITERATIONS; ++j) {
ReadLock(fd, 10, 10);
for (i = 0; i < 10; ++i) {
ASSERT_SYS(0, 1, pread(fd, buf + i, 1, 10 + i));
ASSERT_EQ(buf[0], buf[i]);
}
Unlock(fd, 10, 10);
sched_yield();
}
ASSERT_SYS(0, 0, close(fd));
return 0;
}
void *Writer(void *arg) {
int i, j, fd;
char buf[10];
kind = arg;
ASSERT_NE(-1, (fd = open("db", O_RDWR)));
for (j = 0; j < ITERATIONS; ++j) {
WriteLock(fd, 10, 10);
for (i = 0; i < 10; ++i) {
ASSERT_SYS(0, 1, pread(fd, buf + i, 1, 10 + i));
ASSERT_EQ(buf[0], buf[i]);
}
for (i = 0; i < 10; ++i) {
buf[i]++;
}
for (i = 0; i < 10; ++i) {
ASSERT_SYS(0, 1, pwrite(fd, buf + i, 1, 10 + i));
}
Unlock(fd, 10, 10);
sched_yield();
}
ASSERT_SYS(0, 0, close(fd));
return 0;
}
TEST(posixAdvisoryLocks, threadsAndProcessesFightingForLock) {
int i, rc, pid, fd, ws;
pthread_t th[THREADS + 1];
ASSERT_SYS(0, 3, creat("db", 0644));
ASSERT_SYS(0, 0, ftruncate(3, 30));
ASSERT_SYS(0, 0, close(3));
for (i = 0; i < THREADS; ++i) {
if (i % RATIO == 0) {
ASSERT_EQ(0, pthread_create(th + i, 0, Reader, "reader thread"));
} else {
ASSERT_EQ(0, pthread_create(th + i, 0, Writer, "writer thread"));
}
}
for (i = 0; i < PROCESSES; ++i) {
ASSERT_NE(-1, (rc = fork()));
if (!rc) {
if (i % RATIO == 0) {
Writer("writer process");
} else {
Reader("reader process");
}
_Exit(0);
}
}
ASSERT_NE(-1, (fd = open("db", O_RDWR)));
Lock(fd, F_WRLCK, 0, 10);
Lock(fd, F_WRLCK, 20, 10);
for (i = 0; i < THREADS; ++i) {
ASSERT_EQ(0, pthread_join(th[i], 0));
}
kind = "main process";
for (;;) {
int e = errno;
if ((pid = waitpid(0, &ws, 0)) != -1) {
if (WIFSIGNALED(ws)) {
Log("process %d terminated with %G", pid, WTERMSIG(ws));
testlib_incrementfailed();
} else if (WEXITSTATUS(ws)) {
Log("process %d exited with %d", pid, WEXITSTATUS(ws));
testlib_incrementfailed();
}
} else {
ASSERT_EQ(ECHILD, errno);
errno = e;
break;
}
}
ASSERT_SYS(0, 0, close(fd));
}

View file

@ -560,7 +560,7 @@ TEST(pledge_openbsd, bigSyscalls) {
int LockWorker(void *arg, int tid) {
flockfile(stdout);
ASSERT_EQ(gettid(), stdout->lock._owner);
ASSERT_EQ(gettid(), ((pthread_mutex_t *)stdout->lock)->_owner);
funlockfile(stdout);
return 0;
}

Some files were not shown because too many files have changed in this diff Show more