mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-01 08:48:29 +00:00
Get Redbean fork() working on the New Technology
Now that we have understandable system call tracing on Windows, this change rewrites many of the polyfill internals for that platform, to help things get closer to tip top shape. Support for complex forking scenarios had been in a regressed state for quite some time. Now, it works! Subsequent changes should be able to address the performance.
This commit is contained in:
parent
efedef6e65
commit
0cb6b6ff4b
84 changed files with 1340 additions and 338 deletions
|
@ -96,6 +96,7 @@ o//libc/calls/fcntl.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
# must use alloca()
|
||||
o/$(MODE)/libc/calls/execl.o \
|
||||
o/$(MODE)/libc/calls/execle.o \
|
||||
o/$(MODE)/libc/calls/execlp.o \
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#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/overlapped.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
|
@ -33,7 +34,6 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
|
|||
int prot, int flags,
|
||||
int64_t handle, int64_t off) {
|
||||
/* asan runtime depends on this function */
|
||||
bool32 rc;
|
||||
uint32_t got;
|
||||
size_t i, upsize;
|
||||
struct DirectMap dm;
|
||||
|
@ -44,18 +44,12 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
|
|||
* combination of flags, that'll cause Windows to actually do this!
|
||||
*/
|
||||
upsize = ROUNDUP(size, FRAMESIZE);
|
||||
dm.maphandle = CreateFileMappingNuma(-1, &kNtIsInheritable,
|
||||
kNtPageExecuteReadwrite, upsize >> 32,
|
||||
upsize, NULL, kNtNumaNoPreferredNode);
|
||||
STRACE(
|
||||
"CreateFileMappingNuma(-1, kNtPageExecuteReadwrite, %'zu/%'zu) -> %p",
|
||||
upsize, size, dm.maphandle);
|
||||
if (dm.maphandle) {
|
||||
dm.addr =
|
||||
MapViewOfFileExNuma(dm.maphandle, kNtFileMapWrite | kNtFileMapExecute,
|
||||
0, 0, upsize, addr, kNtNumaNoPreferredNode);
|
||||
STRACE("MapViewOfFileExNuma(WX, %p) → addr:%p", addr, dm.addr);
|
||||
if (dm.addr) {
|
||||
if ((dm.maphandle = CreateFileMappingNuma(
|
||||
-1, &kNtIsInheritable, kNtPageExecuteReadwrite, upsize >> 32,
|
||||
upsize, NULL, kNtNumaNoPreferredNode))) {
|
||||
if ((dm.addr = MapViewOfFileExNuma(
|
||||
dm.maphandle, kNtFileMapWrite | kNtFileMapExecute, 0, 0, upsize,
|
||||
addr, kNtNumaNoPreferredNode))) {
|
||||
for (i = 0; i < size; i += got) {
|
||||
got = 0;
|
||||
op.Internal = 0;
|
||||
|
@ -69,37 +63,27 @@ textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
|
|||
if (i == size) {
|
||||
return dm;
|
||||
}
|
||||
rc = UnmapViewOfFile(dm.addr);
|
||||
STRACE("%s(addr:%p) → %hhhd% m", "UnmapViewOfFile", dm.maphandle, rc);
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
rc = CloseHandle(dm.maphandle);
|
||||
STRACE("%s(%p) → %hhhd% m", "CloseHandle", dm.maphandle, rc);
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
} else {
|
||||
dm.maphandle = CreateFileMappingNuma(
|
||||
handle, &kNtIsInheritable,
|
||||
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
|
||||
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
|
||||
kNtNumaNoPreferredNode);
|
||||
STRACE("CreateFileMappingNuma(fhand:%ld, prot:%s, size:%'zu) → %p", handle,
|
||||
(prot & PROT_WRITE) ? "XRW" : "XR", handle != -1 ? 0 : size);
|
||||
if (dm.maphandle) {
|
||||
dm.addr = MapViewOfFileExNuma(
|
||||
dm.maphandle,
|
||||
(prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute
|
||||
: kNtFileMapRead | kNtFileMapExecute,
|
||||
off >> 32, off, size, addr, kNtNumaNoPreferredNode);
|
||||
STRACE("MapViewOfFileExNuma(prot:%s, off:%'ld, size:%'zu, addr:%p) → %p",
|
||||
(prot & PROT_WRITE) ? "WX" : "RX", off, size, addr, dm.addr);
|
||||
if (dm.addr) {
|
||||
if ((dm.maphandle = CreateFileMappingNuma(
|
||||
handle, &kNtIsInheritable,
|
||||
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
|
||||
handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
|
||||
kNtNumaNoPreferredNode))) {
|
||||
if ((dm.addr = MapViewOfFileExNuma(
|
||||
dm.maphandle,
|
||||
(prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute
|
||||
: kNtFileMapRead | kNtFileMapExecute,
|
||||
off >> 32, off, size, addr, kNtNumaNoPreferredNode))) {
|
||||
return dm;
|
||||
} else {
|
||||
rc = CloseHandle(dm.maphandle);
|
||||
STRACE("%s(%p) → %d% m", "CloseHandle", dm.maphandle, rc);
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
}
|
||||
dm.maphandle = kNtInvalidHandleValue;
|
||||
dm.addr = (void *)(intptr_t)__winerr();
|
||||
dm.addr = (void *)(intptr_t)-1;
|
||||
return dm;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/nt/struct/processinformation.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
|
@ -54,5 +55,5 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
GetExitCodeProcess(procinfo.hProcess, &dwExitCode);
|
||||
} while (dwExitCode == kNtStillActive);
|
||||
CloseHandle(procinfo.hProcess);
|
||||
ExitProcess(dwExitCode);
|
||||
_Exit(dwExitCode);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -52,7 +51,7 @@ noasan noubsan privileged int mprotect(void *addr, size_t len, int prot) {
|
|||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
if (__imp_VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) {
|
||||
if (VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
|
|
|
@ -84,7 +84,7 @@ textwindows int ntspawn(
|
|||
(block =
|
||||
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||
blocksize, NULL, kNtNumaNoPreferredNode))) {
|
||||
if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 &&
|
||||
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
||||
mkntenvblock(block->envvars, envp, extravar) != -1) {
|
||||
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
|
@ -95,10 +95,11 @@ textwindows int ntspawn(
|
|||
} else {
|
||||
__winerr();
|
||||
}
|
||||
STRACE("CreateProcess(%#hs, %#hs) → %d% m", prog16, block->cmdline, rc);
|
||||
STRACE("CreateProcess(%#hs, %!#hs) → %d% m", prog16, block->cmdline, rc);
|
||||
}
|
||||
} else {
|
||||
__winerr();
|
||||
STRACE("ntspawn() alloc failed %m");
|
||||
}
|
||||
if (block) UnmapViewOfFile(block);
|
||||
if (handle) CloseHandle(handle);
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/nt/enum/ctrlevent.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
|
@ -31,16 +33,20 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
|||
siginfo_t info;
|
||||
switch (CtrlType) {
|
||||
case kNtCtrlCEvent:
|
||||
STRACE("kNtCtrlCEvent");
|
||||
sig = pushpop(SIGINT);
|
||||
break;
|
||||
case kNtCtrlBreakEvent:
|
||||
STRACE("kNtCtrlBreakEvent");
|
||||
sig = pushpop(SIGQUIT);
|
||||
break;
|
||||
case kNtCtrlCloseEvent:
|
||||
STRACE("kNtCtrlCloseEvent");
|
||||
sig = pushpop(SIGHUP);
|
||||
break;
|
||||
case kNtCtrlLogoffEvent: // only received by services so hack hack hack
|
||||
case kNtCtrlShutdownEvent: // only received by services so hack hack hack
|
||||
STRACE("kNtCtrlLogoffEvent");
|
||||
sig = pushpop(SIGALRM);
|
||||
break;
|
||||
default:
|
||||
|
@ -48,7 +54,7 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
|
|||
}
|
||||
switch ((rva = __sighandrvas[sig])) {
|
||||
case (uintptr_t)SIG_DFL:
|
||||
ExitProcess(128 + sig);
|
||||
_Exit(128 + sig);
|
||||
case (uintptr_t)SIG_IGN:
|
||||
return true;
|
||||
default:
|
||||
|
|
|
@ -36,42 +36,82 @@
|
|||
#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) {
|
||||
uint32_t br;
|
||||
int64_t handle;
|
||||
char16_t path16[PATH_MAX];
|
||||
uint32_t perm, share, disp, attr;
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
if ((handle = CreateFile(
|
||||
path16, flags & 0xf000000f, /* see consts.sh */
|
||||
(flags & O_EXCL)
|
||||
? kNtFileShareExclusive
|
||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
&kNtIsInheritable,
|
||||
(flags & O_CREAT) && (flags & O_EXCL) ? kNtCreateNew
|
||||
: (flags & O_CREAT) && (flags & O_TRUNC) ? kNtCreateAlways
|
||||
: (flags & O_CREAT) ? kNtOpenAlways
|
||||
: (flags & O_TRUNC) ? kNtTruncateExisting
|
||||
: kNtOpenExisting,
|
||||
/* TODO(jart): Should we just always set overlapped? */
|
||||
(/* note: content indexer demolishes unix-ey i/o performance */
|
||||
kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||
(((flags & ((kNtFileFlagWriteThrough | kNtFileFlagOverlapped |
|
||||
kNtFileFlagNoBuffering | kNtFileFlagRandomAccess) >>
|
||||
8))
|
||||
<< 8) |
|
||||
(flags & (kNtFileFlagSequentialScan | kNtFileFlagDeleteOnClose |
|
||||
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
|
||||
kNtFileAttributeTemporary)))),
|
||||
0)) != -1) {
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) &&
|
||||
(flags & O_TRUNC))) { /* TODO(jart): What was this? */
|
||||
handle = eisdir();
|
||||
} else {
|
||||
handle = __winerr();
|
||||
|
||||
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;
|
||||
}
|
||||
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 ((handle = CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr,
|
||||
0)) != -1) {
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & _O_CREAT) &&
|
||||
(flags & _O_TRUNC))) { /* TODO(jart): What was this? */
|
||||
handle = eisdir();
|
||||
}
|
||||
STRACE("CreateFile() → %ld% m", handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,49 +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/calls/internal.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
#define HAS(X, BITS) (((X) & (BITS)) == (BITS))
|
||||
|
||||
/**
|
||||
* Converts System Five memory protection flags to Windows NT, Part 1.
|
||||
* @see libc/sysv/consts.sh
|
||||
*/
|
||||
privileged uint32_t __prot2nt(int prot, int flags) {
|
||||
return (HAS(prot, PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS))
|
||||
? kNtPageExecuteReadwrite
|
||||
: kNtPageExecuteWritecopy
|
||||
: HAS(prot, PROT_READ | PROT_WRITE)
|
||||
? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS))
|
||||
? kNtPageReadwrite
|
||||
: kNtPageReadwrite /* kNtPageWritecopy */
|
||||
: HAS(prot, PROT_READ | PROT_EXEC)
|
||||
? kNtPageExecuteRead
|
||||
: HAS(prot, PROT_EXEC)
|
||||
? kNtPageExecute
|
||||
: HAS(prot, PROT_READ) ? kNtPageReadonly
|
||||
: kNtPageNoaccess) |
|
||||
((prot | flags) &
|
||||
(kNtSecReserve | kNtSecCommit | kNtSecImage | kNtSecImageNoExecute |
|
||||
kNtSecLargePages | kNtSecNocache | kNtSecWritecombine));
|
||||
}
|
|
@ -19,8 +19,10 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/getconsolectrlevent.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
/**
|
||||
|
@ -32,6 +34,7 @@
|
|||
*/
|
||||
int raise(int sig) {
|
||||
int event;
|
||||
STRACE("raise(%d)", sig);
|
||||
if (sig == SIGTRAP) {
|
||||
DebugBreak();
|
||||
return 0;
|
||||
|
@ -50,6 +53,6 @@ int raise(int sig) {
|
|||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
ExitProcess(128 + sig);
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,6 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
|||
}
|
||||
CloseHandle(h);
|
||||
} else {
|
||||
STRACE("%s failed %m", "CreateFile(kNtFileFlagOpenReparsePoint)");
|
||||
rc = sys_readlinkat_nt_error();
|
||||
}
|
||||
if (freeme && weaken(free)) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
|
@ -24,5 +25,8 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sleep(uint32_t seconds) {
|
||||
return nanosleep(&(struct timespec){seconds, 0}, NULL);
|
||||
int rc;
|
||||
rc = nanosleep(&(struct timespec){seconds, 0}, NULL);
|
||||
STRACE("sleep(%u) → %d% m", seconds, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,46 +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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Return path for failed Win32 API calls.
|
||||
*
|
||||
* @return -1 w/ few exceptions
|
||||
* @note this is a code-size saving device
|
||||
*/
|
||||
privileged int64_t __winerr(void) {
|
||||
errno_t e;
|
||||
if (IsWindows()) {
|
||||
e = __imp_GetLastError();
|
||||
if (weaken(__dos2errno)) {
|
||||
e = weaken(__dos2errno)(e);
|
||||
}
|
||||
} else {
|
||||
e = ENOSYS;
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue