Improve synchronization

- Fix bugs in kDos2Errno definition
- malloc() should now be thread safe
- Fix bug in rollup.com header generator
- Fix open(O_APPEND) on the New Technology
- Fix select() on the New Technology and test it
- Work towards refactoring i/o for thread safety
- Socket reads and writes on NT now poll for signals
- Work towards i/o completion ports on the New Technology
- Make read() and write() intermittently check for signals
- Blinkenlights keyboard i/o so much better on NT w/ poll()
- You can now poll() files and sockets at the same time on NT
- Fix bug in appendr() that manifests with dlmalloc footers off
This commit is contained in:
Justine Tunney 2022-04-14 23:39:48 -07:00
parent 233144b19d
commit 933411ba99
266 changed files with 8761 additions and 4344 deletions

View file

@ -148,7 +148,6 @@ int munlock(const void *, size_t);
int munlockall(void);
int nice(int);
int open(const char *, int, ...);
int openanon(char *, unsigned);
int openat(int, const char *, int, ...);
int pause(void);
int personality(uint64_t);
@ -169,7 +168,7 @@ int sched_setaffinity(int, uint64_t, const void *);
int sched_yield(void);
int setegid(uint32_t);
int seteuid(uint32_t);
int setgid(uint32_t);
int setgid(int);
int setpgid(int, int);
int setpriority(int, unsigned, int);
int setregid(uint32_t, uint32_t);
@ -178,7 +177,7 @@ int setresuid(uint32_t, uint32_t, uint32_t);
int setreuid(uint32_t, uint32_t);
int setrlimit(int, const struct rlimit *);
int setsid(void);
int setuid(uint32_t);
int setuid(int);
int sigignore(int);
int siginterrupt(int, int);
int sigprocmask(int, const struct sigset *, struct sigset *);

View file

@ -65,8 +65,11 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/raise.o: \
OVERRIDE_COPTS += \
-ffreestanding \
$(NO_MAGIC)
o/$(MODE)/libc/calls/termios2linux.o \

View file

@ -16,30 +16,42 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(struct Fd *fd) {
int e;
bool32 ok;
bool ok = true;
// if this file descriptor is wrapped in a named pipe worker thread
// then we need to close our copy of the worker thread handle. it's
// also required that whatever install a worker use malloc, so free
if (fd->worker) {
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
fd->worker = 0;
}
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
GetFileType(fd->handle) == kNtFileTypeDisk)) {
/*
* Like Linux, closing a file on Windows doesn't guarantee it's
* immediately synced to disk. But unlike Linux, this could cause
* subsequent operations, e.g. unlink() to break w/ access error.
*/
// Like Linux, closing a file on Windows doesn't guarantee it's
// immediately synced to disk. But unlike Linux, this could cause
// subsequent operations, e.g. unlink() to break w/ access error.
e = errno;
FlushFileBuffers(fd->handle);
errno = e;
}
ok = CloseHandle(fd->handle);
// now we can close the handle
if (!CloseHandle(fd->handle)) ok = false;
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
ok &= CloseHandle(fd->extra);
if (!CloseHandle(fd->extra)) ok = false;
}
return ok ? 0 : -1;
}

View file

@ -73,7 +73,7 @@ int close(int fd) {
}
}
}
__releasefd(fd);
if (!__vforked) __releasefd(fd);
}
STRACE("%s(%d) → %d% m", "close", fd, rc);
return rc;

View file

