mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Rewrite special file handling on Windows
This change gets GNU grep working. What caused it to not work, is it wouldn't write to an output file descriptor when its dev/ino equaled /dev/null's. So now we invent special dev/ino values for these files
This commit is contained in:
parent
aca2261cda
commit
2db2f40a98
53 changed files with 485 additions and 299 deletions
|
@ -33,9 +33,7 @@
|
|||
* @noreturn
|
||||
*/
|
||||
wontreturn void abort(void) {
|
||||
sigset_t m;
|
||||
sigemptyset(&m);
|
||||
sigaddset(&m, SIGABRT);
|
||||
sigset_t m = 1ull << (SIGABRT - 1);
|
||||
sigprocmask(SIG_UNBLOCK, &m, 0);
|
||||
raise(SIGABRT);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
|
|
|
@ -321,63 +321,18 @@ 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_setfl(int fd, unsigned *flags,
|
||||
unsigned mode, unsigned arg,
|
||||
intptr_t *handle) {
|
||||
|
||||
// you may change the following:
|
||||
//
|
||||
// - O_NONBLOCK make read() raise EAGAIN
|
||||
// - O_APPEND for toggling append mode
|
||||
// - O_RANDOM alt. for posix_fadvise()
|
||||
// - O_SEQUENTIAL alt. for posix_fadvise()
|
||||
// - O_DIRECT works but haven't tested
|
||||
//
|
||||
// the other bits are ignored.
|
||||
unsigned allowed = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT | O_NONBLOCK;
|
||||
unsigned needreo = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT;
|
||||
unsigned newflag = (*flags & ~allowed) | (arg & allowed);
|
||||
|
||||
if ((*flags & needreo) ^ (arg & needreo)) {
|
||||
unsigned perm, share, attr;
|
||||
if (GetNtOpenFlags(newflag, mode, &perm, &share, 0, &attr) == -1) {
|
||||
return -1;
|
||||
}
|
||||
// MSDN says only these are allowed, otherwise it returns EINVAL.
|
||||
attr &= kNtFileFlagBackupSemantics | kNtFileFlagDeleteOnClose |
|
||||
kNtFileFlagNoBuffering | kNtFileFlagOpenNoRecall |
|
||||
kNtFileFlagOpenReparsePoint | kNtFileFlagOverlapped |
|
||||
kNtFileFlagPosixSemantics | kNtFileFlagRandomAccess |
|
||||
kNtFileFlagSequentialScan | kNtFileFlagWriteThrough;
|
||||
intptr_t hand;
|
||||
if ((hand = ReOpenFile(*handle, perm, share, attr)) != -1) {
|
||||
if (hand != *handle) {
|
||||
CloseHandle(*handle);
|
||||
*handle = hand;
|
||||
}
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
// 1. ignore flags that aren't access mode flags
|
||||
// 2. return zero if nothing's changed
|
||||
*flags = newflag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
BLOCK_SIGNALS;
|
||||
if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdSocket) || //
|
||||
__isfdkind(fd, kFdConsole)) {
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdDevNull)) {
|
||||
if (cmd == F_GETFL) {
|
||||
rc = g_fds.p[fd].flags & (O_ACCMODE | O_APPEND | O_DIRECT | O_NONBLOCK |
|
||||
O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
rc = sys_fcntl_nt_setfl(fd, &g_fds.p[fd].flags, g_fds.p[fd].mode, arg,
|
||||
&g_fds.p[fd].handle);
|
||||
rc = sys_fcntl_nt_setfl(fd, arg);
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
rc = FD_CLOEXEC;
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/fmt/wintime.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
|
@ -76,13 +78,47 @@ static textwindows long GetSizeOfReparsePoint(int64_t fh) {
|
|||
return z;
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt(int64_t handle, struct stat *out_st) {
|
||||
static textwindows int sys_fstat_nt_socket(int kind, struct stat *st) {
|
||||
bzero(st, sizeof(*st));
|
||||
st->st_blksize = 512;
|
||||
st->st_mode = S_IFSOCK | 0666;
|
||||
st->st_dev = 0x44444444;
|
||||
st->st_ino = kind;
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt_special(int kind, struct stat *st) {
|
||||
bzero(st, sizeof(*st));
|
||||
st->st_blksize = 512;
|
||||
st->st_mode = S_IFCHR | 0666;
|
||||
st->st_dev = 0x77777777;
|
||||
st->st_ino = kind;
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt(int fd, struct stat *st) {
|
||||
if (fd + 0u >= g_fds.n) return ebadf();
|
||||
switch (g_fds.p[fd].kind) {
|
||||
case kFdEmpty:
|
||||
return ebadf();
|
||||
case kFdConsole:
|
||||
case kFdDevNull:
|
||||
return sys_fstat_nt_special(g_fds.p[fd].kind, st);
|
||||
case kFdSocket:
|
||||
return sys_fstat_nt_socket(g_fds.p[fd].kind, st);
|
||||
default:
|
||||
return sys_fstat_nt_handle(g_fds.p[fd].handle, st);
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_fstat_nt_handle(int64_t handle, struct stat *out_st) {
|
||||
struct stat st = {0};
|
||||
|
||||
// Always set st_blksize to avoid divide by zero issues.
|
||||
// The Linux kernel sets this for /dev/tty and similar too.
|
||||
// TODO(jart): GetVolumeInformationByHandle?
|
||||
st.st_blksize = 4096;
|
||||
st.st_gid = st.st_uid = sys_getuid_nt();
|
||||
|
||||
// We'll use the "umask" to fake out the mode bits.
|
||||
uint32_t umask = atomic_load_explicit(&__umask, memory_order_acquire);
|
||||
|
@ -92,9 +128,13 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *out_st) {
|
|||
break;
|
||||
case kNtFileTypeChar:
|
||||
st.st_mode = S_IFCHR | (0666 & ~umask);
|
||||
st.st_dev = 0x66666666;
|
||||
st.st_ino = handle;
|
||||
break;
|
||||
case kNtFileTypePipe:
|
||||
st.st_mode = S_IFIFO | (0666 & ~umask);
|
||||
st.st_dev = 0x55555555;
|
||||
st.st_ino = handle;
|
||||
break;
|
||||
case kNtFileTypeDisk: {
|
||||
struct NtByHandleFileInformation wst;
|
||||
|
@ -126,7 +166,6 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *out_st) {
|
|||
} else {
|
||||
st.st_ctim = st.st_mtim;
|
||||
}
|
||||
st.st_gid = st.st_uid = sys_getuid_nt();
|
||||
st.st_size = (wst.nFileSizeHigh + 0ull) << 32 | wst.nFileSizeLow;
|
||||
st.st_dev = wst.dwVolumeSerialNumber;
|
||||
st.st_ino = (wst.nFileIndexHigh + 0ull) << 32 | wst.nFileIndexLow;
|
||||
|
|
|
@ -52,7 +52,7 @@ int fstat(int fd, struct stat *st) {
|
|||
} else if (IsMetal()) {
|
||||
rc = sys_fstat_metal(fd, st);
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_fstat_nt(__getfdhandleactual(fd), st);
|
||||
rc = sys_fstat_nt(fd, st);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/stat.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -29,18 +28,43 @@
|
|||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||
int flags) {
|
||||
int rc, e;
|
||||
int64_t fh;
|
||||
uint32_t dwDesiredAccess;
|
||||
|
||||
// handle special files
|
||||
if (startswith(path, "/dev/")) {
|
||||
if (!strcmp(path + 5, "tty")) {
|
||||
return sys_fstat_nt_special(kFdConsole, st);
|
||||
} else if (!strcmp(path + 5, "null")) {
|
||||
return sys_fstat_nt_special(kFdDevNull, st);
|
||||
} else if (!strcmp(path + 5, "stdin")) {
|
||||
return sys_fstat_nt(STDIN_FILENO, st);
|
||||
} else if (!strcmp(path + 5, "stdout")) {
|
||||
return sys_fstat_nt(STDOUT_FILENO, st);
|
||||
} else if (!strcmp(path + 5, "stderr")) {
|
||||
return sys_fstat_nt(STDERR_FILENO, st);
|
||||
} else {
|
||||
return enoent();
|
||||
}
|
||||
}
|
||||
|
||||
// convert path from utf-8 to utf-16
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// open an actual file
|
||||
int rc;
|
||||
int64_t fh;
|
||||
int e = errno;
|
||||
uint32_t dwDesiredAccess = kNtFileGenericRead;
|
||||
BLOCK_SIGNALS;
|
||||
e = errno;
|
||||
dwDesiredAccess = kNtFileGenericRead;
|
||||
TryAgain:
|
||||
if ((fh = CreateFile(
|
||||
path16, dwDesiredAccess,
|
||||
|
@ -50,7 +74,7 @@ TryAgain:
|
|||
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
|
||||
: 0),
|
||||
0)) != -1) {
|
||||
rc = st ? sys_fstat_nt(fh, st) : 0;
|
||||
rc = st ? sys_fstat_nt_handle(fh, st) : 0;
|
||||
CloseHandle(fh);
|
||||
} else if (dwDesiredAccess == kNtFileGenericRead &&
|
||||
GetLastError() == kNtErrorSharingViolation) {
|
||||
|
@ -61,5 +85,7 @@ TryAgain:
|
|||
rc = __winerr();
|
||||
}
|
||||
ALLOW_SIGNALS;
|
||||
|
||||
// mop up errors
|
||||
return __fix_enotdir(rc, path16);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -36,6 +37,7 @@ textwindows int sys_getloadavg_nt(double *a, int n) {
|
|||
int i, rc;
|
||||
uint64_t elapsed, used;
|
||||
struct NtFileTime idle, kern, user;
|
||||
BLOCK_SIGNALS;
|
||||
pthread_spin_lock(&lock);
|
||||
if (GetSystemTimes(&idle, &kern, &user)) {
|
||||
elapsed = (FT(kern) - FT(kern1)) + (FT(user) - FT(user1));
|
||||
|
@ -53,6 +55,7 @@ textwindows int sys_getloadavg_nt(double *a, int n) {
|
|||
rc = __winerr();
|
||||
}
|
||||
pthread_spin_unlock(&lock);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,15 +20,7 @@
|
|||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
|
||||
static textwindows uint32_t __kmp32(const void *buf, size_t size) {
|
||||
size_t i;
|
||||
uint32_t h;
|
||||
const uint32_t kPhiPrime = 0x9e3779b1;
|
||||
const unsigned char *p = (const unsigned char *)buf;
|
||||
for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime;
|
||||
return h;
|
||||
}
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows uint32_t sys_getuid_nt(void) {
|
||||
char16_t buf[257];
|
||||
|
@ -36,7 +28,7 @@ textwindows uint32_t sys_getuid_nt(void) {
|
|||
uint32_t tmp, size = ARRAYLEN(buf);
|
||||
if (!(tmp = atomic_load_explicit(&uid, memory_order_acquire))) {
|
||||
GetUserName(&buf, &size);
|
||||
tmp = __kmp32(buf, size >> 1) & 32767;
|
||||
tmp = __fnv(buf, size >> 1) & 32767;
|
||||
if (!tmp) ++tmp;
|
||||
atomic_store_explicit(&uid, tmp, memory_order_release);
|
||||
}
|
||||
|
|
|
@ -106,6 +106,9 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
|
|||
int bytes = CountConsoleInputBytes();
|
||||
*arg = MAX(0, bytes);
|
||||
return 0;
|
||||
} else if (g_fds.p[fd].kind == kFdDevNull) {
|
||||
*arg = 1;
|
||||
return 0;
|
||||
} else if (GetFileType(handle) == kNtFileTypePipe) {
|
||||
uint32_t avail;
|
||||
if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) {
|
||||
|
|
|
@ -54,7 +54,7 @@ bool32 ischardev(int fd) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
return __isfdkind(fd, kFdConsole) ||
|
||||
return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) ||
|
||||
(__isfdkind(fd, kFdFile) &&
|
||||
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
|
||||
}
|
||||
|
|
|
@ -62,7 +62,9 @@ static textwindows int64_t Seek(struct Fd *f, int64_t offset, int whence) {
|
|||
}
|
||||
|
||||
textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
|
||||
if (__isfdkind(fd, kFdFile)) {
|
||||
if (__isfdkind(fd, kFdDevNull)) {
|
||||
return offset;
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
int filetype = GetFileType(f->handle);
|
||||
if (filetype != kNtFileTypePipe && filetype != kNtFileTypeChar) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/ntmagicpaths.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
|
@ -36,24 +35,6 @@ static inline int IsAlpha(int c) {
|
|||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
textwindows static const char *FixNtMagicPath(const char *path,
|
||||
unsigned flags) {
|
||||
const struct NtMagicPaths *mp = &kNtMagicPaths;
|
||||
asm("" : "+r"(mp));
|
||||
if (!IsSlash(path[0])) return path;
|
||||
if (strcmp(path, mp->devtty) == 0) {
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
return mp->conin;
|
||||
} else if ((flags & O_ACCMODE) == O_WRONLY) {
|
||||
return mp->conout;
|
||||
}
|
||||
}
|
||||
if (strcmp(path, mp->devnull) == 0) return mp->nul;
|
||||
if (strcmp(path, mp->devstdin) == 0) return mp->conin;
|
||||
if (strcmp(path, mp->devstdout) == 0) return mp->conout;
|
||||
return path;
|
||||
}
|
||||
|
||||
textwindows size_t __normntpath(char16_t *p, size_t n) {
|
||||
size_t i, j;
|
||||
for (j = i = 0; i < n; ++i) {
|
||||
|
@ -116,7 +97,6 @@ textwindows int __mkntpath2(const char *path,
|
|||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
return efault();
|
||||
}
|
||||
path = FixNtMagicPath(path, flags);
|
||||
|
||||
size_t x, z;
|
||||
char16_t *p = path16;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
TAB(devtty, "/dev/tty")
|
||||
TAB(devnull, "/dev/null")
|
||||
TAB(devstdin, "/dev/stdin")
|
||||
TAB(devstdout, "/dev/stdout")
|
||||
TAB(nul, "NUL")
|
||||
TAB(conin, "CONIN$")
|
||||
TAB(conout, "CONOUT$")
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_NTMAGICPATHS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_NTMAGICPATHS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct NtMagicPaths {
|
||||
#define TAB(NAME, STRING) char NAME[sizeof(STRING)];
|
||||
#include "libc/calls/ntmagicpaths.inc"
|
||||
#undef TAB
|
||||
};
|
||||
|
||||
extern const struct NtMagicPaths kNtMagicPaths;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_NTMAGICPATHS_H_ */
|
|
@ -18,8 +18,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ntmagicpaths.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -131,24 +131,13 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
|||
return __fix_enotdir(hand, path16);
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_console(int dirfd,
|
||||
const struct NtMagicPaths *mp,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
g_fds.p[fd].kind = kFdConsole;
|
||||
g_fds.p[fd].flags = flags;
|
||||
g_fds.p[fd].mode = mode;
|
||||
g_fds.p[fd].handle =
|
||||
CreateFile(u"CONIN$", kNtGenericRead | kNtGenericWrite, kNtFileShareRead,
|
||||
&kNtIsInheritable, kNtOpenExisting, 0, 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_file(int dirfd, const char *file,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if ((g_fds.p[fd].handle = sys_open_nt_impl(dirfd, file, flags, mode,
|
||||
int64_t handle;
|
||||
if ((handle = sys_open_nt_impl(dirfd, file, flags, mode,
|
||||
kNtFileFlagOverlapped)) != -1) {
|
||||
g_fds.p[fd].handle = handle;
|
||||
g_fds.p[fd].kind = kFdFile;
|
||||
g_fds.p[fd].flags = flags;
|
||||
g_fds.p[fd].mode = mode;
|
||||
|
@ -158,15 +147,61 @@ static textwindows int sys_open_nt_file(int dirfd, const char *file,
|
|||
}
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_special(int fd, int flags, int mode,
|
||||
int kind, const char16_t *name) {
|
||||
g_fds.p[fd].kind = kind;
|
||||
g_fds.p[fd].mode = mode;
|
||||
g_fds.p[fd].flags = flags;
|
||||
g_fds.p[fd].handle = CreateFile(name, kNtGenericRead | kNtGenericWrite,
|
||||
kNtFileShareRead | kNtFileShareWrite,
|
||||
&kNtIsInheritable, kNtOpenExisting, 0, 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
|
||||
int64_t handle;
|
||||
if (!__isfdopen(oldfd)) {
|
||||
return enoent();
|
||||
}
|
||||
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
|
||||
GetCurrentProcess(), &handle, 0, true,
|
||||
kNtDuplicateSameAccess)) {
|
||||
g_fds.p[fd] = g_fds.p[oldfd];
|
||||
g_fds.p[fd].handle = handle;
|
||||
g_fds.p[fd].mode = mode;
|
||||
if (!sys_fcntl_nt_setfl(fd, flags)) {
|
||||
return fd;
|
||||
} else {
|
||||
CloseHandle(handle);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
BLOCK_SIGNALS;
|
||||
__fds_lock();
|
||||
if (!(flags & O_CREAT)) mode = 0;
|
||||
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
|
||||
if (!strcmp(file, kNtMagicPaths.devtty)) {
|
||||
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
if (startswith(file, "/dev/")) {
|
||||
if (!strcmp(file + 5, "tty")) {
|
||||
rc = sys_open_nt_special(fd, flags, mode, kFdConsole, u"CONIN$");
|
||||
} else if (!strcmp(file + 5, "null")) {
|
||||
rc = sys_open_nt_special(fd, flags, mode, kFdDevNull, u"NUL");
|
||||
} else if (!strcmp(file + 5, "stdin")) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDIN_FILENO);
|
||||
} else if (!strcmp(file + 5, "stdout")) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDOUT_FILENO);
|
||||
} else if (!strcmp(file + 5, "stderr")) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDERR_FILENO);
|
||||
} else {
|
||||
rc = enoent();
|
||||
}
|
||||
} else {
|
||||
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
|
@ -175,5 +210,6 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
|||
}
|
||||
__fds_unlock();
|
||||
}
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@
|
|||
int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
|
||||
static bool once, modernize;
|
||||
int d, e, f;
|
||||
/*
|
||||
* RHEL5 doesn't support O_CLOEXEC. It's hard to test for this.
|
||||
* Sometimes the system call succeeds and it just doesn't set the
|
||||
* flag. Other times, it return -530 which makes no sense.
|
||||
*/
|
||||
// RHEL5 doesn't support O_CLOEXEC. It's hard to test for this.
|
||||
// Sometimes the system call succeeds and it just doesn't set the
|
||||
// flag. Other times, it return -530 which makes no sense.
|
||||
if (!IsLinux() || !(flags & O_CLOEXEC) || modernize) {
|
||||
d = __sys_openat(dirfd, file, flags, mode);
|
||||
} else if (once) {
|
||||
|
|
|
@ -47,13 +47,9 @@ static textwindows int _park_thread(uint32_t msdelay, sigset_t waitmask,
|
|||
om = __sig_beginwait(waitmask);
|
||||
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(restartable)) != -1) {
|
||||
unassert((wi = WaitForSingleObject(sem, msdelay)) != -1u);
|
||||
if (wi != kNtWaitTimeout) {
|
||||
_check_signal(false);
|
||||
rc = eintr();
|
||||
_check_cancel();
|
||||
} else if ((rc = _check_signal(restartable))) {
|
||||
_check_cancel();
|
||||
}
|
||||
if (restartable && !(pt->pt_flags & PT_RESTARTABLE)) rc = eintr();
|
||||
rc |= _check_signal(restartable);
|
||||
if (rc == -1 && errno == EINTR) _check_cancel();
|
||||
}
|
||||
__sig_finishwait(om);
|
||||
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_CPU, memory_order_release);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
|
|
|
@ -58,10 +58,10 @@
|
|||
// Polls on the New Technology.
|
||||
//
|
||||
// This function is used to implement poll() and select(). You may poll
|
||||
// on both sockets and files at the same time. We also poll for signals
|
||||
// while poll is polling.
|
||||
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
||||
const sigset_t *sigmask) {
|
||||
// on sockets, files and the console at the same time. We also poll for
|
||||
// both signals and posix thread cancelation, while the poll is polling
|
||||
static textwindows int sys_poll_nt_impl(struct pollfd *fds, uint64_t nfds,
|
||||
uint32_t *ms, sigset_t sigmask) {
|
||||
bool ok;
|
||||
uint64_t millis;
|
||||
uint32_t cm, avail, waitfor;
|
||||
|
@ -72,7 +72,6 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
|||
struct timespec started, deadline, remain, now;
|
||||
int i, rc, sn, pn, gotinvals, gotpipes, gotsocks;
|
||||
|
||||
BLOCK_SIGNALS;
|
||||
started = timespec_real();
|
||||
deadline = timespec_add(started, timespec_frommillis(ms ? *ms : -1u));
|
||||
|
||||
|
@ -128,7 +127,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
|||
__fds_unlock();
|
||||
if (rc) {
|
||||
// failed to create a polling solution
|
||||
goto Finished;
|
||||
return rc;
|
||||
}
|
||||
|
||||
// perform the i/o and sleeping and looping
|
||||
|
@ -170,8 +169,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
|||
// compute a small time slice we don't mind sleeping for
|
||||
if (sn) {
|
||||
if ((gotsocks = WSAPoll(sockfds, sn, 0)) == -1) {
|
||||
rc = __winsockerr();
|
||||
goto Finished;
|
||||
return __winsockerr();
|
||||
}
|
||||
} else {
|
||||
gotsocks = 0;
|
||||
|
@ -190,8 +188,8 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
|||
if (waitfor) {
|
||||
POLLTRACE("poll() sleeping for %'d out of %'lu ms", waitfor,
|
||||
timespec_tomillis(remain));
|
||||
if ((rc = _park_norestart(waitfor, sigmask ? *sigmask : 0)) == -1) {
|
||||
goto Finished; // eintr, ecanceled, etc.
|
||||
if ((rc = _park_norestart(waitfor, sigmask)) == -1) {
|
||||
return -1; // eintr, ecanceled, etc.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,9 +219,14 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
|||
}
|
||||
|
||||
// and finally return
|
||||
rc = gotinvals + gotpipes + gotsocks;
|
||||
return gotinvals + gotpipes + gotsocks;
|
||||
}
|
||||
|
||||
Finished:
|
||||
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint32_t *ms,
|
||||
const sigset_t *sigmask) {
|
||||
int rc;
|
||||
BLOCK_SIGNALS;
|
||||
rc = sys_poll_nt_impl(fds, nfds, ms, sigmask ? *sigmask : 0);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
|
|||
rc = sys_pread(fd, buf, size, offset, offset);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = espipe();
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
} else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull)) {
|
||||
rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, offset);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
|
|
|
@ -32,6 +32,8 @@ static const char *__fdkind2str(int x) {
|
|||
return "kFdSocket";
|
||||
case kFdConsole:
|
||||
return "kFdConsole";
|
||||
case kFdDevNull:
|
||||
return "kFdDevNull";
|
||||
case kFdSerial:
|
||||
return "kFdSerial";
|
||||
case kFdZip:
|
||||
|
|
|
@ -65,7 +65,7 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
|
|||
rc = sys_pwrite(fd, buf, size, offset, offset);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = espipe();
|
||||
} else if (__isfdkind(fd, kFdFile)) {
|
||||
} else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull)) {
|
||||
rc = sys_write_nt(fd, (struct iovec[]){{(void *)buf, size}}, 1, offset);
|
||||
} else {
|
||||
return ebadf();
|
||||
|
|
|
@ -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/atomic.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
@ -733,8 +734,10 @@ static textwindows int WaitForConsole(struct Fd *f, sigset_t waitmask) {
|
|||
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_SEM, memory_order_release);
|
||||
m = __sig_beginwait(waitmask);
|
||||
if ((rc = _check_cancel()) != -1 && (rc = _check_signal(true)) != -1) {
|
||||
WaitForMultipleObjects(2, (int64_t[2]){sem, __keystroke.cin}, 0, ms);
|
||||
int64_t hands[2] = {sem, __keystroke.cin};
|
||||
unassert(WaitForMultipleObjects(2, hands, 0, ms) != -1u);
|
||||
if (~pt->pt_flags & PT_RESTARTABLE) rc = eintr();
|
||||
rc |= _check_signal(true);
|
||||
if (rc == -1 && errno == EINTR) _check_cancel();
|
||||
}
|
||||
__sig_finishwait(m);
|
||||
|
@ -763,6 +766,11 @@ textwindows ssize_t sys_read_nt_impl(int fd, void *data, size_t size,
|
|||
|
||||
// switch to terminal polyfill if reading from win32 console
|
||||
struct Fd *f = g_fds.p + fd;
|
||||
|
||||
if (f->kind == kFdDevNull) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f->kind == kFdConsole) {
|
||||
return ReadFromConsole(f, data, size, waitmask);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
|
|||
switch (g_fds.p[fd].kind) {
|
||||
case kFdFile:
|
||||
case kFdConsole:
|
||||
case kFdDevNull:
|
||||
return sys_read_nt(fd, iov, iovlen, -1);
|
||||
case kFdSocket:
|
||||
return _weaken(sys_recv_nt)(fd, iov, iovlen, 0);
|
||||
|
|
|
@ -83,7 +83,9 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
|
|||
// similar to the lseek() system call, they too raise ESPIPE when
|
||||
// operating on a non-seekable file.
|
||||
bool pwriting = offset != -1;
|
||||
bool seekable = f->kind == kFdFile && GetFileType(handle) == kNtFileTypeDisk;
|
||||
bool seekable =
|
||||
(f->kind == kFdFile && GetFileType(handle) == kNtFileTypeDisk) ||
|
||||
f->kind == kFdDevNull;
|
||||
if (pwriting && !seekable) {
|
||||
return espipe();
|
||||
}
|
||||
|
|
71
libc/calls/setfl.c
Normal file
71
libc/calls/setfl.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*-*- 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 2023 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/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
textwindows int sys_fcntl_nt_setfl(int fd, unsigned flags) {
|
||||
|
||||
// you may change the following:
|
||||
//
|
||||
// - O_NONBLOCK make read() raise EAGAIN
|
||||
// - O_APPEND for toggling append mode
|
||||
// - O_RANDOM alt. for posix_fadvise()
|
||||
// - O_SEQUENTIAL alt. for posix_fadvise()
|
||||
// - O_DIRECT works but haven't tested
|
||||
//
|
||||
// the other bits are ignored.
|
||||
unsigned allowed = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT | O_NONBLOCK;
|
||||
unsigned needreo = O_APPEND | O_SEQUENTIAL | O_RANDOM | O_DIRECT;
|
||||
unsigned newflag = (g_fds.p[fd].flags & ~allowed) | (flags & allowed);
|
||||
|
||||
if (g_fds.p[fd].kind == kFdFile &&
|
||||
((g_fds.p[fd].flags & needreo) ^ (flags & needreo))) {
|
||||
unsigned perm, share, attr;
|
||||
if (GetNtOpenFlags(newflag, g_fds.p[fd].mode, &perm, &share, 0, &attr) ==
|
||||
-1) {
|
||||
return -1;
|
||||
}
|
||||
// MSDN says only these are allowed, otherwise it returns EINVAL.
|
||||
attr &= kNtFileFlagBackupSemantics | kNtFileFlagDeleteOnClose |
|
||||
kNtFileFlagNoBuffering | kNtFileFlagOpenNoRecall |
|
||||
kNtFileFlagOpenReparsePoint | kNtFileFlagOverlapped |
|
||||
kNtFileFlagPosixSemantics | kNtFileFlagRandomAccess |
|
||||
kNtFileFlagSequentialScan | kNtFileFlagWriteThrough;
|
||||
intptr_t hand;
|
||||
if ((hand = ReOpenFile(g_fds.p[fd].handle, perm, share, attr)) != -1) {
|
||||
if (hand != g_fds.p[fd].handle) {
|
||||
CloseHandle(g_fds.p[fd].handle);
|
||||
g_fds.p[fd].handle = hand;
|
||||
}
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
// 1. ignore flags that aren't access mode flags
|
||||
// 2. return zero if nothing's changed
|
||||
g_fds.p[fd].flags = newflag;
|
||||
return 0;
|
||||
}
|
|
@ -88,11 +88,13 @@ textwindows bool __sig_ignored(int sig) {
|
|||
textwindows void __sig_delete(int sig) {
|
||||
struct Dll *e;
|
||||
__sig.pending &= ~(1ull << (sig - 1));
|
||||
BLOCK_SIGNALS;
|
||||
_pthread_lock();
|
||||
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e)) {
|
||||
POSIXTHREAD_CONTAINER(e)->tib->tib_sigpending &= ~(1ull << (sig - 1));
|
||||
}
|
||||
_pthread_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
|
||||
static textwindows bool __sig_should_use_altstack(unsigned flags,
|
||||
|
@ -219,7 +221,7 @@ textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) {
|
|||
}
|
||||
|
||||
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
|
||||
++__sig.count;
|
||||
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
|
||||
int sig = sf->si.si_signo;
|
||||
sigset_t blocksigs = __sighandmask[sig];
|
||||
if (!(sf->flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1);
|
||||
|
@ -309,7 +311,9 @@ static int __sig_killer(struct PosixThread *pt, int sig, int sic) {
|
|||
textwindows int __sig_kill(struct PosixThread *pt, int sig, int sic) {
|
||||
int rc;
|
||||
BLOCK_SIGNALS;
|
||||
_pthread_ref(pt);
|
||||
rc = __sig_killer(pt, sig, sic);
|
||||
_pthread_unref(pt);
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
@ -333,7 +337,7 @@ textwindows void __sig_generate(int sig, int sic) {
|
|||
atomic_load_explicit(&pt->pt_status, memory_order_acquire) <
|
||||
kPosixThreadTerminated &&
|
||||
!(pt->tib->tib_sigmask & (1ull << (sig - 1)))) {
|
||||
mark = pt;
|
||||
_pthread_ref((mark = pt));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -345,6 +349,7 @@ textwindows void __sig_generate(int sig, int sic) {
|
|||
STRACE("all threads block %G so adding to pending signals of process", sig);
|
||||
__sig.pending |= 1ull << (sig - 1);
|
||||
}
|
||||
_pthread_unref(mark);
|
||||
ALLOW_SIGNALS;
|
||||
}
|
||||
|
||||
|
@ -411,7 +416,7 @@ static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
|
|||
struct CosmoTib *tib) {
|
||||
|
||||
// increment the signal count for getrusage()
|
||||
++__sig.count;
|
||||
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
|
||||
|
||||
// log vital crash information reliably for --strace before doing much
|
||||
// we don't print this without the flag since raw numbers scare people
|
||||
|
|
|
@ -18,14 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Configures process to ignore signal.
|
||||
*/
|
||||
int sigignore(int sig) {
|
||||
struct sigaction sa;
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sa_handler = SIG_IGN;
|
||||
struct sigaction sa = {.sa_handler = SIG_IGN};
|
||||
return sigaction(sig, &sa, 0);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -53,7 +54,8 @@ int sigpending(sigset_t *pending) {
|
|||
}
|
||||
rc = 0;
|
||||
} else if (IsWindows()) {
|
||||
*pending = __sig.pending | __get_tls()->tib_sigpending;
|
||||
*pending = atomic_load_explicit(&__sig.pending, memory_order_acquire) |
|
||||
__get_tls()->tib_sigpending;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = enosys();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
|
|
@ -11,6 +11,7 @@ COSMOPOLITAN_C_START_
|
|||
#define kFdZip 6
|
||||
#define kFdEpoll 7
|
||||
#define kFdReserved 8
|
||||
#define kFdDevNull 9
|
||||
|
||||
struct Fd {
|
||||
char kind;
|
||||
|
|
|
@ -7,7 +7,9 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
int sys_fstat(int, struct stat *);
|
||||
int sys_fstatat(int, const char *, struct stat *, int);
|
||||
int sys_fstat_nt(int64_t, struct stat *);
|
||||
int sys_fstat_nt(int, struct stat *);
|
||||
int sys_fstat_nt_special(int, struct stat *);
|
||||
int sys_fstat_nt_handle(int64_t, struct stat *);
|
||||
int sys_fstatat_nt(int, const char *, struct stat *, int);
|
||||
int sys_lstat_nt(const char *, struct stat *);
|
||||
int sys_fstat_metal(int, struct stat *);
|
||||
|
|
|
@ -16,6 +16,7 @@ int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX], int);
|
|||
int __mkntpathat(int, const char *, int, char16_t[hasatleast PATH_MAX]);
|
||||
int __mkntpathath(int64_t, const char *, int, char16_t[hasatleast PATH_MAX]);
|
||||
int ntaccesscheck(const char16_t *, uint32_t) paramsnonnull();
|
||||
int sys_fcntl_nt_setfl(int, unsigned);
|
||||
int sys_pause_nt(void);
|
||||
int64_t __fix_enotdir(int64_t, char16_t *);
|
||||
int64_t __fix_enotdir3(int64_t, char16_t *, char16_t *);
|
||||
|
|
|
@ -27,6 +27,7 @@ textwindows ssize_t sys_writev_nt(int fd, const struct iovec *iov, int iovlen) {
|
|||
switch (g_fds.p[fd].kind) {
|
||||
case kFdFile:
|
||||
case kFdConsole:
|
||||
case kFdDevNull:
|
||||
return sys_write_nt(fd, iov, iovlen, -1);
|
||||
case kFdSocket:
|
||||
return _weaken(sys_send_nt)(fd, iov, iovlen, 0);
|
||||
|
|
|
@ -60,11 +60,11 @@ const char *(DescribeStat)(char buf[N], int rc, const struct stat *st) {
|
|||
}
|
||||
|
||||
if (st->st_dev) {
|
||||
append(", .st_%s=%lu", "dev", st->st_dev);
|
||||
append(", .st_%s=%#lx", "dev", st->st_dev);
|
||||
}
|
||||
|
||||
if (st->st_ino) {
|
||||
append(", .st_%s=%lu", "ino", st->st_ino);
|
||||
append(", .st_%s=%#lx", "ino", st->st_ino);
|
||||
}
|
||||
|
||||
if (st->st_gen) {
|
||||
|
|
|
@ -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 2023 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,10 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/ntmagicpaths.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
const struct NtMagicPaths kNtMagicPaths = {
|
||||
#define TAB(NAME, STRING) STRING,
|
||||
#include "libc/calls/ntmagicpaths.inc"
|
||||
#undef TAB
|
||||
};
|
||||
uint64_t __fnv(const void *data, size_t size) {
|
||||
const unsigned char *p = data;
|
||||
const unsigned char *pe = p + size;
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
while (p < pe) {
|
||||
hash *= 0x100000001b3;
|
||||
hash ^= *p++;
|
||||
}
|
||||
return hash;
|
||||
}
|
|
@ -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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 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,35 +16,22 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Releases memory of detached threads that have terminated.
|
||||
*/
|
||||
void _pthread_decimate(void) {
|
||||
struct Dll *e;
|
||||
struct PosixThread *pt;
|
||||
enum PosixThreadStatus status;
|
||||
StartOver:
|
||||
_pthread_lock();
|
||||
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e)) {
|
||||
pt = POSIXTHREAD_CONTAINER(e);
|
||||
if (pt->tib == __get_tls()) continue;
|
||||
status = atomic_load_explicit(&pt->pt_status, memory_order_acquire);
|
||||
if (status != kPosixThreadZombie) break;
|
||||
if (!atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire)) {
|
||||
dll_remove(&_pthread_list, e);
|
||||
_pthread_unlock();
|
||||
_pthread_free(pt, false);
|
||||
goto StartOver;
|
||||
static bool _pthread_deref(struct PosixThread *pt) {
|
||||
int refs = atomic_load_explicit(&pt->pt_refs, memory_order_acquire);
|
||||
if (!refs) return true;
|
||||
unassert(refs > 0);
|
||||
return !atomic_fetch_sub(&pt->pt_refs, 1);
|
||||
}
|
||||
|
||||
void _pthread_unref(struct PosixThread *pt) {
|
||||
if (_pthread_deref(pt)) {
|
||||
unassert(_weaken(_pthread_free));
|
||||
_weaken(_pthread_free)(pt, false);
|
||||
_weaken(_pthread_decimate)();
|
||||
}
|
||||
}
|
||||
_pthread_unlock();
|
||||
}
|
|
@ -28,14 +28,12 @@ __msabi extern typeof(ReOpenFile) *const __imp_ReOpenFile;
|
|||
* Reopens file on the New Technology.
|
||||
*
|
||||
* @return handle, or -1 on failure
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess,
|
||||
uint32_t dwShareMode, uint32_t dwFlagsAndAttributes) {
|
||||
int64_t hHandle;
|
||||
hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode,
|
||||
dwFlagsAndAttributes);
|
||||
if (hHandle == -1) __winerr();
|
||||
NTTRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile,
|
||||
DescribeNtFileAccessFlags(dwDesiredAccess),
|
||||
DescribeNtFileShareFlags(dwShareMode),
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_LOG_LIBFATAL_INTERNAL_H_
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -30,15 +25,6 @@ __funline char *__stpcpy(char *d, const char *s) {
|
|||
}
|
||||
}
|
||||
|
||||
__funline long __write_linux(int fd, const void *p, long n) {
|
||||
long ax = 1;
|
||||
asm volatile("syscall"
|
||||
: "+a"(ax)
|
||||
: "D"(fd), "S"(p), "d"(n)
|
||||
: "rcx", "r11", "memory");
|
||||
return ax;
|
||||
}
|
||||
|
||||
__funline void *__repstosb(void *di, char al, size_t cx) {
|
||||
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
asm("rep stosb"
|
||||
|
|
|
@ -96,11 +96,19 @@ static wontreturn void UnsupportedSyntax(unsigned char c) {
|
|||
}
|
||||
|
||||
static void Open(const char *path, int fd, int flags) {
|
||||
close(fd);
|
||||
if (open(path, flags, 0644) == -1) {
|
||||
int tmpfd;
|
||||
// use open+dup2 to support things like >/dev/stdout
|
||||
if ((tmpfd = open(path, flags, 0644)) == -1) {
|
||||
perror(path);
|
||||
_Exit(1);
|
||||
}
|
||||
if (tmpfd != fd) {
|
||||
if (dup2(tmpfd, fd) == -1) {
|
||||
perror("dup2");
|
||||
_Exit(1);
|
||||
}
|
||||
close(tmpfd);
|
||||
}
|
||||
}
|
||||
|
||||
static int SystemExec(void) {
|
||||
|
|
|
@ -67,10 +67,8 @@
|
|||
#include "libc/thread/itimer.internal.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
extern int64_t __wincrashearly;
|
||||
void __keystroke_wipe(void);
|
||||
|
||||
static textwindows wontreturn void AbortFork(const char *func) {
|
||||
|
@ -399,7 +397,7 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
|
|||
__tls_enabled_set(true);
|
||||
// clear pending signals
|
||||
tib->tib_sigpending = 0;
|
||||
__sig.pending = 0;
|
||||
atomic_store_explicit(&__sig.pending, 0, memory_order_relaxed);
|
||||
// re-enable threads
|
||||
__enable_threads();
|
||||
// re-apply code morphing for function tracing
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/struct/rusage.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/fmt/wintime.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
|
@ -75,7 +76,7 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
|
|||
.ru_majflt = memcount.PageFaultCount,
|
||||
.ru_inblock = iocount.ReadOperationCount,
|
||||
.ru_oublock = iocount.WriteOperationCount,
|
||||
.ru_nsignals = __sig.count,
|
||||
.ru_nsignals = atomic_load_explicit(&__sig.count, memory_order_acquire),
|
||||
};
|
||||
|
||||
if (who == RUSAGE_BOTH) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -26,6 +27,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
|
|||
unsigned i;
|
||||
uint32_t op;
|
||||
char *a, *b, *x, *y, *p;
|
||||
BLOCK_SIGNALS;
|
||||
__mmi_lock();
|
||||
size = (size + 4095) & -4096;
|
||||
p = addr;
|
||||
|
@ -62,5 +64,6 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
|
|||
}
|
||||
}
|
||||
__mmi_unlock();
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,23 +20,15 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/runtime/zipos.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/zip.internal.h"
|
||||
|
||||
static uint64_t __zipos_fnv(const char *s, int len) {
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
for (int i = 0; i < len; i++) {
|
||||
hash *= 0x100000001b3;
|
||||
hash ^= (unsigned char)s[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint64_t __zipos_inode(struct Zipos *zipos, int64_t cfile, //
|
||||
const void *name, size_t namelen) {
|
||||
unassert(cfile >= 0);
|
||||
if (cfile == ZIPOS_SYNTHETIC_DIRECTORY) {
|
||||
if (namelen && ((char *)name)[namelen - 1] == '/') --namelen;
|
||||
cfile = INT64_MIN | __zipos_fnv(name, namelen);
|
||||
cfile = INT64_MIN | __fnv(name, namelen);
|
||||
}
|
||||
return cfile;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,7 @@ dontthrow nocallback;
|
|||
uint64_t tpenc(uint32_t) pureconst;
|
||||
char *chomp(char *) libcesque;
|
||||
wchar_t *wchomp(wchar_t *) libcesque;
|
||||
uint64_t __fnv(const void *, size_t) strlenesque;
|
||||
bool startswith(const char *, const char *) strlenesque;
|
||||
bool startswithi(const char *, const char *) strlenesque;
|
||||
bool endswith(const char *, const char *) strlenesque;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define COSMOPOLITAN_LIBC_THREAD_POSIXTHREAD_INTERNAL_H_
|
||||
#include "libc/calls/struct/sched_param.h"
|
||||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/dll.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
@ -16,9 +17,9 @@
|
|||
#define PT_RESTARTABLE 64
|
||||
#define PT_OPENBSD_KLUDGE 128
|
||||
|
||||
#define PT_BLOCKER_CPU ((_Atomic(int) *)-0)
|
||||
#define PT_BLOCKER_SEM ((_Atomic(int) *)-1)
|
||||
#define PT_BLOCKER_IO ((_Atomic(int) *)-2)
|
||||
#define PT_BLOCKER_CPU ((atomic_int *)-0)
|
||||
#define PT_BLOCKER_SEM ((atomic_int *)-1)
|
||||
#define PT_BLOCKER_IO ((atomic_int *)-2)
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -80,9 +81,10 @@ enum PosixThreadStatus {
|
|||
|
||||
struct PosixThread {
|
||||
int pt_flags; // 0x00: see PT_* constants
|
||||
_Atomic(int) pt_canceled; // 0x04: thread has bad beliefs
|
||||
atomic_int pt_canceled; // 0x04: thread has bad beliefs
|
||||
_Atomic(enum PosixThreadStatus) pt_status;
|
||||
_Atomic(int) ptid; // transitions 0 → tid
|
||||
atomic_int ptid; // transitions 0 → tid
|
||||
atomic_int pt_refs; // negative means free
|
||||
void *(*pt_start)(void *); // creation callback
|
||||
void *pt_arg; // start's parameter
|
||||
void *pt_rc; // start's return value
|
||||
|
@ -90,7 +92,7 @@ struct PosixThread {
|
|||
struct CosmoTib *tib; // middle of tls allocation
|
||||
struct Dll list; // list of threads
|
||||
struct _pthread_cleanup_buffer *pt_cleanup;
|
||||
_Atomic(_Atomic(int) *) pt_blocker;
|
||||
_Atomic(atomic_int *) pt_blocker;
|
||||
int64_t pt_semaphore;
|
||||
intptr_t pt_iohandle;
|
||||
void *pt_ioverlap;
|
||||
|
@ -119,6 +121,7 @@ void _pthread_onfork_prepare(void);
|
|||
void _pthread_ungarbage(void);
|
||||
void _pthread_unkey(struct CosmoTib *);
|
||||
void _pthread_unlock(void);
|
||||
void _pthread_unref(struct PosixThread *);
|
||||
void _pthread_unwind(struct PosixThread *);
|
||||
void _pthread_zombify(struct PosixThread *);
|
||||
|
||||
|
@ -126,6 +129,10 @@ __funline pureconst struct PosixThread *_pthread_self(void) {
|
|||
return (struct PosixThread *)__get_tls()->tib_pthread;
|
||||
}
|
||||
|
||||
__funline void _pthread_ref(struct PosixThread *pt) {
|
||||
atomic_fetch_add_explicit(&pt->pt_refs, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_THREAD_POSIXTHREAD_INTERNAL_H_ */
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
|
@ -26,7 +25,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
|
@ -67,6 +65,7 @@ __static_yoink("_pthread_atfork");
|
|||
#define MAP_STACK_OPENBSD 0x4000
|
||||
|
||||
void _pthread_free(struct PosixThread *pt, bool isfork) {
|
||||
unassert(dll_is_alone(&pt->list) && &pt->list != _pthread_list);
|
||||
if (pt->pt_flags & PT_STATIC) return;
|
||||
if (pt->pt_flags & PT_OWNSTACK) {
|
||||
unassert(!munmap(pt->pt_attr.__stackaddr, pt->pt_attr.__stacksize));
|
||||
|
@ -86,6 +85,26 @@ void _pthread_free(struct PosixThread *pt, bool isfork) {
|
|||
free(pt);
|
||||
}
|
||||
|
||||
void _pthread_decimate(void) {
|
||||
struct Dll *e;
|
||||
struct PosixThread *pt;
|
||||
enum PosixThreadStatus status;
|
||||
StartOver:
|
||||
_pthread_lock();
|
||||
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e)) {
|
||||
pt = POSIXTHREAD_CONTAINER(e);
|
||||
status = atomic_load_explicit(&pt->pt_status, memory_order_acquire);
|
||||
if (status != kPosixThreadZombie) break;
|
||||
if (!atomic_load_explicit(&pt->tib->tib_tid, memory_order_acquire)) {
|
||||
dll_remove(&_pthread_list, e);
|
||||
_pthread_unlock();
|
||||
_pthread_unref(pt);
|
||||
goto StartOver;
|
||||
}
|
||||
}
|
||||
_pthread_unlock();
|
||||
}
|
||||
|
||||
static int PosixThread(void *arg, int tid) {
|
||||
void *rc;
|
||||
struct PosixThread *pt = arg;
|
||||
|
|
|
@ -116,8 +116,7 @@ errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr,
|
|||
if (value_ptr) {
|
||||
*value_ptr = pt->pt_rc;
|
||||
}
|
||||
_pthread_free(pt, false);
|
||||
_pthread_decimate();
|
||||
_pthread_unref(pt);
|
||||
}
|
||||
STRACE("pthread_timedjoin_np(%d, %s, %s) → %s", _pthread_tid(pt),
|
||||
DescribeReturnValue(alloca(30), err, value_ptr),
|
||||
|
|
82
test/libc/calls/specialfile_test.c
Normal file
82
test/libc/calls/specialfile_test.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*-*- 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 2023 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/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
int pipefd[2];
|
||||
int stdoutBack;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
}
|
||||
|
||||
void CaptureStdout(void) {
|
||||
ASSERT_NE(-1, (stdoutBack = dup(1)));
|
||||
ASSERT_SYS(0, 0, pipe(pipefd));
|
||||
ASSERT_NE(-1, dup2(pipefd[1], 1));
|
||||
}
|
||||
|
||||
void RestoreStdout(void) {
|
||||
ASSERT_SYS(0, 1, dup2(stdoutBack, 1));
|
||||
ASSERT_SYS(0, 0, close(stdoutBack));
|
||||
ASSERT_SYS(0, 0, close(pipefd[1]));
|
||||
ASSERT_SYS(0, 0, close(pipefd[0]));
|
||||
}
|
||||
|
||||
TEST(specialfile, devNull) {
|
||||
ASSERT_SYS(0, 3, creat("/dev/null", 0644));
|
||||
ASSERT_EQ(O_WRONLY, fcntl(3, F_GETFL) & ~O_LARGEFILE);
|
||||
ASSERT_SYS(0, 2, write(3, "hi", 2));
|
||||
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 0));
|
||||
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 2));
|
||||
ASSERT_SYS(0, 0, lseek(3, 0, SEEK_END));
|
||||
ASSERT_SYS(0, 0, lseek(3, 0, SEEK_CUR));
|
||||
if (!IsLinux()) {
|
||||
// rhel7 doesn't have this behavior
|
||||
ASSERT_SYS(0, 2, lseek(3, 2, SEEK_CUR));
|
||||
ASSERT_SYS(0, 2, lseek(3, 2, SEEK_END));
|
||||
}
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(specialfile, devNullRead) {
|
||||
char buf[8] = {0};
|
||||
ASSERT_SYS(0, 3, open("/dev/null", O_RDONLY));
|
||||
ASSERT_EQ(O_RDONLY, fcntl(3, F_GETFL) & ~O_LARGEFILE);
|
||||
ASSERT_SYS(0, 0, read(3, buf, 8));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
TEST(specialfile, devStdout) {
|
||||
char buf[8] = {8};
|
||||
CaptureStdout();
|
||||
ASSERT_SYS(0, 6, creat("/dev/stdout", 0644));
|
||||
ASSERT_SYS(0, 2, write(6, "hi", 2));
|
||||
ASSERT_EQ(2, read(pipefd[0], buf, 8));
|
||||
ASSERT_STREQ("hi", buf);
|
||||
ASSERT_SYS(ESPIPE, -1, pwrite(6, "hi", 2, 0));
|
||||
ASSERT_SYS(ESPIPE, -1, lseek(6, 0, SEEK_END));
|
||||
ASSERT_SYS(0, 0, close(6));
|
||||
RestoreStdout();
|
||||
}
|
|
@ -195,6 +195,15 @@ TEST(system, exitStatusPreservedAfterSemiColon) {
|
|||
RestoreStdout();
|
||||
}
|
||||
|
||||
TEST(system, devStdout) {
|
||||
CaptureStdout();
|
||||
ASSERT_EQ(0, GETEXITSTATUS(system("echo sup >/dev/stdout")));
|
||||
char buf[16] = {0};
|
||||
ASSERT_EQ(4, read(pipefd[0], buf, 16));
|
||||
ASSERT_STREQ("sup\n", buf);
|
||||
RestoreStdout();
|
||||
}
|
||||
|
||||
TEST(system, globio) {
|
||||
char buf[9] = {0};
|
||||
CaptureStdout();
|
||||
|
|
1
third_party/nsync/futex.c
vendored
1
third_party/nsync/futex.c
vendored
|
@ -172,6 +172,7 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare,
|
|||
if (_check_cancel () == -1) return -1;
|
||||
if (_check_signal (false) == -1) return -1;
|
||||
ok = WaitOnAddress (w, &expect, sizeof(int), timespec_tomillis (wait));
|
||||
if (_check_signal (false) == -1) { _check_cancel (); return -1; }
|
||||
if (_check_cancel () == -1) return -1;
|
||||
if (ok) {
|
||||
return 0;
|
||||
|
|
|
@ -620,9 +620,8 @@ RetryOnEtxtbsyRaceCondition:
|
|||
goto TerminateJob;
|
||||
}
|
||||
if (received > 0) {
|
||||
WARNF("%s client sent %d unexpected bytes so killing job", origname,
|
||||
received);
|
||||
goto HangupClientAndTerminateJob;
|
||||
WARNF("%s client sent %d unexpected bytes", origname, received);
|
||||
continue;
|
||||
}
|
||||
if (received == MBEDTLS_ERR_SSL_WANT_READ) { // EAGAIN SO_RCVTIMEO
|
||||
WARNF("%s (pid %d) is taking a really long time", origname,
|
||||
|
|
|
@ -178,14 +178,18 @@ __static_yoink("blink_xnu_aarch64"); // is apple silicon
|
|||
#define MONITOR_MICROS 150000
|
||||
#define READ(F, P, N) readv(F, &(struct iovec){P, N}, 1)
|
||||
#define WRITE(F, P, N) writev(F, &(struct iovec){P, N}, 1)
|
||||
#define LockInc(P) (*(_Atomic(typeof(*(P))) *)(P))++
|
||||
#define LockDec(P) (*(_Atomic(typeof(*(P))) *)(P))--
|
||||
#define AppendCrlf(P) mempcpy(P, "\r\n", 2)
|
||||
#define HasHeader(H) (!!cpm.msg.headers[H].a)
|
||||
#define HeaderData(H) (inbuf.p + cpm.msg.headers[H].a)
|
||||
#define HeaderLength(H) (cpm.msg.headers[H].b - cpm.msg.headers[H].a)
|
||||
#define HeaderEqualCase(H, S) \
|
||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
||||
#define LockInc(P) \
|
||||
atomic_fetch_add_explicit((_Atomic(typeof(*(P))) *)(P), +1, \
|
||||
memory_order_relaxed)
|
||||
#define LockDec(P) \
|
||||
atomic_fetch_add_explicit((_Atomic(typeof(*(P))) *)(P), -1, \
|
||||
memory_order_relaxed)
|
||||
|
||||
#define TRACE_BEGIN \
|
||||
do { \
|
||||
|
|
|
@ -60,7 +60,6 @@ static char msg[128];
|
|||
static uint32_t msglen;
|
||||
static const char *prog;
|
||||
static atomic_int a_termsig;
|
||||
static atomic_long a_errors;
|
||||
static atomic_long a_requests;
|
||||
static atomic_bool a_finished;
|
||||
|
||||
|
@ -125,23 +124,21 @@ static void NewClient(struct Client *client, const struct sockaddr_in *addr) {
|
|||
|
||||
static void *Worker(void *arg) {
|
||||
while (!a_finished) {
|
||||
bool32 ok;
|
||||
uint32_t i;
|
||||
uint32_t dwFlags;
|
||||
uint32_t dwBytes;
|
||||
struct Client *client;
|
||||
uint64_t CompletionKey;
|
||||
struct NtOverlapped *lpOverlapped;
|
||||
if (!(ok = GetQueuedCompletionStatus(iocp, &dwBytes, &CompletionKey,
|
||||
&lpOverlapped, -1u)) &&
|
||||
!lpOverlapped) {
|
||||
uint32_t dwRecordCount;
|
||||
struct NtOverlappedEntry records[8];
|
||||
if (!GetQueuedCompletionStatusEx(iocp, records, ARRAYLEN(records),
|
||||
&dwRecordCount, -1u, false)) {
|
||||
fprintf(stderr, "GetQueuedCompletionStatus() failed w/ %d\n",
|
||||
GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
client = (struct Client *)CompletionKey;
|
||||
for (i = 0; i < dwRecordCount; ++i) {
|
||||
uint32_t dwBytes = records[i].dwNumberOfBytesTransferred;
|
||||
struct Client *client = (struct Client *)records[i].lpCompletionKey;
|
||||
switch (client->state) {
|
||||
case SENDING:
|
||||
if (ok) {
|
||||
dwFlags = 0;
|
||||
client->state = RECEIVING;
|
||||
client->iov.buf = client->buf;
|
||||
|
@ -153,15 +150,8 @@ static void *Worker(void *arg) {
|
|||
fprintf(stderr, "WSARecv() failed w/ %d\n", WSAGetLastError());
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "WSAConnect() or WSASend() failed w/ %d\n",
|
||||
WSAGetLastError());
|
||||
__imp_closesocket(client->handle);
|
||||
++a_errors;
|
||||
}
|
||||
break;
|
||||
case RECEIVING:
|
||||
if (ok) {
|
||||
if (!dwBytes) {
|
||||
fprintf(stderr, "got disconnect\n");
|
||||
break;
|
||||
|
@ -183,16 +173,12 @@ static void *Worker(void *arg) {
|
|||
fprintf(stderr, "WSASend() failed w/ %d\n", WSAGetLastError());
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "WSARecv() failed w/ %d\n", WSAGetLastError());
|
||||
__imp_closesocket(client->handle);
|
||||
++a_errors;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -209,12 +195,12 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
prog = argv[0];
|
||||
if (!prog) {
|
||||
prog = "ab";
|
||||
prog = "winbench";
|
||||
}
|
||||
|
||||
int opt;
|
||||
int nclients = 20;
|
||||
int nthreads = GetMaximumProcessorCount(0xffff) * 2;
|
||||
int nclients = 1000;
|
||||
int nthreads = GetMaximumProcessorCount(0xffff);
|
||||
struct sockaddr_in destaddr = {AF_INET, htons(8080), {htonl(0x7f000001)}};
|
||||
while ((opt = getopt(argc, argv, "hH:P:")) != -1) {
|
||||
switch (opt) {
|
||||
|
@ -280,7 +266,7 @@ int main(int argc, char *argv[]) {
|
|||
NewClient(clients + i, &destaddr);
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
sleep(10);
|
||||
|
||||
a_finished = true;
|
||||
long request_count = a_requests;
|
||||
|
|
Loading…
Add table
Reference in a new issue