Get fork() working on Windows

This is done without using Microsoft's internal APIs. MAP_PRIVATE
mappings are copied to the subprocess via a pipe, since Microsoft
doesn't want us to have proper COW pages. MAP_SHARED mappings are
remapped without needing to do any copying. Global variables need
copying along with the stack and the whole heap of anonymous mem.
This actually improves the reliability of the redbean http server
although one shouldn't expect 10k+ connections on a home computer
that isn't running software built to serve like Linux or FreeBSD.
main
Justine Tunney 2 years ago
parent aea89fe832
commit db33973e0a
  1. 11
      ape/ape.S
  2. 2
      ape/config.h
  3. 2
      build/compile
  4. 10
      dsp/core/core.mk
  5. 10
      dsp/tty/tty.mk
  6. 16
      examples/forkrand.c
  7. 51
      examples/forky.c
  8. 2
      examples/hello.c
  9. 5
      libc/calls/commandv.c
  10. 2
      libc/calls/dup-nt.c
  11. 2
      libc/calls/hefty/dirstream.c
  12. 158
      libc/calls/hefty/fork-nt.c
  13. 11
      libc/calls/hefty/fork.c
  14. 2
      libc/calls/hefty/ntspawn.c
  15. 1
      libc/calls/hefty/spawnlp.c
  16. 4
      libc/calls/hefty/spawnve-nt.c
  17. 4
      libc/calls/hefty/vfork.S
  18. 12
      libc/calls/internal.h
  19. 9
      libc/calls/wait.c
  20. 66
      libc/calls/wait4-nt.c
  21. 7
      libc/calls/zygote.c
  22. 4
      libc/isystem/windows.h
  23. 1
      libc/libc.mk
  24. 3
      libc/log/asan.c
  25. 6
      libc/log/log.mk
  26. 54
      libc/mem/putenv.c
  27. 4
      libc/nt/dll.h
  28. 35
      libc/nt/enum/color.h
  29. 8
      libc/nt/enum/cw.h
  30. 24
      libc/nt/enum/idc.h
  31. 10
      libc/nt/enum/pwr.h
  32. 19
      libc/nt/enum/sw.h
  33. 8
      libc/nt/enum/wa.h
  34. 7
      libc/nt/enum/wait.h
  35. 185
      libc/nt/enum/wm.h
  36. 62
      libc/nt/enum/ws.h
  37. 95
      libc/nt/events.h
  38. 24
      libc/nt/master.sh
  39. 41
      libc/nt/paint.h
  40. 16
      libc/nt/struct/drawtextparams.h
  41. 4
      libc/nt/struct/msg.h
  42. 18
      libc/nt/struct/paintstruct.h
  43. 15
      libc/nt/struct/rect.h
  44. 13
      libc/nt/struct/size.h
  45. 22
      libc/nt/struct/wndclass.h
  46. 24
      libc/nt/struct/wndclassex.h
  47. 4
      libc/nt/synchronization.h
  48. 10
      libc/nt/typedef/wndproc.h
  49. 12
      libc/nt/user32/DefWindowProcA.s
  50. 12
      libc/nt/user32/DefWindowProcW.s
  51. 10
      libc/nt/user32/FillRect.s
  52. 10
      libc/nt/user32/LoadCursorA.s
  53. 10
      libc/nt/user32/LoadCursorW.s
  54. 10
      libc/nt/user32/LoadImageA.s
  55. 10
      libc/nt/user32/LoadImageW.s
  56. 13
      libc/nt/user32/RegisterClassA.s
  57. 13
      libc/nt/user32/RegisterClassExA.s
  58. 13
      libc/nt/user32/RegisterClassExW.s
  59. 13
      libc/nt/user32/RegisterClassW.s
  60. 13
      libc/nt/user32/ShowCaret.s
  61. 13
      libc/nt/user32/ShowCursor.s
  62. 323
      libc/nt/windows.h
  63. 5
      libc/runtime/_exit.S
  64. 2
      libc/runtime/arememoryintervalsok.c
  65. 32
      libc/runtime/directmap.c
  66. 1
      libc/runtime/directmap.h
  67. 51
      libc/runtime/directmapnt.c
  68. 6
      libc/runtime/getdosargv.c
  69. 1
      libc/runtime/internal.h
  70. 38
      libc/runtime/jmpstack.S
  71. 20
      libc/runtime/memtrack.c
  72. 6
      libc/runtime/memtrack.h
  73. 2
      libc/runtime/memtracknt.c
  74. 4
      libc/runtime/mmap.c
  75. 22
      libc/runtime/mmi.c
  76. 2
      libc/runtime/msync-nt.c
  77. 1
      libc/runtime/runtime.h
  78. 5
      libc/runtime/runtime.mk
  79. 106
      libc/runtime/winmain.greg.c
  80. 16
      libc/runtime/winmain.h
  81. 3
      libc/sock/accept-nt.c
  82. 1
      libc/sock/internal.h
  83. 12
      libc/sock/kntwsadata.c
  84. 1
      libc/stdio/stdio.mk
  85. 146
      libc/stdio/system.c
  86. 1
      libc/sysv/sysv.mk
  87. 10
      net/http/http.mk
  88. 6
      test/ape/lib/test.mk
  89. 10
      test/dsp/core/test.mk
  90. 6
      test/libc/intrin/test.mk
  91. 102
      test/libc/runtime/memtrack_test.c
  92. 5
      test/libc/runtime/mmap_test.c
  93. 10
      test/libc/runtime/test.mk
  94. 6
      test/net/http/parsehttprequest_test.c
  95. 6
      test/net/http/test.mk
  96. 10
      third_party/stb/stb.mk
  97. 2
      tool/build/blinkenlights.c
  98. 8
      tool/build/build.mk
  99. 14
      tool/build/lib/buildlib.mk
  100. 2
      tool/build/lib/disarg.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -225,9 +225,14 @@ pc: cld
3: call pcread
dec %di
jnz 3b
6: mov %ax,XLM(LOADSTATE)+0
mov %cx,XLM(LOADSTATE)+2
mov %dx,XLM(LOADSTATE)+4
6: mov $XLM(LOADSTATE),%di # ax,cx,dx,es
stosw
xchg %cx,%ax
stosw
xchg %dx,%ax
stosw
mov %es,%ax
stosw
ljmp $0,$REAL(realmodeloader)
.endfn pc,globl,hidden

@ -126,7 +126,7 @@
#define XLM_BADIDT 0x2230
#define XLM_BADIDT_SIZE 6
#define XLM_LOADSTATE 0x2240
#define XLM_LOADSTATE_SIZE 6
#define XLM_LOADSTATE_SIZE 8
#define XLM_SIZE ROUNDUP(XLM_LOADSTATE + XLM_LOADSTATE_SIZE, 0x1000)
#define IMAGE_BASE_REAL (XLM_BASE_REAL + XLM_SIZE)

@ -280,5 +280,5 @@ if "$@"; then
exit 0
fi
printf "$LOGFMT" "$CCNAME $CCVERSION: compile $REASON:" "$*" >&2
printf "\n$LOGFMT" "$CCNAME $CCVERSION: compile $REASON:" "$*" >&2
exit 1

@ -58,11 +58,11 @@ o/$(MODE)/dsp/core/det3.o: \
OVERRIDE_CFLAGS += \
-ffast-math
ifeq (,$(MODE))
$(DSP_CORE_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
# ifeq (,$(MODE))
# $(DSP_CORE_OBJS): \
# OVERRIDE_CFLAGS += \
# -fsanitize=address
# endif
DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)))
DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS))

@ -59,11 +59,11 @@ o/$(MODE)/dsp/tty/ttyraster.o: \
OVERRIDE_CFLAGS += \
$(MATHEMATICAL)
ifeq (,$(MODE))
$(DSP_TTY_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
# ifeq (,$(MODE))
# $(DSP_TTY_OBJS): \
# OVERRIDE_CFLAGS += \
# -fsanitize=address
# endif
DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)))
DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS))