@ -0,0 +1,110 @@
/*-*- 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/sysv/consts/o.h"
// code size optimization
// <sync libc/sysv/consts.sh>
#define _O_APPEND 0x00000400 // kNtFileAppendData
#define _O_CREAT 0x00000040 // kNtOpenAlways
#define _O_EXCL 0x00000080 // kNtCreateNew
#define _O_TRUNC 0x00000200 // kNtCreateAlways
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
#define _O_NDELAY 0x00000800 // kNtFileFlagWriteThrough
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
#define _O_NONBLOCK 0x00000800
#define _O_CLOEXEC 0x00080000
// </sync libc/sysv/consts.sh>
textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
uint32_t *out_share, uint32_t *out_disp,
uint32_t *out_attr) {
uint32_t perm, share, disp, attr;
switch (flags & O_ACCMODE) {
case O_RDONLY:
perm = kNtFileGenericRead | kNtGenericExecute;
break;
case O_WRONLY:
perm = kNtFileGenericWrite | kNtGenericExecute;
break;
case O_RDWR:
perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute;
break;
default:
return -1;
}
if (flags & _O_APPEND) {
perm = kNtFileAppendData;
}
if (flags & _O_EXCL) {
share = kNtFileShareExclusive;
} else {
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
}
if ((flags & _O_CREAT) && (flags & _O_EXCL)) {
disp = kNtCreateNew;
} else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) {
disp = kNtCreateAlways;
} else if (flags & _O_CREAT) {
disp = kNtOpenAlways;
} else if (flags & _O_TRUNC) {
disp = kNtTruncateExisting;
} else {
disp = kNtOpenExisting;
}
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
} else {
attr = kNtFileAttributeNormal;
if (flags & _O_DIRECTORY) {
attr |= kNtFileFlagBackupSemantics;
}
if (~mode & 0200) {
attr |= kNtFileAttributeReadonly;
}
}
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed;
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
if (out_perm) *out_perm = perm;
if (out_share) *out_share = share;
if (out_disp) *out_disp = disp;
if (out_attr) *out_attr = attr;
return 0;
}

View file

@ -16,32 +16,35 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/reverse.internal.h"
#include "libc/calls/calls.h"
#include "libc/intrin/lockxadd.h"
#include "libc/nt/process.h"
static const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\";
static textwindows size_t UintToChar16Array(char16_t *a, uint64_t i) {
size_t j = 0;
static textwindows char16_t *UintToChar16Array(char16_t p[21], uint64_t x) {
char t;
size_t a, b, i = 0;
do {
a[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
a[j] = 0;
reverse(a, j);
return j;
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
textwindows char16_t *CreatePipeName(char16_t *a) {
static long x;
unsigned i;
for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i];
i += UintToChar16Array(a + i, GetCurrentProcessId());
a[i++] = u'-';
i += UintToChar16Array(a + i, GetCurrentProcessId());
a[i++] = u'-';
i += UintToChar16Array(a + i, x++);
a[i] = u'\0';
char16_t *p = a;
const char *q = "\\\\?\\pipe\\cosmo\\";
while (*q) *p++ = *q++;
p = UintToChar16Array(p, GetCurrentProcessId());
*p++ = '-';
p = UintToChar16Array(p, _lockxadd(&x, 1));
*p = 0;
return a;
}

View file

@ -18,18 +18,21 @@
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
int prot, int flags, int fd,
int64_t off) {
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
int flags, int fd, int64_t off) {
size_t i;
bool iscow;
int64_t handle;
@ -38,6 +41,18 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
struct ProtectNt fl;
const struct NtSecurityAttributes *sec;
#ifndef NDEBUG
struct NtProcessMemoryCountersEx memcount = {
.cb = sizeof(struct NtProcessMemoryCountersEx),
};
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
if (memcount.PeakWorkingSetSize > 5ull * 1024 * 1024 * 1024) {
kprintf("error: exceeded 5gb memory limit%n");
_Exit(201);
}
}
#endif
if (fd != -1) {
handle = g_fds.p[fd].handle;
} else {

View file

@ -33,8 +33,8 @@
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*/
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {
/* asan runtime depends on this function */
struct DirectMap d;
if (!IsWindows() && !IsMetal()) {

View file

@ -24,38 +24,62 @@
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sock/ntstdin.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Implements dup(), dup2(), and dup3() for Windows NT.
* Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
*/
textwindows int sys_dup_nt(int oldfd, int newfd, int flags) {
int64_t proc;
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
int64_t proc, handle;
// validate the api usage
if (oldfd < 0) return einval();
if (flags & ~O_CLOEXEC) return einval();
if (oldfd >= g_fds.n ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) {
return ebadf();
}
// allocate a new file descriptor
if (newfd == -1) {
if ((newfd = __reservefd()) == -1) return -1;
if ((newfd = __reservefd(start)) == -1) {
return -1;
}
} else {
if (__ensurefds(newfd) == -1) return -1;
if (g_fds.p[newfd].kind) close(newfd);
g_fds.p[newfd].kind = kFdReserved;
}
// if this file descriptor is wrapped in a named pipe worker thread
// then we should clone the original authentic handle rather than the
// stdin worker's named pipe. we won't clone the worker, since that
// can always be recreated again on demand.
if (g_fds.p[oldfd].worker) {
handle = g_fds.p[oldfd].worker->reader;
} else {
handle = g_fds.p[oldfd].handle;
}
proc = GetCurrentProcess();
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
0, true, kNtDuplicateSameAccess)) {
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].flags = flags;
g_fds.p[newfd].mode = g_fds.p[oldfd].mode;
g_fds.p[newfd].flags = g_fds.p[oldfd].flags & ~O_CLOEXEC;
if (flags & O_CLOEXEC) g_fds.p[newfd].flags |= O_CLOEXEC;
if (g_fds.p[oldfd].kind == kFdSocket && weaken(_dupsockfd)) {
g_fds.p[newfd].extra =
(intptr_t)weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
} else {
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
}
if (g_fds.p[oldfd].worker) {
g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker);
}
return newfd;
} else {
__releasefd(newfd);

View file

@ -34,7 +34,7 @@ int dup(int fd) {
if (!IsWindows()) {
fd2 = sys_dup(fd);
} else {
fd2 = sys_dup_nt(fd, -1, 0);
fd2 = sys_dup_nt(fd, -1, 0, -1);
}
STRACE("%s(%d) → %d% m", "dup", fd, fd2);
return fd2;

View file

@ -38,7 +38,7 @@ int dup2(int oldfd, int newfd) {
} else if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, 0);
} else {
rc = sys_dup_nt(oldfd, newfd, 0);
rc = sys_dup_nt(oldfd, newfd, 0, -1);
}
STRACE("dup2(%d, %d) → %d% m", oldfd, newfd, rc);
return rc;

View file

@ -40,7 +40,7 @@ int dup3(int oldfd, int newfd, int flags) {
if (!IsWindows()) {
rc = sys_dup3(oldfd, newfd, flags);
} else {
rc = sys_dup_nt(oldfd, newfd, flags);
rc = sys_dup_nt(oldfd, newfd, flags, -1);
}
STRACE("dup3(%d, %d, %d) → %d% m", oldfd, newfd, flags, rc);
return rc;

View file

@ -41,9 +41,9 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = g_fds.p[0].handle;
startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle;
startinfo.hStdInput = __getfdhandleactual(0);
startinfo.hStdOutput = __getfdhandleactual(1);
startinfo.hStdError = __getfdhandleactual(2);
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
if (rc == -1) return -1;
CloseHandle(g_fds.p[0].handle);

View file

@ -17,49 +17,52 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/files.h"
#include "libc/nt/nt/file.h"
#include "libc/nt/ntdll.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/fileaccessinformation.h"
#include "libc/nt/struct/filebasicinformation.h"
#include "libc/nt/struct/iostatusblock.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_fadvise_nt(int fd, uint64_t offset, uint64_t len,
int advice) {
int64_t h2;
NtStatus status;
uint32_t sharemode;
struct NtIoStatusBlock iostatus;
struct NtFileBasicInformation basicinfo;
struct NtFileAccessInformation accessinfo;
int64_t h1, h2;
int flags, mode;
uint32_t perm, share, attr;
if (!__isfdkind(fd, kFdFile)) return ebadf();
sharemode = /* xxx: no clue how to query this */
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
/* TODO(jart): can we do it in one call w/ NtQueryObject? */
if (!NtError(status = NtQueryInformationFile(g_fds.p[fd].handle, &iostatus,
&basicinfo, sizeof(basicinfo),
kNtFileBasicInformation)) &&
!NtError(status = NtQueryInformationFile(g_fds.p[fd].handle, &iostatus,
&accessinfo, sizeof(accessinfo),
kNtFileAccessInformation))) {
if ((h2 = ReOpenFile(g_fds.p[fd].handle, accessinfo.AccessFlags, sharemode,
advice | basicinfo.FileAttributes)) != -1) {
if (h2 != g_fds.p[fd].handle) {
CloseHandle(g_fds.p[fd].handle);
g_fds.p[fd].handle = h2;
}
return 0;
h1 = g_fds.p[fd].handle;
mode = g_fds.p[fd].mode;
flags = g_fds.p[fd].flags;
flags &= ~(O_SEQUENTIAL | O_RANDOM);
switch (advice) {
case MADV_NORMAL:
break;
case MADV_RANDOM:
flags |= O_RANDOM;
break;
case MADV_SEQUENTIAL:
flags |= O_SEQUENTIAL;
break;
default:
return einval();
}
if (GetNtOpenFlags(flags, mode, &perm, &share, 0, &attr) == -1) return -1;
if ((h2 = ReOpenFile(h1, perm, share, attr)) != -1) {
if (h2 != h1) {
CloseHandle(h1);
g_fds.p[fd].handle = h2;
}
return __winerr();
} else if (status == kNtStatusDllNotFound) {
return enosys();
g_fds.p[fd].flags = flags;
return 0;
} else {
return ntreturn(status);
return __winerr();
}
}

View file

@ -20,7 +20,9 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/flock.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.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/nt/enum/filelockflags.h"
@ -38,38 +40,8 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
static textwindows int sys_fcntl_nt_reservefd(int start) {
int fd;
for (;;) {
fd = start;
if (fd >= g_fds.n) {
if (__ensurefds(fd) == -1) return -1;
}
_cmpxchg(&g_fds.f, fd, fd + 1);
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
return fd;
}
}
}
static textwindows int sys_fcntl_nt_dupfd(int oldfd, int cmd, int start) {
int newfd;
int64_t proc;
if ((newfd = sys_fcntl_nt_reservefd(start)) != -1) {
proc = GetCurrentProcess();
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc,
&g_fds.p[newfd].handle, 0, true,
kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].flags = cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0;
return newfd;
} else {
__releasefd(newfd);
return __winerr();
}
} else {
return -1;
}
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
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) {
@ -98,7 +70,7 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
}
if (!len) len = size - off;
if (off < 0 || len < 0) return einval();
_offset2overlap(off, &ov);
_offset2overlap(f->handle, off, &ov);
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
flags = 0;
if (cmd == F_SETLK) flags |= kNtLockfileFailImmediately;
@ -136,11 +108,9 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
return g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
O_NOATIME | O_NONBLOCK);
} 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
* - O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
*/
// O_APPEND doesn't appear to be tunable at cursory glance
// O_NONBLOCK might require we start doing all i/o in threads
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
return einval();
} else if (cmd == F_GETFD) {
if (g_fds.p[fd].flags & O_CLOEXEC) {

View file

@ -21,6 +21,7 @@
#include "libc/sysv/errfuns.h"
textwindows int sys_fdatasync_nt(int fd) {
// TODO(jart): what should we do with worker pipes?
if (!__isfdkind(fd, kFdFile)) return ebadf();
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
}

View file

@ -20,42 +20,32 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/fileno.h"
STATIC_YOINK("_init_g_fds");
hidden struct Fds g_fds;
struct Fds g_fds;
_Alignas(64) char __fds_lock;
static textwindows int64_t GetHandleNt(long a) {
int64_t b;
b = GetStdHandle(a);
STRACE("GetStdHandle(%ld) → %ld% m", a, b);
return b;
}
hidden textstartup void InitializeFileDescriptors(void) {
textstartup void InitializeFileDescriptors(void) {
struct Fds *fds;
fds = VEIL("r", &g_fds);
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
fds->p = fds->__init_p;
if (IsMetal()) {
pushmov(&fds->f, 3ull);
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdSerial);
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdSerial);
fds->__init_p[STDERR_FILENO].kind = pushpop(kFdSerial);
fds->__init_p[STDIN_FILENO].handle = VEIL("r", 0x3F8ull);
fds->__init_p[STDOUT_FILENO].handle = VEIL("r", 0x3F8ull);
fds->__init_p[STDERR_FILENO].handle = VEIL("r", 0x3F8ull);
fds->__init_p[0].kind = pushpop(kFdSerial);
fds->__init_p[1].kind = pushpop(kFdSerial);
fds->__init_p[2].kind = pushpop(kFdSerial);
fds->__init_p[0].handle = VEIL("r", 0x3F8ull);
fds->__init_p[1].handle = VEIL("r", 0x3F8ull);
fds->__init_p[2].handle = VEIL("r", 0x3F8ull);
} else if (IsWindows()) {
pushmov(&fds->f, 3ull);
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdFile);
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdFile);
fds->__init_p[STDERR_FILENO].kind = pushpop(kFdFile);
fds->__init_p[STDIN_FILENO].handle =
GetHandleNt(pushpop(kNtStdInputHandle));
fds->__init_p[STDOUT_FILENO].handle =
GetHandleNt(pushpop(kNtStdOutputHandle));
fds->__init_p[STDERR_FILENO].handle =
GetHandleNt(pushpop(kNtStdErrorHandle));
fds->__init_p[0].kind = pushpop(kFdFile);
fds->__init_p[1].kind = pushpop(kFdFile);
fds->__init_p[2].kind = pushpop(kFdFile);
fds->__init_p[0].handle = GetStdHandle(pushpop(kNtStdInputHandle));
fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle));
fds->__init_p[2].handle = GetStdHandle(pushpop(kNtStdErrorHandle));
}
}

View file

@ -18,6 +18,6 @@
*/
#include "libc/calls/internal.h"
cthread_spinlock_t __sig_lock;
_Alignas(64) char __sig_lock;
unsigned __sighandrvas[NSIG];
unsigned __sighandflags[NSIG];

View file