@ -7,18 +7,20 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/nt/nt/process.h"
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/calls/calls.h"
#include "libc/time/time.h"
noinline void dostuff(void) {
int i, us;
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
for (unsigned i = 0; i < 5; ++i) {
int us = rand() % 500000;
for (i = 0; i < 5; ++i) {
us = rand() % 500000;
usleep(us);
printf("%s%u%s%u [%s=%d]\n", "hello no. ", i, " from ", getpid(), "us", us);
fflush(stdout);
@ -26,9 +28,8 @@ noinline void dostuff(void) {
}
int main(int argc, char *argv[]) {
fprintf(stderr, "%p\n", RtlCloneUserProcess);
int child;
if ((child = fork()) == -1) perror("fork"), exit(1);
int rc, child, wstatus;
CHECK_NE(-1, (child = fork()));
if (!child) {
/* child process */
dostuff();
@ -37,8 +38,7 @@ int main(int argc, char *argv[]) {
/* parent process */
dostuff();
/* note: abandoned children become zombies */
int rc, wstatus;
if ((rc = wait(&wstatus)) == -1) perror("wait"), exit(1);
CHECK_NE(-1, (rc = wait(&wstatus)));
return WEXITSTATUS(wstatus);
}
}

@ -1,51 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/conv.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/x/x.h"
int main(int argc, char *argv[]) {
int pid;
long *addr;
int64_t fh;
if (argc == 1) {
fh = CreateFileMappingNuma(-1, &kNtIsInheritable, kNtPageReadwrite, 0,
FRAMESIZE, NULL, kNtNumaNoPreferredNode);
addr = MapViewOfFileExNuma(fh, kNtFileMapRead | kNtFileMapWrite, 0, 0,
FRAMESIZE, NULL, kNtNumaNoPreferredNode);
*addr = 0x31337;
CHECK_NE(-1, (pid = spawnve(
0, (int[3]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO},
"o/examples/forky.com",
(char *const[]){"o/examples/forky.com",
gc(xasprintf("%#lx", (intptr_t)addr)),
gc(xasprintf("%#lx", fh)), NULL},
environ)));
CHECK_NE(-1, waitpid(pid, NULL, 0));
} else {
addr = (long *)(intptr_t)strtoul(argv[1], NULL, 0);
fh = strtoul(argv[2], NULL, 0);
addr = MapViewOfFileExNuma(fh, kNtFileMapRead | kNtFileMapWrite, 0, 0,
FRAMESIZE, addr, kNtNumaNoPreferredNode);
printf("%#lx\n", *addr);
}
return 0;
}

@ -7,8 +7,6 @@
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
int main() {

@ -24,6 +24,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/nt/ntdll.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
@ -32,7 +33,7 @@
static int accessexe(char pathname[hasatleast PATH_MAX], size_t len,
const char *ext) {
len = stpcpy(&pathname[len], ext) - &pathname[0];
if (access(pathname, X_OK) != -1) {
if (isexecutable(pathname)) {
return len;
} else {
return -1;
@ -48,7 +49,7 @@ static int accesscmd(char pathname[hasatleast PATH_MAX], const char *path,
pathlen = strlen(path);
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
p = mempcpy(pathname, path, pathlen);
if (pathlen) *p++ = '/';
if (pathlen && pathname[pathlen - 1] != '/') *p++ = '/';
p = mempcpy(p, name, namelen);
len = p - &pathname[0];
hasdot = !!memchr(basename(name), '.', namelen);

@ -44,7 +44,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
}
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
GetCurrentProcess(), &g_fds.p[newfd].handle, 0,
(flags & O_CLOEXEC), kNtDuplicateSameAccess)) {
flags & O_CLOEXEC, kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].flags = flags;
return newfd;

@ -134,7 +134,7 @@ DIR *opendir(const char *name) {
DIR *res;
if (!IsWindows() && !IsXnu()) {
res = NULL;
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) {
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)) != -1) {
if (!(res = fdopendir(fd))) close(fd);
}
return res;

@ -0,0 +1,158 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/itoa.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/ipc.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
static textwindows int64_t ParseInt(char16_t **p) {
uint64_t x = 0;
while ('0' <= **p && **p <= '9') {
x *= 10;
x += *(*p)++ - '0';
}
return x;
}
static textwindows void WriteAll(int64_t h, void *buf, size_t n) {
char *p;
size_t i;
uint32_t wrote;
for (p = buf, i = 0; i < n; i += wrote) {
WriteFile(h, p + i, n - i, &wrote, NULL);
}
}
static textwindows void ReadAll(int64_t h, void *buf, size_t n) {
char *p;
size_t i;
uint32_t got;
for (p = buf, i = 0; i < n; i += got) {
ReadFile(h, p + i, n - i, &got, NULL);
}
}
textwindows void WinMainForked(void) {
int64_t h;
void *addr;
jmp_buf jb;
char16_t *p;
uint64_t size;
char16_t var[21 + 1 + 21 + 1];
uint32_t i, varlen, protect, access;
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
if (!varlen || varlen >= ARRAYLEN(var)) return;
p = var;
h = ParseInt(&p);
if (*p++ == ' ') CloseHandle(ParseInt(&p));
ReadAll(h, jb, sizeof(jb));
ReadAll(h, &_mmi.i, sizeof(_mmi.i));
for (i = 0; i < _mmi.i; ++i) {
ReadAll(h, &_mmi.p[i], sizeof(_mmi.p[i]));
addr = (void *)((uint64_t)_mmi.p[i].x << 16);
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE;
switch (_mmi.p[i].prot) {
case PROT_READ | PROT_WRITE | PROT_EXEC:
protect = kNtPageExecuteReadwrite;
access = kNtFileMapRead | kNtFileMapWrite | kNtFileMapExecute;
break;
case PROT_READ | PROT_WRITE:
protect = kNtPageReadwrite;
access = kNtFileMapRead | kNtFileMapWrite;
break;
case PROT_READ:
protect = kNtPageReadonly;
access = kNtFileMapRead;
break;
default:
protect = kNtPageNoaccess;
access = 0;
break;
}
if (_mmi.p[i].flags & MAP_PRIVATE) {
MapViewOfFileExNuma(
(_mmi.p[i].h = CreateFileMappingNuma(-1, NULL, protect, 0, size, NULL,
kNtNumaNoPreferredNode)),
access, 0, 0, size, addr, kNtNumaNoPreferredNode);
ReadAll(h, addr, size);
} else {
MapViewOfFileExNuma(_mmi.p[i].h, access, 0, 0, size, addr,
kNtNumaNoPreferredNode);
}
}
ReadAll(h, _edata, _end - _edata);
CloseHandle(h);
longjmp(jb, 1);
}
textwindows int fork$nt(void) {
jmp_buf jb;
int64_t reader, writer;
int i, rc, pid, fds[3];
char *p, buf[21 + 1 + 21 + 1];
if (!setjmp(jb)) {
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
p = buf;
p += uint64toarray_radix10(reader, p);
*p++ = ' ';
p += uint64toarray_radix10(writer, p);
setenv("_FORK", buf, true);
fds[0] = 0;
fds[1] = 1;
fds[2] = 2;
/* TODO: CloseHandle(g_fds.p[pid].h) if SIGCHLD is SIG_IGN */
if ((pid = spawnve(0, fds, g_argv[0], g_argv, environ)) != -1) {
CloseHandle(reader);
WriteAll(writer, jb, sizeof(jb));
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
for (i = 0; i < _mmi.i; ++i) {
WriteAll(writer, &_mmi.p[i], sizeof(_mmi.p[i]));
if (_mmi.p[i].flags & MAP_PRIVATE) {
WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE);
}
}
WriteAll(writer, _edata, _end - _edata);
CloseHandle(writer);
rc = pid;
} else {
rc = -1;
}
unsetenv("_FORK");
} else {
rc = winerr();
}
} else {
rc = 0;
}
return rc;
}

@ -20,6 +20,7 @@
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Creates new process zygote style.
@ -29,7 +30,13 @@
*/
int fork(void) {
int rc;
rc = fork$sysv();
if (rc == 0) __onfork();
if (!IsWindows()) {
rc = fork$sysv();
} else {
rc = fork$nt();
}
if (rc == 0) {
__onfork();
}
return rc;
}

@ -25,8 +25,10 @@
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/conv.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"

@ -21,6 +21,7 @@
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/mem/mem.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
/**

@ -67,7 +67,7 @@ textwindows int spawnve$nt(unsigned flags, int stdiofds[3], const char *program,
}
if (handle != -1 &&
ntspawn(program, argv, envp, NULL, NULL,
ntspawn(program, argv, envp, &kNtIsInheritable, NULL,
(flags & SPAWN_TABULARASA) ? false : true,
(flags & SPAWN_DETACH)
? (kNtCreateNewProcessGroup | kNtDetachedProcess |
@ -83,7 +83,7 @@ textwindows int spawnve$nt(unsigned flags, int stdiofds[3], const char *program,
if (handle != -1) {
stdiofds[i] = tubes[i];
g_fds.p[tubes[i]].kind = kFdFile;
g_fds.p[tubes[i]].flags = O_CLOEXEC;
g_fds.p[tubes[i]].flags = 0;
CloseHandle(sti.stdiofds[i]);
} else {
CloseHandle(tubes[i]);

@ -27,7 +27,9 @@
/
/ @return pid of child process or 0 if forked process
/ @returnstwice
vfork: mov __NR_vfork(%rip),%eax
vfork: testb IsWindows()
jnz fork$nt
mov __NR_vfork(%rip),%eax
cmp $-1,%eax
je systemfive.enosys
pop %rsi

@ -56,11 +56,11 @@ struct Fds {
extern const struct Fd kEmptyFd;
extern int g_sighandrvas[NSIG] hidden;
extern struct Fds g_fds hidden;
extern struct NtSystemInfo g_ntsysteminfo hidden;
extern struct NtStartupInfo g_ntstartupinfo hidden;
extern const struct NtSecurityAttributes kNtIsInheritable hidden;
hidden extern int g_sighandrvas[NSIG];
hidden extern struct Fds g_fds;
hidden extern struct NtSystemInfo g_ntsysteminfo;
hidden extern struct NtStartupInfo g_ntstartupinfo;
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
ssize_t createfd(void) hidden;
int growfds(void) hidden;
@ -218,6 +218,7 @@ void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
int gettimeofday$nt(struct timeval *, struct timezone *) hidden;
bool32 isatty$nt(int) hidden;
char *getcwd$nt(char *, size_t) hidden;
int fork$nt(void) hidden;
int chdir$nt(const char *) hidden;
int close$nt(int) hidden;
int dup$nt(int, int, int) hidden;
@ -258,6 +259,7 @@ int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
cosmopolitan § syscalls » windows nt » support
*/
void WinMainForked(void) hidden;
int getsetpriority$nt(int, unsigned, int, int (*)(int));
void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;

@ -18,9 +18,6 @@
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Waits for status to change on any child process.
@ -31,9 +28,5 @@
* @asyncsignalsafe
*/
int wait(int *opt_out_wstatus) {
if (!IsWindows()) {
return wait4$sysv(-1, opt_out_wstatus, 0, NULL);
} else {
return enosys(); /* TODO(jart) */
}
return wait4(-1, opt_out_wstatus, 0, NULL);
}

@ -21,11 +21,14 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/rusage.h"
#include "libc/conv/conv.h"
#include "libc/macros.h"
#include "libc/nt/accounting.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/filetime.h"
#include "libc/nt/synchronization.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/w.h"
@ -33,34 +36,51 @@
textwindows int wait4$nt(int pid, int *opt_out_wstatus, int options,
struct rusage *opt_out_rusage) {
int pids[64];
int64_t handles[64];
uint32_t dwExitCode;
uint32_t i, count, timeout;
struct NtFileTime createfiletime, exitfiletime, kernelfiletime, userfiletime;
if (!isfdkind(pid, kFdProcess)) return esrch();
for (;;) {
dwExitCode = kNtStillActive;
if (!(options & WNOHANG)) {
WaitForSingleObject(g_fds.p[pid].handle, 0xffffffff);
if (pid != -1) {
if (!isfdkind(pid, kFdProcess)) {
return echild();
}
if (GetExitCodeProcess(g_fds.p[pid].handle, &dwExitCode)) {
if (dwExitCode != kNtStillActive) {
if (opt_out_wstatus) { /* @see WEXITSTATUS() */
*opt_out_wstatus = (dwExitCode & 0xff) << 8;
}
if (opt_out_rusage) {
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
GetProcessTimes(GetCurrentProcess(), &createfiletime, &exitfiletime,
&kernelfiletime, &userfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_utime, userfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_stime, kernelfiletime);
}
return pid;
} else if (options & WNOHANG) {
return pid;
} else {
continue;
handles[0] = g_fds.p[pid].handle;
pids[0] = pid;
count = 1;
} else {
for (count = 0, i = g_fds.n; i--;) {
if (g_fds.p[i].kind == kFdProcess) {
pids[count] = i;
handles[count] = g_fds.p[i].handle;
if (++count == ARRAYLEN(handles)) break;
}
}
if (!count) {
return echild();
}
}
for (;;) {
dwExitCode = kNtStillActive;
if (options & WNOHANG) {
i = WaitForMultipleObjects(count, handles, false, 0);
if (i == kNtWaitTimeout) return 0;
} else {
return winerr();
i = WaitForMultipleObjects(count, handles, false, -1);
}
if (i == kNtWaitFailed) return winerr();
if (!GetExitCodeProcess(handles[i], &dwExitCode)) return winerr();
if (dwExitCode == kNtStillActive) continue;
if (opt_out_wstatus) { /* @see WEXITSTATUS() */
*opt_out_wstatus = (dwExitCode & 0xff) << 8;
}
if (opt_out_rusage) {
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
GetProcessTimes(GetCurrentProcess(), &createfiletime, &exitfiletime,
&kernelfiletime, &userfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_utime, userfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_stime, kernelfiletime);
}
return pids[i];
}
}

@ -17,8 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/nt/struct/securityattributes.h"
#include "libc/calls/internal.h"
#include "libc/nt/struct/securityattributes.h"
const struct NtSecurityAttributes kNtIsInheritable = {
sizeof(struct NtSecurityAttributes), NULL, true};
sizeof(struct NtSecurityAttributes),
NULL,
true,
};

@ -69,9 +69,9 @@
#define PINT_PTR intptr_t*
#define UINT_PTR uintptr_t
#define PUINT_PTR uintptr_t*
#define LONG_PTR int32_t*
#define LONG_PTR intptr_t
#define PLONG_PTR int32_t**
#define ULONG_PTR uint32_t*
#define ULONG_PTR uintptr_t
#define PULONG_PTR uint32_t**
#define POINTER_64_INT int64_t*
#define __int3264 int64_t

@ -15,7 +15,6 @@ o/$(MODE)/libc: o/$(MODE)/libc/alg \
o/$(MODE)/libc/crt \
o/$(MODE)/libc/dns \
o/$(MODE)/libc/elf \
o/$(MODE)/libc/escape \
o/$(MODE)/libc/fmt \
o/$(MODE)/libc/intrin \
o/$(MODE)/libc/linux \

@ -401,7 +401,8 @@ void __asan_map_shadow(void *p, size_t n) {
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (sm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, a, a, sm.maphandle) == -1) {
TrackMemoryInterval(&_mmi, a, a, sm.maphandle, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) == -1) {
abort();
}
}

@ -64,9 +64,9 @@ $(LIBC_LOG_A_OBJS): \
$(NO_MAGIC) \
-fwrapv
ifeq (,$(MODE))
LIBC_LOG_ASAN = o/$(MODE)/libc/log/asan.o
endif
# ifeq (,$(MODE))
# LIBC_LOG_ASAN = o/$(MODE)/libc/log/asan.o
# endif
LIBC_LOG_ASAN_A = o/$(MODE)/libc/log/log.a
LIBC_LOG_LIBS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)))

@ -24,53 +24,49 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static size_t g_environcap;
#define MAX_VARS 512
int PutEnvImpl(char *string, bool overwrite) {
if (!environ) {
g_environcap = 0;
if ((environ = calloc(8, sizeof(char *)))) {
g_environcap = 8;
}
}
char *equalp = strchr(string, '=');
if (!equalp) return einval();
unsigned namelen = equalp + 1 - string;
unsigned i;
int PutEnvImpl(char *s, bool overwrite) {
char *p;
unsigned i, namelen;
p = strchr(s, '=');
if (!p) goto fail;
namelen = p + 1 - s;
for (i = 0; environ[i]; ++i) {
if (strncmp(environ[i], string, namelen) == 0) {
if (strncmp(environ[i], s, namelen) == 0) {
if (!overwrite) {
free_s(&string);
free(s);
return 0;
}
goto replace;
}
}
if (i + 1 >= g_environcap) {
if (!g_environcap) g_environcap = i + 1;
if (!grow(&environ, &g_environcap, sizeof(char *), 0)) {
free_s(&string);
return -1;
}
}
if (i + 1 >= MAX_VARS) goto fail;
environ[i + 1] = NULL;
replace:
free_s(&environ[i]);
environ[i] = string;
free(environ[i]);
environ[i] = s;
return 0;
fail:
free(s);
return einval();
}
/**
* Emplaces environment key=value.
* @see setenv(), getenv()
*/
int putenv(char *string) { return PutEnvImpl(string, true); }
textexit static void putenv_fini(void) {
for (char **envp = environ; *envp; ++envp) free_s(envp);
free_s(&environ);
int putenv(char *string) {
return PutEnvImpl(strdup(string), true);
}
textstartup static void putenv_init(void) { atexit(putenv_fini); }
textstartup static void putenv_init(void) {
char **pin, **pout;
pin = environ;
pout = malloc(sizeof(char *) * MAX_VARS);
environ = pout;
while (*pin) *pout++ = strdup(*pin++);
*pout = NULL;
}
const void *const putenv_ctor[] initarray = {putenv_init};

@ -34,8 +34,8 @@ int64_t LoadLibraryEx(const char16_t *lpLibFileName, int64_t hFile,
uint32_t dwFlags);
uint32_t GetModuleFileName(int64_t hModule, char16_t *lpFilename,
uint32_t nSize);
intptr_t GetModuleHandle(const char *lpModuleName);
intptr_t GetModuleHandleW(const char16_t *lpModuleName);
intptr_t GetModuleHandle(const char *opt_lpModuleName);
intptr_t GetModuleHandleW(const char16_t *opt_lpModuleName);
void *GetProcAddress(int64_t hModule, const char *lpProcName);
int32_t FreeResource(int64_t hResData);
intptr_t LockResource(int64_t hResData);

@ -0,0 +1,35 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_COLOR_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_COLOR_H_
#define kNtColorScrollbar 0
#define kNtColorBackground 1
#define kNtColorActivecaption 2
#define kNtColorInactivecaption 3
#define kNtColorMenu 4
#define kNtColorWindow 5
#define kNtColorWindowframe 6
#define kNtColorMenutext 7
#define kNtColorWindowtext 8
#define kNtColorCaptiontext 9
#define kNtColorActiveborder 10
#define kNtColorInactiveborder 11
#define kNtColorAppworkspace 12
#define kNtColorHighlight 13
#define kNtColorHighlighttext 14
#define kNtColorBtnface 15
#define kNtColorBtnshadow 16
#define kNtColorGraytext 17
#define kNtColorBtntext 18
#define kNtColorInactivecaptiontext 19
#define kNtColorBtnhighlight 20
#define kNtColor3ddkshadow 21
#define kNtColor3dlight 22
#define kNtColorInfotext 23
#define kNtColorInfobk 24
#define kNtColorHotlight 26
#define kNtColorGradientactivecaption 27
#define kNtColorGradientinactivecaption 28
#define kNtColorMenuhilight 29
#define kNtColorMenubar 30
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_COLOR_H_ */

@ -0,0 +1,8 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_CW_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_CW_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define kNtCwUsedefault ((int)0x80000000)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_CW_H_ */

@ -0,0 +1,24 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_IDC_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_IDC_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define kNtIdcArrow ((const char16_t *)32512)
#define kNtIdcIbeam ((const char16_t *)32513)
#define kNtIdcWait ((const char16_t *)32514)
#define kNtIdcCross ((const char16_t *)32515)
#define kNtIdcUparrow ((const char16_t *)32516)
#define kNtIdcSizenwse ((const char16_t *)32642)
#define kNtIdcSizenesw ((const char16_t *)32643)
#define kNtIdcSizewe ((const char16_t *)32644)
#define kNtIdcSizens ((const char16_t *)32645)
#define kNtIdcSizeall ((const char16_t *)32646)
#define kNtIdcNo ((const char16_t *)32648)
#define kNtIdcHand ((const char16_t *)32649)
#define kNtIdcHelp ((const char16_t *)32651)
#define kNtIdcPin ((const char16_t *)32671)
#define kNtIdcPerson ((const char16_t *)32672)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_IDC_H_ */

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_PWR_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_PWR_H_
#define kNtPwrOk 1
#define kNtPwrFail (-1)
#define kNtPwrSuspendrequest 1
#define kNtPwrSuspendresume 2
#define kNtPwrCriticalresume 3
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_PWR_H_ */

@ -0,0 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_SW_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_SW_H_
#define kNtSwHide 0
#define kNtSwShownormal 1
#define kNtSwNormal 1
#define kNtSwShowminimized 2
#define kNtSwShowmaximized 3
#define kNtSwMaximize 3
#define kNtSwShownoactivate 4
#define kNtSwShow 5
#define kNtSwMinimize 6
#define kNtSwShowminnoactive 7
#define kNtSwShowna 8
#define kNtSwRestore 9
#define kNtSwShowdefault 10
#define kNtSwForceminimize 11
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_SW_H_ */

@ -0,0 +1,8 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_WA_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_WA_H_
#define kNtWaInactive 0
#define kNtWaActive 1
#define kNtWaClickactive 2
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_WA_H_ */

@ -0,0 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_WAIT_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_WAIT_H_
#define kNtWaitFailed 0xffffffffu
#define kNtWaitTimeout 0x00000102u
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_WAIT_H_ */

@ -0,0 +1,185 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_WM_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_WM_H_
#define kNtWmNull 0x0000
#define kNtWmCreate 0x0001
#define kNtWmDestroy 0x0002
#define kNtWmMove 0x0003
#define kNtWmSize 0x0005
#define kNtWmActivate 0x0006
#define kNtWmSetfocus 0x0007
#define kNtWmKillfocus 0x0008
#define kNtWmEnable 0x000A
#define kNtWmSetredraw 0x000B
#define kNtWmSettext 0x000C
#define kNtWmGettext 0x000D
#define kNtWmGettextlength 0x000E
#define kNtWmPaint 0x000F
#define kNtWmClose 0x0010
#define kNtWmQueryendsession 0x0011
#define kNtWmQueryopen 0x0013
#define kNtWmEndsession 0x0016
#define kNtWmQuit 0x0012
#define kNtWmErasebkgnd 0x0014
#define kNtWmSyscolorchange 0x0015
#define kNtWmShowwindow 0x0018
#define kNtWmWininichange 0x001A
#define kNtWmSettingchange kNtWmWininichange
#define kNtWmDevmodechange 0x001B
#define kNtWmActivateapp 0x001C
#define kNtWmFontchange 0x001D
#define kNtWmTimechange 0x001E
#define kNtWmCancelmode 0x001F
#define kNtWmSetcursor 0x0020
#define kNtWmMouseactivate 0x0021
#define kNtWmChildactivate 0x0022
#define kNtWmQueuesync 0x0023
#define kNtWmGetminmaxinfo 0x0024
#define kNtWmPainticon 0x0026
#define kNtWmIconerasebkgnd 0x0027
#define kNtWmNextdlgctl 0x0028
#define kNtWmSpoolerstatus 0x002A
#define kNtWmDrawitem 0x002B
#define kNtWmMeasureitem 0x002C
#define kNtWmDeleteitem 0x002D
#define kNtWmVkeytoitem 0x002E
#define kNtWmChartoitem 0x002F
#define kNtWmSetfont 0x0030
#define kNtWmGetfont 0x0031
#define kNtWmSethotkey 0x0032
#define kNtWmGethotkey 0x0033
#define kNtWmQuerydragicon 0x0037
#define kNtWmCompareitem 0x0039
#define kNtWmGetobject 0x003D
#define kNtWmCompacting 0x0041
#define kNtWmWindowposchanging 0x0046
#define kNtWmWindowposchanged 0x0047
#define kNtWmPower 0x0048
#define kNtWmCopydata 0x004A
#define kNtWmCanceljournal 0x004B
#define kNtWmNotify 0x004E
#define kNtWmInputlangchangerequest 0x0050
#define kNtWmInputlangchange 0x0051
#define kNtWmTcard 0x0052
#define kNtWmHelp 0x0053
#define kNtWmUserchanged 0x0054
#define kNtWmNotifyformat 0x0055
#define kNtWmContextmenu 0x007B
#define kNtWmStylechanging 0x007C
#define kNtWmStylechanged 0x007D
#define kNtWmDisplaychange 0x007E
#define kNtWmGeticon 0x007F
#define kNtWmSeticon 0x0080
#define kNtWmNccreate 0x0081
#define kNtWmNcdestroy 0x0082
#define kNtWmNccalcsize 0x0083
#define kNtWmNchittest 0x0084
#define kNtWmNcpaint 0x0085
#define kNtWmNcactivate 0x0086
#define kNtWmGetdlgcode 0x0087
#define kNtWmNcmousemove 0x00A0
#define kNtWmNclbuttondown 0x00A1
#define kNtWmNclbuttonup 0x00A2
#define kNtWmNclbuttondblclk 0x00A3
#define kNtWmNcrbuttondown 0x00A4
#define kNtWmNcrbuttonup 0x00A5
#define kNtWmNcrbuttondblclk 0x00A6
#define kNtWmNcmbuttondown 0x00A7
#define kNtWmNcmbuttonup 0x00A8
#define kNtWmNcmbuttondblclk 0x00A9
#define kNtWmNcxbuttondown 0x00AB
#define kNtWmNcxbuttonup 0x00AC
#define kNtWmNcxbuttondblclk 0x00AD
#define kNtWmKeyfirst 0x0100
#define kNtWmKeydown 0x0100
#define kNtWmKeyup 0x0101
#define kNtWmChar 0x0102
#define kNtWmDeadchar 0x0103
#define kNtWmSyskeydown 0x0104
#define kNtWmSyskeyup 0x0105
#define kNtWmSyschar 0x0106
#define kNtWmSysdeadchar 0x0107
#define kNtWmUnichar 0x0109
#define kNtWmKeylast 0x0109
#define kNtWmInitdialog 0x0110
#define kNtWmCommand 0x0111
#define kNtWmSyscommand 0x0112
#define kNtWmTimer 0x0113
#define kNtWmHscroll 0x0114
#define kNtWmVscroll 0x0115
#define kNtWmInitmenu 0x0116
#define kNtWmInitmenupopup 0x0117
#define kNtWmGesture 0x0119
#define kNtWmGesturenotify 0x011A
#define kNtWmMenuselect 0x011F
#define kNtWmMenuchar 0x0120
#define kNtWmEnteridle 0x0121
#define kNtWmMenurbuttonup 0x0122
#define kNtWmMenudrag 0x0123
#define kNtWmMenugetobject 0x0124
#define kNtWmUninitmenupopup 0x0125
#define kNtWmMenucommand 0x0126
#define kNtWmChangeuistate 0x0127
#define kNtWmUpdateuistate 0x0128
#define kNtWmQueryuistate 0x0129
#define kNtWmMousefirst 0x0200
#define kNtWmMousemove 0x0200
#define kNtWmLbuttondown 0x0201
#define kNtWmLbuttonup 0x0202
#define kNtWmLbuttondblclk 0x0203
#define kNtWmRbuttondown 0x0204
#define kNtWmRbuttonup 0x0205
#define kNtWmRbuttondblclk 0x0206
#define kNtWmMbuttondown 0x0207
#define kNtWmMbuttonup 0x0208
#define kNtWmMbuttondblclk 0x0209
#define kNtWmMousewheel 0x020A
#define kNtWmXbuttondown 0x020B
#define kNtWmXbuttonup 0x020C
#define kNtWmXbuttondblclk 0x020D
#define kNtWmMousehwheel 0x020E
#define kNtWmMouselast 0x020E
#define kNtWmParentnotify 0x0210
#define kNtWmEntermenuloop 0x0211
#define kNtWmExitmenuloop 0x0212
#define kNtWmNextmenu 0x0213
#define kNtWmSizing 0x0214
#define kNtWmCapturechanged 0x0215
#define kNtWmMoving 0x0216
#define kNtWmPowerbroadcast 0x0218
#define kNtWmMdicreate 0x0220
#define kNtWmMdidestroy 0x0221
#define kNtWmMdiactivate 0x0222
#define kNtWmMdirestore 0x0223
#define kNtWmMdinext 0x0224
#define kNtWmMdimaximize 0x0225
#define kNtWmMditile 0x0226
#define kNtWmMdicascade 0x0227
#define kNtWmMdiiconarrange 0x0228
#define kNtWmMdigetactive 0x0229
#define kNtWmMdisetmenu 0x0230
#define kNtWmEntersizemove 0x0231
#define kNtWmExitsizemove 0x0232
#define kNtWmDropfiles 0x0233
#define kNtWmMdirefreshmenu 0x0234
#define kNtWmCut 0x0300
#define kNtWmCopy 0x0301
#define kNtWmPaste 0x0302
#define kNtWmClear 0x0303
#define kNtWmUndo 0x0304
#define kNtWmRenderformat 0x0305
#define kNtWmRenderallformats 0x0306
#define kNtWmDestroyclipboard 0x0307
#define kNtWmDrawclipboard 0x0308
#define kNtWmPaintclipboard 0x0309
#define kNtWmVscrollclipboard 0x030A
#define kNtWmSizeclipboard 0x030B
#define kNtWmAskcbformatname 0x030C
#define kNtWmChangecbchain 0x030D
#define kNtWmHscrollclipboard 0x030E
#define kNtWmQuerynewpalette 0x030F
#define kNtWmPaletteischanging 0x0310
#define kNtWmPalettechanged 0x0311
#define kNtWmHotkey 0x0312
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_WM_H_ */

@ -0,0 +1,62 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_WS_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_WS_H_
#define kNtWsOverlapped 0x00000000
#define kNtWsPopup 0x80000000
#define kNtWsChild 0x40000000
#define kNtWsMinimize 0x20000000
#define kNtWsVisible 0x10000000
#define kNtWsDisabled 0x08000000
#define kNtWsClipsiblings 0x04000000
#define kNtWsClipchildren 0x02000000
#define kNtWsMaximize 0x01000000
#define kNtWsCaption 0x00C00000
#define kNtWsBorder 0x00800000
#define kNtWsDlgframe 0x00400000
#define kNtWsVscroll 0x00200000
#define kNtWsHscroll 0x00100000
#define kNtWsSysmenu 0x00080000
#define kNtWsThickframe 0x00040000
#define kNtWsGroup 0x00020000
#define kNtWsTabstop 0x00010000
#define kNtWsMinimizebox 0x00020000
#define kNtWsMaximizebox 0x00010000
#define kNtWsTiled kNtWsOverlapped
#define kNtWsIconic kNtWsMinimize
#define kNtWsSizebox kNtWsThickframe
#define kNtWsTiledwindow kNtWsOverlappedwindow
#define kNtWsOverlappedwindow \
(kNtWsOverlapped | kNtWsCaption | kNtWsSysmenu | kNtWsThickframe | \
kNtWsMinimizebox | kNtWsMaximizebox)
#define kNtWsPopupwindow (kNtWsPopup | kNtWsBorder | kNtWsSysmenu)
#define kNtWsExDlgmodalframe 0x00000001
#define kNtWsExNoparentnotify 0x00000004
#define kNtWsExTopmost 0x00000008
#define kNtWsExAcceptfiles 0x00000010
#define kNtWsExTransparent 0x00000020
#define kNtWsExMdichild 0x00000040
#define kNtWsExToolwindow 0x00000080
#define kNtWsExWindowedge 0x00000100
#define kNtWsExClientedge 0x00000200
#define kNtWsExContexthelp 0x00000400
#define kNtWsExRight 0x00001000
#define kNtWsExLeft 0x00000000
#define kNtWsExRtlreading 0x00002000
#define kNtWsExLtrreading 0x00000000
#define kNtWsExLeftscrollbar 0x00004000
#define kNtWsExRightscrollbar 0x00000000
#define kNtWsExControlparent 0x00010000
#define kNtWsExStaticedge 0x00020000
#define kNtWsExAppwindow 0x00040000
#define kNtWsExNoinheritlayout 0x00100000
#define kNtWsExNoredirectionbitmap 0x00200000
#define kNtWsExLayoutrtl 0x00400000
#define kNtWsExComposited 0x02000000
#define kNtWsExNoactivate 0x08000000
#define kNtWsExOverlappedwindow (kNtWsExWindowedge | kNtWsExClientedge)
#define kNtWsExPalettewindow \
(kNtWsExWindowedge | kNtWsExToolwindow | kNtWsExTopmost)
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_WS_H_ */

@ -1,5 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_NT_EVENTS_H_
#define COSMOPOLITAN_LIBC_NT_EVENTS_H_
#include "libc/nt/struct/msg.h"
#include "libc/nt/struct/point.h"
#if 0
/* ░░░░
@ -27,64 +29,61 @@
*/
#endif
#define NT_EVENT_SYSTEM_SOUND 0x0001
#define NT_EVENT_SYSTEM_ALERT 0x0002
#define NT_EVENT_SYSTEM_FOREGROUND 0x0003
#define NT_EVENT_SYSTEM_MENUSTART 0x0004
#define NT_EVENT_SYSTEM_MENUEND 0x0005
#define NT_EVENT_SYSTEM_MENUPOPUPSTART 0x0006
#define NT_EVENT_SYSTEM_MENUPOPUPEND 0x0007
#define NT_EVENT_SYSTEM_CAPTURESTART 0x0008
#define NT_EVENT_SYSTEM_CAPTUREEND 0x0009
#define NT_EVENT_SYSTEM_MOVESIZESTART 0x000A
#define NT_EVENT_SYSTEM_MOVESIZEEND 0x000B
#define NT_EVENT_SYSTEM_SOUND 0x0001
#define NT_EVENT_SYSTEM_ALERT 0x0002
#define NT_EVENT_SYSTEM_FOREGROUND 0x0003
#define NT_EVENT_SYSTEM_MENUSTART 0x0004
#define NT_EVENT_SYSTEM_MENUEND 0x0005
#define NT_EVENT_SYSTEM_MENUPOPUPSTART 0x0006
#define NT_EVENT_SYSTEM_MENUPOPUPEND 0x0007
#define NT_EVENT_SYSTEM_CAPTURESTART 0x0008
#define NT_EVENT_SYSTEM_CAPTUREEND 0x0009
#define NT_EVENT_SYSTEM_MOVESIZESTART 0x000A