@ -1,7 +1,7 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
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
@ -16,48 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/calls/strace.internal.h"
static void __ensurefds_destroy(void) {
weaken(free)(g_fds.p);
}
int __ensurefds(int fd) {
size_t n1, n2;
struct Fd *p1, *p2;
for (;;) {
p1 = g_fds.p;
n1 = g_fds.n;
if (fd < n1) return fd;
if (weaken(malloc)) {
n2 = MAX(fd + 1, n1 + (n1 << 1));
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
memcpy(p2, p1, n1 * sizeof(*p1));
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
if (_cmpxchg(&g_fds.p, p1, p2)) {
g_fds.n = n2;
if (weaken(free)) {
if (p1 == g_fds.__init_p) {
atexit(__ensurefds_destroy);
} else {
weaken(free)(p1);
}
}
return fd;
} else if (weaken(free)) {
weaken(free)(p2);
}
} else {
return enomem();
}
} else {
return emfile();
}
}
/**
* Returns effective user ID of calling process.
*/
uint32_t geteuid(void) {
int rc;
rc = sys_geteuid();
STRACE("%s() → %d% m", "geteuid", rc);
return rc;
}

View file

@ -1,7 +1,7 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
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
@ -17,10 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/sock/ntstdin.internal.h"
hidden const struct NtSecurityAttributes kNtIsInheritable = {
sizeof(struct NtSecurityAttributes),
NULL,
true,
};
int64_t __getfdhandleactual(int fd) {
if (g_fds.p[fd].worker) {
return g_fds.p[fd].worker->reader;
} else {
return g_fds.p[fd].handle;
}
}

View file

@ -47,6 +47,8 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
} else {
return __winerr();
}
bzero(&memcount, sizeof(memcount));
memcount.cb = sizeof(struct NtProcessMemoryCountersEx);
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
usage->ru_maxrss = memcount.PeakWorkingSetSize / 1024;
usage->ru_majflt = memcount.PageFaultCount;

View file

@ -16,11 +16,11 @@
#include "libc/calls/struct/winsize.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/struct/context.h"
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/systeminfo.h"
@ -58,8 +58,10 @@ enum FdKind {
struct Fd {
enum FdKind kind;
unsigned flags;
unsigned mode;
int64_t handle;
int64_t extra;
struct NtStdinWorker *worker;
bool zombie;
};
@ -73,16 +75,19 @@ struct Fds {
extern const struct Fd kEmptyFd;
hidden extern int __vforked;
hidden extern char __fds_lock;
hidden extern char __sig_lock;
hidden extern bool __time_critical;
hidden extern cthread_spinlock_t __sig_lock;
hidden extern unsigned __sighandrvas[NSIG];
hidden extern unsigned __sighandflags[NSIG];
hidden extern struct Fds g_fds;
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
int __reservefd(void) hidden;
int __reservefd(int) hidden;
void __releasefd(int) hidden;
int __ensurefds(int) hidden;
int64_t __getfdhandleactual(int) hidden;
void __printfds(void);
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
@ -178,6 +183,7 @@ i32 sys_posix_openpt(i32) hidden;
i32 sys_renameat(i32, const char *, i32, const char *) hidden;
i32 sys_sched_setaffinity(i32, u64, const void *) hidden;
i32 sys_sched_yield(void) hidden;
i32 sys_setgid(i32) hidden;
i32 sys_setitimer(i32, const struct itimerval *, struct itimerval *) hidden;
i32 sys_setpgid(i32, i32) hidden;
i32 sys_setpriority(i32, u32, i32) hidden;
@ -185,6 +191,7 @@ i32 sys_setresgid(uint32_t, uint32_t, uint32_t) hidden;
i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden;
i32 sys_setrlimit(i32, const struct rlimit *) hidden;
i32 sys_setsid(void) hidden;
i32 sys_setuid(i32) hidden;
i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden;
i32 sys_sigaltstack(const void *, void *) hidden;
i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
@ -216,6 +223,7 @@ i64 sys_sendfile(i32, i32, i64 *, u64) hidden;
i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden;
i64 sys_write(i32, const void *, u64) hidden;
u32 sys_geteuid(void) hidden;
u32 sys_getgid(void) hidden;
u32 sys_getsid(int) hidden;
u32 sys_gettid(void) hidden;
@ -266,7 +274,7 @@ i64 sys_lseek_nt(int, i64, int) hidden;
int sys_chdir_nt(const char *) hidden;
int sys_close_epoll_nt(int) hidden;
int sys_close_nt(struct Fd *) hidden;
int sys_dup_nt(int, int, int) hidden;
int sys_dup_nt(int, int, int, int) hidden;
int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;
int sys_fadvise_nt(int, u64, u64, int) hidden;
@ -331,12 +339,13 @@ int64_t __winerr(void) nocallback privileged;
int64_t ntreturn(uint32_t);
ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int) hidden;
ssize_t sys_writev_nt(int, const struct iovec *, int) hidden;
struct NtOverlapped *_offset2overlap(int64_t, struct NtOverlapped *) hidden;
unsigned __wincrash_nt(struct NtExceptionPointers *);
void *GetProcAddressModule(const char *, const char *) hidden;
void WinMainForked(void) hidden;
void _ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
void _ntlinux2context(struct NtContext *, const ucontext_t *) hidden;
struct NtOverlapped *_offset2overlap(int64_t, int64_t,
struct NtOverlapped *) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » metal

View file

@ -92,4 +92,6 @@ static textstartup void LoadavgNtInit(void) {
LoadavgNtPoll(hCounter, 0);
}
const void *const LoadavgNtCtor[] initarray = {LoadavgNtInit};
const void *const LoadavgNtCtor[] initarray = {
LoadavgNtInit,
};

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nt/ipc.h"
@ -33,11 +34,15 @@
* @asyncsignalsafe
*/
int mkfifo(const char *pathname, unsigned mode) {
/* TODO(jart): Windows? */
if (IsAsan() && !__asan_is_valid(pathname, 1)) return efault();
if (IsLinux()) {
return sys_mknod(pathname, mode | S_IFIFO, 0);
// TODO(jart): Windows?
int rc;
if (IsAsan() && !__asan_is_valid(pathname, 1)) {
rc = efault();
} else if (IsLinux()) {
rc = sys_mknod(pathname, mode | S_IFIFO, 0);
} else {
return sys_mkfifo(pathname, mode);
rc = sys_mkfifo(pathname, mode);
}
STRACE("mkfifo(%#s, %#o) → %d% m", pathname, mode, rc);
return rc;
}

View file

@ -49,10 +49,8 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
} else {
slice = ms;
}
if (!__time_critical) {
STRACE("SleepEx(%u, true)", slice);
}
if (SleepEx(slice, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
rc = eintr();
break;
}

View file

@ -18,9 +18,9 @@
*/
#include "libc/calls/internal.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/str/str.h"
textwindows struct NtOverlapped *_offset2overlap(int64_t opt_offset,
textwindows struct NtOverlapped *_offset2overlap(int64_t handle,
int64_t opt_offset,
struct NtOverlapped *mem) {
if (opt_offset == -1) return NULL;
bzero(mem, sizeof(struct NtOverlapped));

View file

@ -36,89 +36,12 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#define _O_APPEND 0x00000400 /* kNtFileAppendData */
#define _O_CREAT 0x00000040 /* kNtOpenAlways */
#define _O_EXCL 0x00000080 /* kNtCreateNew */
#define _O_TRUNC 0x00000200 /* kNtCreateAlways */
#define _O_DIRECTORY 0x00010000 /* kNtFileFlagBackupSemantics */
#define _O_TMPFILE 0x00410000 /* AttributeTemporary|FlagDeleteOnClose */
#define _O_DIRECT 0x00004000 /* kNtFileFlagNoBuffering */
#define _O_NDELAY 0x00000800 /* kNtFileFlagWriteThrough */
#define _O_RANDOM 0x80000000 /* kNtFileFlagRandomAccess */
#define _O_SEQUENTIAL 0x40000000 /* kNtFileFlagSequentialScan */
#define _O_COMPRESSED 0x20000000 /* kNtFileAttributeCompressed */
#define _O_INDEXED 0x10000000 /* !kNtFileAttributeNotContentIndexed */
#define _O_NONBLOCK 0x00000800
#define _O_CLOEXEC 0x00080000
static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
uint32_t flags, int32_t mode) {
int64_t handle;
uint32_t br, err;
char16_t path16[PATH_MAX];
uint32_t perm, share, disp, attr;
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
switch (flags & O_ACCMODE) {
case O_RDONLY:
perm = kNtFileGenericRead | kNtGenericExecute;
break;
case O_WRONLY:
perm = kNtFileGenericWrite | kNtGenericExecute;
break;
case O_RDWR:
perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute;
break;
default:
unreachable;
}
if (flags & _O_EXCL) {
share = kNtFileShareExclusive;
} else {
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
}
if ((flags & _O_CREAT) && (flags & _O_EXCL)) {
disp = kNtCreateNew;
} else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) {
disp = kNtCreateAlways;
} else if (flags & _O_CREAT) {
disp = kNtOpenAlways;
} else if (flags & _O_TRUNC) {
disp = kNtTruncateExisting;
} else {
disp = kNtOpenExisting;
}
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
} else {
attr = kNtFileAttributeNormal;
if (flags & _O_DIRECTORY) attr |= kNtFileFlagBackupSemantics;
if (~mode & 0200) {
attr |= kNtFileAttributeReadonly;
if (!IsTiny() && disp == kNtCreateAlways) {
// iron out esoteric unix/win32 inconsistency (golang #38225)
if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable,
kNtTruncateExisting, kNtFileAttributeNormal,
0)) != -1 ||
(errno != ENOENT && errno != ENOTDIR)) {
return handle;
}
}
}
}
flags |= kNtFileFlagOverlapped;
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed;
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
if (GetNtOpenFlags(flags, mode, &perm, &share, &disp, &attr) == -1) return -1;
return CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, 0);
}
@ -141,6 +64,7 @@ static textwindows ssize_t sys_open_nt_console(int dirfd,
}
g_fds.p[fd].kind = kFdConsole;
g_fds.p[fd].flags = flags;
g_fds.p[fd].mode = mode;
return fd;
}
@ -150,6 +74,7 @@ static textwindows ssize_t sys_open_nt_file(int dirfd, const char *file,
if ((g_fds.p[fd].handle = sys_open_nt_impl(dirfd, file, flags, mode)) != -1) {
g_fds.p[fd].kind = kFdFile;
g_fds.p[fd].flags = flags;
g_fds.p[fd].mode = mode;
return fd;
} else {
return -1;
@ -160,7 +85,7 @@ textwindows ssize_t sys_open_nt(int dirfd, const char *file, uint32_t flags,
int32_t mode) {
int fd;
ssize_t rc;
if ((fd = __reservefd()) == -1) return -1;
if ((fd = __reservefd(-1)) == -1) return -1;
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
} else {

View file

@ -1,99 +0,0 @@
/*-*- 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 2020 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/str/path.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
static struct OpenAnon { int count; } g_openanon;
static void openanon_genpath(const char *name, struct OpenAnon *state,
char pathbuf[hasatleast PATH_MAX]) {
char c;
size_t i;
char *p, *pe;
p = stpcpy(pathbuf, kTmpPath);
pe = pathbuf + PATH_MAX - 8 - 10 - 1 - 10 - 1;
if (!name) name = "openanon";
for (i = 0; p < pe; ++i) {
if (!(c = name[i])) break;
if (_isdirsep(c)) c = '_';
*p++ = c;
}
*p++ = '.';
p += uint64toarray_radix10(getpid(), p);
*p++ = '.';
p += uint64toarray_radix10(++state->count, p);
*p = '\0';
assert(p < pe);
}
static int openanon_impl(const char *name, unsigned flags,
struct OpenAnon *state,
char pathbuf[hasatleast PATH_MAX]) {
int fd;
openanon_genpath(name, state, pathbuf);
flags |= O_RDWR | O_CREAT | O_EXCL | O_TRUNC;
if (!IsWindows()) {
if ((fd = sys_openat(AT_FDCWD, pathbuf, flags, 0600)) != -1) {
unlink(pathbuf);
}
return fd;
} else {
if ((fd = __reservefd()) == -1) return -1;
if ((g_fds.p[fd].handle = CreateFileA(
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
&kNtIsInheritable, kNtCreateAlways,
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose),
0)) != -1) {
g_fds.p[fd].kind = kFdFile;
g_fds.p[fd].flags = flags;
return fd;
} else {
__releasefd(fd);
return __winerr();
}
}
}
/**
* Creates anonymous file.
*
* @param name is purely informative
* @param flags can have O_CLOEXEC
* @return fd of file with no name, needing close(), or -1 w/ errno
* @see memfd_create() if disk-paranoid
* @see mkostempsm() for named files
*/
int openanon(char *name, unsigned flags) {
char pathbuf[PATH_MAX];
return openanon_impl(name, flags, &g_openanon, pathbuf);
}

View file

@ -29,12 +29,13 @@ int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
struct MetalFile *state;
if (strcmp(file, "ape.com")) return enoent();
if (!weaken(calloc)) return enomem();
if ((fd = __reservefd()) == -1) return -1;
if ((fd = __reservefd(-1)) == -1) return -1;
state = weaken(calloc)(1, sizeof(struct MetalFile));
state->base = (char *)_base;
state->size = _end - _base;
g_fds.p[fd].kind = kFdFile;
g_fds.p[fd].flags = flags;
g_fds.p[fd].mode = mode;
g_fds.p[fd].handle = (intptr_t)state;
return fd;
}

View file

@ -20,31 +20,41 @@
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/ipc.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
uint32_t mode;
int64_t hin, hout;
int reader, writer;
char16_t pipename[64];
if (!pipefd) return efault();
CreatePipeName(pipename);
if ((reader = __reservefd()) == -1) return -1;
if ((writer = __reservefd()) == -1) {
if ((reader = __reservefd(-1)) == -1) return -1;
if ((writer = __reservefd(-1)) == -1) {
__releasefd(reader);
return -1;
}
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
0, &kNtIsInheritable)) != -1) {
if (~flags & O_DIRECT) {
mode = kNtPipeTypeByte | kNtPipeReadmodeByte;
} else {
mode = kNtPipeTypeMessage | kNtPipeReadmodeMessage;
}
if ((hin = CreateNamedPipe(pipename,
kNtPipeAccessInbound | kNtFileFlagOverlapped, mode,
1, 512, 512, 0, &kNtIsInheritable)) != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable,
kNtOpenExisting, 0, 0)) != -1) {
kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) {
g_fds.p[reader].kind = kFdFile;
g_fds.p[reader].flags = flags;
g_fds.p[reader].mode = 0010444;
g_fds.p[reader].handle = hin;
g_fds.p[writer].kind = kFdFile;
g_fds.p[writer].flags = flags;
g_fds.p[writer].mode = 0010222;
g_fds.p[writer].handle = hout;
pipefd[0] = reader;
pipefd[1] = writer;

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
@ -31,10 +32,18 @@
* @see pipe2()
*/
int pipe(int pipefd[hasatleast 2]) {
if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) return efault();
if (!IsWindows()) {
return sys_pipe(pipefd);
int rc;
if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pipe(pipefd);
} else {
return sys_pipe_nt(pipefd, 0);
rc = sys_pipe_nt(pipefd, 0);
}
if (!rc) {
STRACE("pipe([{%d, %d}]) → %d% m", pipefd[0], pipefd[1], rc);
} else {
STRACE("pipe(%p) → %d% m", pipefd, rc);
}
return rc;
}

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
@ -29,11 +30,20 @@
* @return 0 on success, or -1 w/ errno and pipefd isn't modified
*/
int pipe2(int pipefd[hasatleast 2], int flags) {
if (!pipefd) return efault();
if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) return efault();
if (!IsWindows()) {
return sys_pipe2(pipefd, flags);
int rc;
if (!pipefd) {
rc = efault();
} else if (IsAsan() && !__asan_is_valid(pipefd, sizeof(int) * 2)) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_pipe2(pipefd, flags);
} else {
return sys_pipe_nt(pipefd, flags);
rc = sys_pipe_nt(pipefd, flags);
}
if (!rc) {
STRACE("pipe2([{%d, %d}], %#o) → %d% m", pipefd[0], pipefd[1], flags, rc);
} else {
STRACE("pipe2(%p, %#o) → %d% m", pipefd, flags, rc);
}
return rc;
}

58
libc/calls/printfds.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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/internal.h"
#include "libc/intrin/kprintf.h"
static const char *__fdkind2str(int x) {
switch (x) {
case kFdEmpty:
return "kFdEmpty";
case kFdFile:
return "kFdFile";
case kFdSocket:
return "kFdSocket";
case kFdProcess:
return "kFdProcess";
case kFdConsole:
return "kFdConsole";
case kFdSerial:
return "kFdSerial";
case kFdZip:
return "kFdZip";
case kFdEpoll:
return "kFdEpoll";
default:
return "kFdWut";
}
}
void __printfds(void) {
int i;
for (i = 0; i < g_fds.n; ++i) {
if (!g_fds.p[i].kind) continue;
kprintf("%3d %s", i, __fdkind2str(g_fds.p[i].kind));
if (g_fds.p[i].zombie) kprintf(" zombie");
if (g_fds.p[i].flags) kprintf(" flags=%#x", g_fds.p[i].flags);
if (g_fds.p[i].mode) kprintf(" mode=%#o", g_fds.p[i].mode);
if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle);
if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra);
if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker);
kprintf("%n", g_fds.p[i].zombie);
}
}

View file

@ -23,6 +23,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/console.h"
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
@ -65,7 +66,9 @@ int raise(int sig) {
// doesn't make any sense and it's so evil.
if (GenerateConsoleCtrlEvent(event, 0)) {
// XXX: we shouldn't need to sleep here ctrl-c is evil on nt
SleepEx(100, false);
if (SleepEx(100, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
}
__sig_check(false);
rc = 0;
} else {

View file

@ -20,30 +20,48 @@
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/ipc.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/synchronization.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
size_t size, ssize_t offset) {
uint32_t got;
uint32_t err, got, avail;
struct NtOverlapped overlap;
if (ReadFile(fd->handle, data, _clampio(size), &got,
_offset2overlap(offset, &overlap))) {
return got;
} else if (
// make sure read() returns 0 on broken pipe
GetLastError() == kNtErrorBrokenPipe ||
// make sure pread() returns 0 if we start reading after EOF
GetLastError() == kNtErrorHandleEof) {
return 0;
} else {
return __winerr();
if (fd->worker) {
for (;;) {
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
if (avail) break;
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion ||
_check_interrupts(true, g_fds.p)) {
return eintr();
}
}
}
if (ReadFile(fd->handle, data, _clampio(size), &got,
_offset2overlap(fd->handle, offset, &overlap))) {
return got;
}
err = GetLastError();
// make sure read() returns 0 on broken pipe
if (err == kNtErrorBrokenPipe) return 0;
// make sure read() returns 0 on closing named pipe
if (err == kNtErrorNoData) return 0;
// make sure pread() returns 0 if we start reading after EOF
if (err == kNtErrorHandleEof) return 0;
return __winerr();
}
textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,

View file

@ -23,6 +23,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"

View file

@ -28,7 +28,7 @@ textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov,
case kFdConsole:
return sys_read_nt(fd, iov, iovlen, -1);
case kFdSocket:
return weaken(sys_recvfrom_nt)(fd, iov, iovlen, 0, NULL, 0);
return weaken(sys_recv_nt)(fd, iov, iovlen, 0);
default:
return ebadf();
}

View file

@ -37,7 +37,9 @@ static int GetFirstIov(struct iovec *iov, int iovlen) {
ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i;
if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) asm("pause");
while (!IsDataAvailable(fd)) {
__builtin_ia32_pause();
}
((char *)iov[i].iov_base)[0] = inb(fd->handle);
return 1;
} else {

View file

@ -17,16 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
void __releasefd(int fd) {
int x;
if (!__vforked && 0 <= fd && fd < g_fds.n) {
bzero(g_fds.p + fd, sizeof(*g_fds.p));
do {
x = g_fds.f;
if (fd >= x) break;
} while (!_lockcmpxchg(&g_fds.f, x, fd));
if (0 <= fd && fd < g_fds.n) {
_spinlock(&__fds_lock);
g_fds.p[fd].kind = 0;
g_fds.f = MIN(fd, g_fds.f);
_spunlock(&__fds_lock);
}
}

View file

@ -16,24 +16,98 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Grows file descriptor array memory if needed.
*/
int __ensurefds(int fd) {
size_t n1, n2;
struct Fd *p1, *p2;
_spinlock(&__fds_lock);
n1 = g_fds.n;
if (fd >= n1) {
STRACE("__ensurefds(%d) extending", fd);
if (weaken(malloc)) {
// TODO(jart): we need a semaphore for this
p1 = g_fds.p;
n2 = fd + (fd >> 1);
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
memcpy(p2, p1, n1 * sizeof(*p1));
g_fds.p = p2;
g_fds.n = n2;
if (p1 != g_fds.__init_p) {
weaken(free)(p1);
}
} else {
fd = enomem();
}
} else {
fd = emfile();
}
}
_spunlock(&__fds_lock);
return fd;
}
/**
* Finds open file descriptor slot.
*/
int __reservefd(void) {
int __reservefd(int start) {
int fd;
for (;;) {
fd = g_fds.f;
if (fd >= g_fds.n) {
if (__ensurefds(fd) == -1) return -1;
}
_cmpxchg(&g_fds.f, fd, fd + 1);
if (_cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
_spinlock(&__fds_lock);
fd = start < 0 ? g_fds.f : start;
while (fd < g_fds.n && g_fds.p[fd].kind) ++fd;
if (fd < g_fds.n) {
g_fds.f = fd + 1;
bzero(g_fds.p + fd, sizeof(*g_fds.p));
g_fds.p[fd].kind = kFdReserved;
_spunlock(&__fds_lock);
return fd;
} else {
_spunlock(&__fds_lock);
if (__ensurefds(fd) == -1) {
return -1;
}
}
}
}
/**
* Closes non-stdio file descriptors to free dynamic memory.
*/
static void __freefds(void) {
int i;
STRACE("__freefds()");
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind) {
close(i);
}
}
if (g_fds.p != g_fds.__init_p) {
memcpy(g_fds.__init_p, g_fds.p, sizeof(*g_fds.p) * 3);
weaken(free)(g_fds.p);
g_fds.p = g_fds.__init_p;
g_fds.n = ARRAYLEN(g_fds.__init_p);
}
}
static textstartup void __freefds_init(void) {
atexit(__freefds);
}
const void *const __freefds_ctor[] initarray = {
__freefds_init,
};

32
libc/calls/setgid.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Sets effective group id of current process.
* @return 0 on success or -1 w/ errno
*/
int setgid(int gid) {
int rc;
rc = sys_setgid(gid);
STRACE("%s(%d) → %d% m", "setgid", gid);
return rc;
}

32
libc/calls/setuid.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- 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/internal.h"
#include "libc/calls/strace.internal.h"
/**
* Sets effective group id of current process.
* @return 0 on success or -1 w/ errno
*/
int setuid(int uid) {
int rc;
rc = sys_setuid(uid);
STRACE("%s(%d) → %d% m", "setuid", uid);
return rc;
}

View file

@ -38,7 +38,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
int i;
uint64_t a, b;
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
if (old) {
*old = __sig.mask;
}
@ -54,7 +54,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
}
__sig.mask.__bits[0] &= ~(SIGKILL | SIGSTOP);
}
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
return 0;
} else {
return einval();

View file

@ -64,7 +64,7 @@ static textwindows void __sig_free(struct Signal *mem) {
static textwindows struct Signal *__sig_remove(void) {
struct Signal *prev, *res;
if (__sig.queue) {
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
if (!sigismember(&__sig.mask, res->sig)) {
if (res == __sig.queue) {
@ -78,7 +78,7 @@ static textwindows struct Signal *__sig_remove(void) {
STRACE("%G is masked", res->sig);
}
}
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
} else {
res = 0;
}
@ -97,7 +97,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
STRACE("delivering %G", sig);
// enter the signal
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
rva = __sighandrvas[sig];
flags = __sighandflags[sig];
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
@ -108,7 +108,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
// signal handler. in that case you must use SA_NODEFER.
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
// setup the somewhat expensive information args
// only if they're requested by the user in sigaction()
@ -130,9 +130,9 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
// since sigaction() is @asyncsignalsafe we only restore it if the
// user didn't change it during the signal handler. we also don't
// need to do anything if this was a oneshot signal or nodefer.
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
}
if (!restartable) {
@ -192,9 +192,9 @@ textwindows bool __sig_handle(bool restartable, int sig, int si_code,
textwindows int __sig_raise(int sig, int si_code) {
int rc;
int candeliver;
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
candeliver = !sigismember(&__sig.mask, sig);
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
switch (candeliver) {
case 1:
__sig_handle(false, sig, si_code, 0);
@ -217,7 +217,7 @@ textwindows int __sig_add(int sig, int si_code) {
struct Signal *mem;
if (1 <= sig && sig <= NSIG) {
STRACE("enqueuing %G", sig);
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
if ((mem = __sig_alloc())) {
mem->sig = sig;
mem->si_code = si_code;
@ -227,7 +227,7 @@ textwindows int __sig_add(int sig, int si_code) {
} else {
rc = enomem();
}
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
} else {
rc = einval();
}

View file

@ -213,7 +213,7 @@ static int __sigaction(int sig, const struct sigaction *act,
rc = 0;
}
if (rc != -1 && !__vforked) {
cthread_spinlock(&__sig_lock);
_spinlock(&__sig_lock);
if (oldact) {
oldrva = __sighandrvas[sig];
oldact->sa_sigaction = (sigaction_f)(
@ -223,7 +223,7 @@ static int __sigaction(int sig, const struct sigaction *act,
__sighandrvas[sig] = rva;
__sighandflags[sig] = act->sa_flags;
}
cthread_spunlock(&__sig_lock);
_spunlock(&__sig_lock);
}
return rc;
}

View file

@ -26,6 +26,7 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
@ -76,7 +77,11 @@ int sigsuspend(const sigset_t *ignore) {
rc = eintr();
break;
}
SleepEx(__SIG_POLLING_INTERVAL_MS, true);
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
STRACE("IOCP TRIGGERED EINTR");
rc = eintr();
break;
}
#ifdef SYSDEBUG
ms += __SIG_POLLING_INTERVAL_MS;
if (ms >= __SIG_LOGGING_INTERVAL_MS) {

View file

@ -67,7 +67,7 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
if (!__isfdopen(pid) &&
(handle = OpenProcess(kNtSynchronize | kNtProcessQueryInformation,
true, pid))) {
if ((pid = __reservefd()) != -1) {
if ((pid = __reservefd(-1)) != -1) {
g_fds.p[pid].kind = kFdProcess;
g_fds.p[pid].handle = handle;
g_fds.p[pid].flags = O_CLOEXEC;
@ -111,6 +111,8 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus,
}
if (opt_out_rusage) {
bzero(opt_out_rusage, sizeof(*opt_out_rusage));
bzero(&memcount, sizeof(memcount));
memcount.cb = sizeof(struct NtProcessMemoryCountersEx);
if (GetProcessMemoryInfo(handles[i], &memcount, sizeof(memcount))) {
opt_out_rusage->ru_maxrss = memcount.PeakWorkingSetSize / 1024;
opt_out_rusage->ru_majflt = memcount.PageFaultCount;

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"

View file

@ -19,6 +19,8 @@
#include "libc/macros.internal.h"
.init.start 300,_init_wincrash
mov __wincrashearly(%rip),%rcx
ntcall __imp_RemoveVectoredExceptionHandler
pushpop 1,%rcx
ezlea __wincrash_nt,dx
ntcall __imp_AddVectoredExceptionHandler

View file

@ -0,0 +1,20 @@
/*-*- 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.
*/
int64_t __wincrashearly;

View file

@ -23,12 +23,14 @@
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/runtime/internal.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
@ -36,17 +38,20 @@
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
ssize_t offset) {
uint32_t sent;
uint32_t err, sent;
struct NtOverlapped overlap;
if (WriteFile(g_fds.p[fd].handle, data, _clampio(size), &sent,
_offset2overlap(offset, &overlap))) {
_offset2overlap(g_fds.p[fd].handle, offset, &overlap))) {
return sent;
} else if (GetLastError() == kNtErrorBrokenPipe) {
}
err = GetLastError();
// make sure write() raises SIGPIPE on broken pipe
// make sure write() raises SIGPIPE on closing named pipe
if (err == kNtErrorBrokenPipe || err == kNtErrorNoData) {
__sig_raise(SIGPIPE, SI_KERNEL);
return epipe();
} else {
return __winerr();
}
return __winerr();
}
textwindows ssize_t sys_write_nt(int fd, const struct iovec *iov, size_t iovlen,

View file

@ -27,7 +27,7 @@ textwindows ssize_t sys_writev_nt(int fd, const struct iovec *iov, int iovlen) {
case kFdConsole:
return sys_write_nt(fd, iov, iovlen, -1);
case kFdSocket:
return weaken(sys_sendto_nt)(fd, iov, iovlen, 0, NULL, 0);
return weaken(sys_send_nt)(fd, iov, iovlen, 0);
default:
return ebadf();
}

View file

@ -24,7 +24,9 @@ ssize_t sys_writev_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i, j, wrote = 0;
for (i = 0; i < iovlen; ++i) {
for (j = 0; j < iov[i].iov_len; ++j) {
while (!(inb(fd->handle + UART_LSR) & UART_TTYTXR)) asm("pause");
while (!(inb(fd->handle + UART_LSR) & UART_TTYTXR)) {
__builtin_ia32_pause();
}
outb(fd->handle, ((char *)iov[i].iov_base)[j]);
++wrote;
}