Add epoll and do more release readiness changes
This change also pays off some of the remaining technical debt with stdio, file descriptors, and memory managemnt polyfills.main
parent
a9ea949df8
commit
3e4fd4b0ad
2
Makefile
2
Makefile
|
@ -316,7 +316,7 @@ COSMOPOLITAN_HEADERS = \
|
|||
|
||||
o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_OBJS)))
|
||||
o/cosmopolitan.h: \
|
||||
o/$(MODE)/tool/build/rollup.com.dbg \
|
||||
o/$(MODE)/tool/build/rollup.com \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
|
||||
@ACTION=ROLLUP TARGET=$@ build/do $^ >$@
|
||||
|
|
205
ape/ape.S
205
ape/ape.S
|
@ -34,7 +34,6 @@
|
|||
│ αcτµαlly pδrταblε εxεcµταblε § program header │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/config.h"
|
||||
#include "ape/lib/apm.h"
|
||||
#include "ape/lib/pc.h"
|
||||
#include "ape/macros.h"
|
||||
#include "ape/notice.inc"
|
||||
|
@ -49,7 +48,7 @@
|
|||
|
||||
#define USE_SYMBOL_HACK 0
|
||||
|
||||
.source "NOTICE"
|
||||
.source "LICENSE"
|
||||
.source "ape/ape.S"
|
||||
.source "ape/ape.lds"
|
||||
.section .text,"ax",@progbits
|
||||
|
@ -360,85 +359,9 @@ pcread: push %ax
|
|||
xor %ax,%ax # try disk reset on error
|
||||
int $0x13
|
||||
pop %ax
|
||||
jmp 1b
|
||||
jmp pcread
|
||||
.endfn pcread
|
||||
|
||||
/ Waits for serial lines to become idle.
|
||||
/
|
||||
/ @param di short array of serial ports (0 means not present)
|
||||
/ @param si number of items in array
|
||||
/ @mode long,legacy,real
|
||||
sflush: mov %si,%cx
|
||||
mov %di,%si
|
||||
xor %dx,%dx
|
||||
0: lodsb
|
||||
mov %al,%dl
|
||||
lodsb
|
||||
mov %al,%dh
|
||||
test %ax,%ax
|
||||
jz 2f
|
||||
add $UART_LSR,%dx
|
||||
mov $UART_TTYIDL,%ah
|
||||
1: in %dx,%al
|
||||
and %ah,%al
|
||||
rep
|
||||
nop
|
||||
jz 1b
|
||||
loop 0b
|
||||
2: ret
|
||||
.endfn sflush,globl
|
||||
|
||||
/ Transmits byte over serial line.
|
||||
/
|
||||
/ This is both blocking and asynchronous.
|
||||
/
|
||||
/ @param di character to send
|
||||
/ @param si serial port
|
||||
/ @mode long,legacy,real
|
||||
/ @see ttytxr
|
||||
sputc: push %ax
|
||||
push %cx
|
||||
push %dx
|
||||
mov %si,%dx
|
||||
add $UART_LSR,%dx
|
||||
mov $UART_TTYTXR,%ah
|
||||
1: in %dx,%al
|
||||
and %ah,%al
|
||||
jnz 2f
|
||||
rep
|
||||
nop
|
||||
jmp 1b
|
||||
2: mov %di,%ax
|
||||
mov %si,%dx
|
||||
out %al,%dx
|
||||
pop %dx
|
||||
pop %cx
|
||||
pop %ax
|
||||
ret
|
||||
.endfn sputc,globl
|
||||
|
||||
/ Shuts down personal computer.
|
||||
/
|
||||
/ @mode real
|
||||
/ @noreturn
|
||||
apmoff: mov $0x5300,%ax # apm installation check
|
||||
xor %bx,%bx # for the apm bios itself
|
||||
int $APM_SERVICE
|
||||
jc 1f
|
||||
cmp $'P<<8|'M,%bx # did apm bios service interrupt?
|
||||
jne 1f
|
||||
mov $0x5301,%ax # real mode interface connect
|
||||
xor %bx,%bx # to apm bios device
|
||||
int $APM_SERVICE # ignore errors e.g. already connected
|
||||
xor %bx,%bx
|
||||
xor %cx,%cx
|
||||
mov $0x5307,%ax # set power state
|
||||
mov $1,%bl # for all devices within my dominion
|
||||
mov $3,%cl # to off
|
||||
int $APM_SERVICE
|
||||
1: call panic
|
||||
.endfn apmoff,globl
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ αcτµαlly pδrταblε εxεcµταblε § partition table ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
@ -1156,115 +1079,41 @@ sinit: mov %di,%dx
|
|||
2: ret
|
||||
.endfn sinit,global,hidden
|
||||
|
||||
/ Abnormally exits program.
|
||||
/
|
||||
/ @param di message
|
||||
/ @mode real
|
||||
/ @noreturn
|
||||
rldie: call rlpute
|
||||
call rloff
|
||||
.endfn rldie,globl,hidden
|
||||
|
||||
/ Shuts down machine.
|
||||
/
|
||||
/ @mode real
|
||||
/ @noreturn
|
||||
rloff: mov $kBiosDataAreaXlm+COM1,%di
|
||||
mov $4,%si
|
||||
call sflush
|
||||
call apmoff
|
||||
.endfn rloff,globl,hidden
|
||||
|
||||
/ Prints error message.
|
||||
/
|
||||
/ @param di message
|
||||
/ @mode real
|
||||
rlpute: mov kBiosDataAreaXlm+METAL_STDERR(%bx),%si
|
||||
test %si,%si
|
||||
jnz 1f
|
||||
mov kBiosDataAreaXlm+METAL_STDOUT,%si
|
||||
1: xor %ax,%ax
|
||||
push %ax
|
||||
push %si
|
||||
mov $REAL(.Lstr.crlf),%ax
|
||||
push %ax
|
||||
push %si
|
||||
push %di
|
||||
push %si
|
||||
mov $REAL(.Lstr.error),%ax
|
||||
push %ax
|
||||
1: pop %di
|
||||
test %di,%di
|
||||
jz 2f
|
||||
pop %si
|
||||
call rlput2
|
||||
jmp 1b
|
||||
2: ret
|
||||
.endfn rlpute,globl,hidden
|
||||
|
||||
/ Prints string to both video and serial.
|
||||
/
|
||||
/ @param di NUL-terminated string
|
||||
/ @param si serial port
|
||||
/ @mode real
|
||||
rlput2: push %di
|
||||
push %si
|
||||
call rvputs
|
||||
pop %si
|
||||
pop %di
|
||||
test %si,%si
|
||||
jz 1f
|
||||
call sputs
|
||||
1: ret
|
||||
.endfn rlput2,globl,hidden
|
||||
|
||||
/ Writes string to serial line.
|
||||
/
|
||||
/ @param di NUL-terminated string
|
||||
/ @param si serial port
|
||||
/ @mode long,legacy,real
|
||||
sputs: push %bx
|
||||
mov %di,%bx
|
||||
1: xchg %bx,%si
|
||||
lodsb
|
||||
xchg %bx,%si
|
||||
test %al,%al
|
||||
jz 2f
|
||||
mov %ax,%di
|
||||
push %si
|
||||
rlcall sputc
|
||||
pop %si
|
||||
jmp 1b
|
||||
2: pop %bx
|
||||
ret
|
||||
.endfn sputs,globl
|
||||
|
||||
/ Video put string.
|
||||
/
|
||||
/ @param di is the string
|
||||
/ @mode real
|
||||
rvputs: mov %di,%si
|
||||
rvputs: push %bp
|
||||
push %bx
|
||||
mov %di,%si
|
||||
0: lodsb
|
||||
test %al,%al
|
||||
je 1f
|
||||
rlcall rvputc
|
||||
jmp 0b
|
||||
1: ret
|
||||
.endfn rvputs,globl,hidden
|
||||
|
||||
/ Video put char.
|
||||
/
|
||||
/ @param al is the char
|
||||
/ @mode real
|
||||
rvputc: push %bx # don't clobber bp,bx,di,si,cx
|
||||
push %bp # original ibm pc scroll up bug
|
||||
mov $7,%bx # normal mda/cga style page zero
|
||||
mov $0x0e,%ah # teletype output al cp437
|
||||
int $0x10 # vidya service
|
||||
pop %bp # preserves al
|
||||
pop %bx
|
||||
jmp 0b
|
||||
1: pop %bx
|
||||
pop %bp
|
||||
ret
|
||||
.endfn rvputc
|
||||
.endfn rvputs,globl,hidden
|
||||
|
||||
/ Abnormally halts startup.
|
||||
/
|
||||
/ @param di message
|
||||
/ @mode real
|
||||
/ @noreturn
|
||||
rldie: push %di
|
||||
mov $REAL(.Lstr.error),%di
|
||||
call rvputs
|
||||
pop %di
|
||||
call rvputs
|
||||
mov $REAL(.Lstr.crlf),%di
|
||||
call rvputs
|
||||
xor %ax,%ax # get keystroke
|
||||
int $0x16 # keyboard service
|
||||
jmp triplf
|
||||
.endfn rldie,globl,hidden
|
||||
|
||||
/* █ █▒
|
||||
█ █
|
||||
|
@ -1321,6 +1170,7 @@ longmodeloader:
|
|||
jc 9f
|
||||
call unreal
|
||||
/ call hiload
|
||||
call pinit
|
||||
jmp golong
|
||||
9: mov $REAL(.Lstr.e820),%ax
|
||||
call rldie
|
||||
|
@ -1568,7 +1418,6 @@ pinit: push %ds
|
|||
/ @see Intel Manual V3A §4.1.2
|
||||
golong: cli
|
||||
lidt XLM(BADIDT)
|
||||
call pinit
|
||||
mov %cr4,%eax
|
||||
or $CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
|
||||
mov %eax,%cr4
|
||||
|
|
|
@ -21,7 +21,7 @@ APE_LIB_A_OBJS = \
|
|||
$(APE_LIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
o/$(MODE)/ape/ape.lds.zip.o \
|
||||
o/$(MODE)/ape/ape.S.zip.o \
|
||||
o/$(MODE)/NOTICE.zip.o
|
||||
o/$(MODE)/LICENSE.zip.o
|
||||
|
||||
APE_LIB_A_CHECKS = $(APE_LIB_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
APE_LIB_A_DIRECTDEPS = LIBC_STR LIBC_STUBS
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/* UNIX v7 usr/src/games/hangman.c
|
||||
*
|
||||
* Copyright 2002 Caldera International Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code and documentation must retain the
|
||||
* above copyright notice, this list of conditions and the following
|
||||
* disclaimer. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided with
|
||||
* the distribution.
|
||||
*
|
||||
* All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed or owned by Caldera
|
||||
* International, Inc.
|
||||
*
|
||||
* Neither the name of Caldera International, Inc. nor the names of
|
||||
* other contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENCE BY CALDERA
|
||||
* INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
/* clang-format off */
|
||||
#define DICT "usr/share/dict/hangman"
|
||||
#define MAXERR 7
|
||||
#define MINSCORE 0
|
||||
#define MINLEN 7
|
||||
|
||||
char *dictfile;
|
||||
int alive,lost;
|
||||
FILE *dict;
|
||||
long int dictlen;
|
||||
float errors=0, words=0;
|
||||
char word[26],alph[26],realword[26];
|
||||
|
||||
void fatal(s)
|
||||
char *s;
|
||||
{
|
||||
fprintf(stderr,"%s\n",s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
long tvec;
|
||||
struct stat statb;
|
||||
time(&tvec);
|
||||
srand(tvec);
|
||||
if((dict=fopen(dictfile,"r"))==NULL) fatal("no dictionary");
|
||||
if(stat(dictfile,&statb)<0) fatal("can't stat");
|
||||
dictlen=statb.st_size;
|
||||
}
|
||||
|
||||
double frand()
|
||||
{
|
||||
return(rand()/32768.);
|
||||
}
|
||||
|
||||
void pscore()
|
||||
{
|
||||
if(words!=0) printf("(%4.2f/%.0f) ",errors/words,words);
|
||||
}
|
||||
|
||||
void getword()
|
||||
{ char wbuf[128],c;
|
||||
int i,j;
|
||||
loop:
|
||||
if(fscanf(dict,"%s\n",wbuf)==EOF)
|
||||
{ fseek(dict,0L,0);
|
||||
goto loop;
|
||||
}
|
||||
if((c=wbuf[0])>'z' || c<'a') goto loop;
|
||||
for(i=j=0;wbuf[j]!=0;i++,j++)
|
||||
{ if(wbuf[j]=='-') j++;
|
||||
wbuf[i]=wbuf[j];
|
||||
}
|
||||
wbuf[i]=0;
|
||||
if(i<MINLEN) goto loop;
|
||||
for(j=0;j<i;j++)
|
||||
if((c=wbuf[j])<'a' || c>'z') goto loop;
|
||||
pscore();
|
||||
strcpy(realword,wbuf);
|
||||
for(j=0;j<i;word[j++]='.');
|
||||
}
|
||||
|
||||
void startnew()
|
||||
{ int i;
|
||||
long int pos;
|
||||
char buf[128];
|
||||
for(i=0;i<26;i++) word[i]=alph[i]=realword[i]=0;
|
||||
pos=frand()*dictlen;
|
||||
pos%=dictlen;
|
||||
fseek(dict,pos,0);
|
||||
fscanf(dict,"%s\n",buf);
|
||||
getword();
|
||||
alive=MAXERR;
|
||||
lost=0;
|
||||
}
|
||||
|
||||
void stateout()
|
||||
{ int i;
|
||||
printf("guesses: ");
|
||||
for(i=0;i<26;i++)
|
||||
if(alph[i]!=0) putchar(alph[i]);
|
||||
printf(" word: %s ",word);
|
||||
printf("errors: %d/%d\n",MAXERR-alive,MAXERR);
|
||||
}
|
||||
|
||||
void getguess()
|
||||
{ char gbuf[128],c;
|
||||
int ok=0,i;
|
||||
loop:
|
||||
printf("guess: ");
|
||||
if(gets(gbuf)==NULL)
|
||||
{ putchar('\n');
|
||||
exit(0);
|
||||
}
|
||||
if((c=gbuf[0])<'a' || c>'z')
|
||||
{ printf("lower case\n");
|
||||
goto loop;
|
||||
}
|
||||
if(alph[c-'a']!=0)
|
||||
{ printf("you guessed that\n");
|
||||
goto loop;
|
||||
}
|
||||
else alph[c-'a']=c;
|
||||
for(i=0;realword[i]!=0;i++)
|
||||
if(realword[i]==c)
|
||||
{ word[i]=c;
|
||||
ok=1;
|
||||
}
|
||||
if(ok==0)
|
||||
{ alive--;
|
||||
errors=errors+1;
|
||||
if(alive<=0) lost=1;
|
||||
return;
|
||||
}
|
||||
for(i=0;word[i]!=0;i++)
|
||||
if(word[i]=='.') return;
|
||||
alive=0;
|
||||
lost=0;
|
||||
return;
|
||||
}
|
||||
|
||||
void wordout()
|
||||
{
|
||||
errors=errors+2;
|
||||
printf("the answer was %s, you blew it\n",realword);
|
||||
}
|
||||
|
||||
void youwon()
|
||||
{
|
||||
printf("you win, the word is %s\n",realword);
|
||||
}
|
||||
|
||||
main(argc,argv)
|
||||
char **argv;
|
||||
{
|
||||
if(argc==1) dictfile=DICT;
|
||||
else dictfile=argv[1];
|
||||
setup();
|
||||
for(;;)
|
||||
{ startnew();
|
||||
while(alive>0)
|
||||
{ stateout();
|
||||
getguess();
|
||||
}
|
||||
words=words+1;
|
||||
if(lost) wordout();
|
||||
else youwon();
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@
|
|||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
|
|
|
@ -277,27 +277,17 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
* @return true if value was exchanged, otherwise false
|
||||
* @see lockcmpxchg()
|
||||
*/
|
||||
#define cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
asm(ZFLAG_ASM("cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*(IFTHING)), "+a"(*(ISEQUALTOME)) \
|
||||
: "r"((typeof(*(IFTHING)))(REPLACEITWITHME)) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
|
||||
#define ezcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm(ZFLAG_ASM("cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
#define cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -307,14 +297,17 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
* @return true if value was exchanged, otherwise false
|
||||
* @see lockcmpxchg()
|
||||
*/
|
||||
#define lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
asm(ZFLAG_ASM("lock cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*(IFTHING)), "+a"(*(ISEQUALTOME)) \
|
||||
: "r"((typeof(*(IFTHING)))(REPLACEITWITHME)) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
#define lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("lock cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,6 @@ textwindows int chdir$nt(const char *path) {
|
|||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
textwindows int close$nt(int fd) {
|
||||
bool32 ok;
|
||||
if (isfdopen(fd)) {
|
||||
if (__isfdopen(fd)) {
|
||||
if (g_fds.p[fd].kind == kFdFile) {
|
||||
/*
|
||||
* Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
|
@ -37,8 +37,8 @@ textwindows int close$nt(int fd) {
|
|||
if (g_fds.p[fd].kind == kFdConsole) {
|
||||
ok &= CloseHandle(g_fds.p[fd].extra);
|
||||
}
|
||||
removefd(fd);
|
||||
return ok ? 0 : winerr();
|
||||
__removefd(fd);
|
||||
return ok ? 0 : __winerr();
|
||||
} else {
|
||||
return ebadf();
|
||||
}
|
||||
|
|
|
@ -20,9 +20,10 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Closes file descriptor.
|
||||
|
@ -32,17 +33,24 @@
|
|||
*/
|
||||
int close(int fd) {
|
||||
int rc;
|
||||
if (fd == -1) return einval();
|
||||
if (isfdkind(fd, kFdZip)) {
|
||||
rc = weaken(__zipos_close)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle);
|
||||
if (fd < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = weaken(__zipos_close)(fd);
|
||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) {
|
||||
rc = weaken(close$epoll)(fd);
|
||||
} else if (!IsWindows()) {
|
||||
rc = close$sysv(fd);
|
||||
} else if (isfdkind(fd, kFdSocket)) {
|
||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) {
|
||||
rc = weaken(closesocket$nt)(fd);
|
||||
} else {
|
||||
} else if (fd < g_fds.n &&
|
||||
(g_fds.p[fd].kind == kFdFile || g_fds.p[fd].kind == kFdConsole)) {
|
||||
rc = close$nt(fd);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
if (fd < g_fds.n) {
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
g_fds.f = MIN(g_fds.f, fd);
|
||||
}
|
||||
removefd(fd);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -30,17 +30,17 @@
|
|||
* Implements dup(), dup2(), and dup3() for Windows NT.
|
||||
*/
|
||||
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||
if (!isfdkind(oldfd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(oldfd, kFdFile)) return ebadf();
|
||||
if (newfd == -1) {
|
||||
if ((newfd = createfd()) == -1) return -1;
|
||||
} else if (isfdindex(newfd)) {
|
||||
if ((newfd = __getemptyfd()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (__ensurefds(newfd) != -1) {
|
||||
if (g_fds.p[newfd].kind != kFdEmpty) {
|
||||
close(newfd);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if (growfds() == -1) return -1;
|
||||
} while (newfd >= g_fds.n);
|
||||
return -1;
|
||||
}
|
||||
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
|
||||
GetCurrentProcess(), &g_fds.p[newfd].handle, 0,
|
||||
|
@ -49,6 +49,6 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
|||
g_fds.p[newfd].flags = flags;
|
||||
return newfd;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ textwindows int fadvise$nt(int fd, uint64_t offset, uint64_t len, int advice) {
|
|||
struct NtIoStatusBlock iostatus;
|
||||
struct NtFileBasicInformation basicinfo;
|
||||
struct NtFileAccessInformation accessinfo;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
sharemode = /* xxx: no clue how to query this */
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
/* TODO(jart): can we do it in one call w/ NtQueryObject? */
|
||||
|
@ -56,7 +56,7 @@ textwindows int fadvise$nt(int fd, uint64_t offset, uint64_t len, int advice) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
return winerr();
|
||||
return __winerr();
|
||||
} else if (status == kNtStatusDllNotFound) {
|
||||
return enosys();
|
||||
} else {
|
||||
|
|
|
@ -51,7 +51,7 @@ int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
|||
} else if (!IsWindows()) {
|
||||
return posix_fallocate$sysv(fd, offset, length);
|
||||
} else if (IsWindows()) {
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (mode == FALLOC_FL_ZERO_RANGE) {
|
||||
if (DeviceIoControl(
|
||||
g_fds.p[fd].handle, kNtFsctlSetZeroData,
|
||||
|
@ -59,7 +59,7 @@ int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
|||
sizeof(struct NtFileZeroDataInformation), NULL, 0, &br, NULL)) {
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
} else if (!mode && !offset) {
|
||||
/*
|
||||
|
|
|
@ -21,20 +21,31 @@
|
|||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
|
||||
uint32_t flags;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
switch (cmd) {
|
||||
case F_GETFL:
|
||||
return g_fds.p[fd].flags;
|
||||
case F_SETFL:
|
||||
return (g_fds.p[fd].flags = arg);
|
||||
case F_GETFD:
|
||||
if (!GetHandleInformation(g_fds.p[fd].handle, &flags)) return -1;
|
||||
arg = (flags & FD_CLOEXEC) ^ FD_CLOEXEC;
|
||||
return arg;
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
case F_SETFD:
|
||||
arg ^= FD_CLOEXEC;
|
||||
if (!SetHandleInformation(g_fds.p[fd].handle, FD_CLOEXEC, arg)) return -1;
|
||||
return 0;
|
||||
if (arg & O_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0; /* TODO(jart): Implement me. */
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int fdatasync$nt(int fd) {
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
/*
|
||||
* XXX: On Windows NT this might be more analagous to fflush() and
|
||||
* Microsoft docs say to do manual block i/o for database-ish
|
||||
* guarantees on disk persistence. Consider: Really good UPS.
|
||||
*/
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : winerr();
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : __winerr();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
|
||||
enum FdKind fdkind(int fd) {
|
||||
if (isfdindex(fd)) {
|
||||
if (0 <= fd && fd <= g_fds.n) {
|
||||
return g_fds.p[fd].kind;
|
||||
} else {
|
||||
return kFdEmpty;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
textwindows int flock$nt(int fd, int op) {
|
||||
struct NtOverlapped ov;
|
||||
struct NtByHandleFileInformation info;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
|
||||
((!(op & LOCK_UN) &&
|
||||
|
@ -39,6 +39,6 @@ textwindows int flock$nt(int fd, int op) {
|
|||
info.nFileSizeHigh, &ov)))) {
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,6 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) {
|
|||
st->st_blocks = roundup(actualsize, PAGESIZE) / 512;
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,20 +22,20 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Returns information about file, via open()'d descriptor.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fstat(int fd, struct stat *st) {
|
||||
if (isfdkind(fd, kFdZip)) {
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
return weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, st);
|
||||
} else if (!IsWindows()) {
|
||||
return fstat$sysv(fd, st);
|
||||
} else {
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
return fstat$nt(g_fds.p[fd].handle, st);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
textwindows int ftruncate$nt(int fd, uint64_t length) {
|
||||
bool32 ok;
|
||||
int64_t tell;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
tell = -1;
|
||||
if (SetFilePointerEx(g_fds.p[fd].handle, 0, &tell, kNtFileCurrent)) {
|
||||
ok = SetFilePointerEx(g_fds.p[fd].handle, length, NULL, kNtFileBegin) &&
|
||||
SetEndOfFile(g_fds.p[fd].handle);
|
||||
SetFilePointerEx(g_fds.p[fd].handle, tell, NULL, kNtFileBegin);
|
||||
return ok ? 0 : winerr();
|
||||
return ok ? 0 : __winerr();
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,12 +33,22 @@ void InitializeFileDescriptors(void) {
|
|||
pushmov(&fds->f, 3ul);
|
||||
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
||||
fds->p = fds->__init_p;
|
||||
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDERR_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDIN_FILENO].handle = GetStdHandle(pushpop(kNtStdInputHandle));
|
||||
fds->__init_p[STDOUT_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdOutputHandle));
|
||||
fds->__init_p[STDERR_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdErrorHandle));
|
||||
if (!IsMetal()) {
|
||||
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDERR_FILENO].kind = pushpop(kFdFile);
|
||||
fds->__init_p[STDIN_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdInputHandle));
|
||||
fds->__init_p[STDOUT_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdOutputHandle));
|
||||
fds->__init_p[STDERR_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdErrorHandle));
|
||||
} else {
|
||||
fds->__init_p[STDIN_FILENO].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[STDOUT_FILENO].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[STDERR_FILENO].kind = pushpop(kFdSerial);
|
||||
fds->__init_p[STDIN_FILENO].handle = 0x3F8;
|
||||
fds->__init_p[STDOUT_FILENO].handle = 0x3F8;
|
||||
fds->__init_p[STDERR_FILENO].handle = 0x3F8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ textwindows char *getcwd$nt(char *buf, size_t size) {
|
|||
erange();
|
||||
}
|
||||
} else {
|
||||
winerr();
|
||||
__winerr();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ int getdomainname(char *name, size_t len) {
|
|||
} else {
|
||||
nSize = ARRAYLEN(name16);
|
||||
if (!GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16);
|
||||
return 0;
|
||||
|
|
|
@ -25,14 +25,11 @@
|
|||
/**
|
||||
* Finds open file descriptor slot.
|
||||
*/
|
||||
ssize_t createfd(void) {
|
||||
size_t fd;
|
||||
for (;;) {
|
||||
while (g_fds.f < g_fds.n) {
|
||||
if (g_fds.p[(fd = g_fds.f++)].kind == kFdEmpty) {
|
||||
return fd;
|
||||
}
|
||||
ssize_t __getemptyfd(void) {
|
||||
for (; g_fds.f < g_fds.n; ++g_fds.f) {
|
||||
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
|
||||
return g_fds.f;
|
||||
}
|
||||
if (growfds() == -1) return -1;
|
||||
}
|
||||
return __ensurefds(g_fds.f);
|
||||
}
|
|
@ -50,7 +50,7 @@ int gethostname(char *name, size_t len) {
|
|||
} else {
|
||||
nSize = ARRAYLEN(name16);
|
||||
if (!GetComputerNameEx(kNtComputerNameDnsHostname, name16, &nSize)) {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16);
|
||||
return 0;
|
||||
|
|
|
@ -46,6 +46,6 @@ textwindows int getpriority$nt(int ignored) {
|
|||
}
|
||||
abort();
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,6 @@ textwindows int getrusage$nt(int who, struct rusage *usage) {
|
|||
FileTimeToTimeVal(&usage->ru_stime, KernelFileTime);
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,18 +23,20 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int growfds(void) {
|
||||
int __ensurefds(int fd) {
|
||||
size_t i, n;
|
||||
struct Fd *p;
|
||||
if (fd < g_fds.n) return fd;
|
||||
if (weaken(realloc)) {
|
||||
if ((p = weaken(realloc)(g_fds.p != g_fds.__init_p ? g_fds.p : NULL,
|
||||
(n = (i = g_fds.n) << 1) * sizeof(*p)))) {
|
||||
if ((p = weaken(realloc)(
|
||||
g_fds.p != g_fds.__init_p ? g_fds.p : NULL,
|
||||
(n = MAX(fd + 1, (i = g_fds.n) << 1)) * sizeof(*p)))) {
|
||||
do {
|
||||
p[i++].kind = kFdEmpty;
|
||||
} while (i < n);
|
||||
g_fds.p = p;
|
||||
g_fds.n = n;
|
||||
return 0;
|
||||
return fd;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ static textwindows int copyfile$nt(const char *src, const char *dst,
|
|||
}
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ static textwindows noinline DIR *opendir$nt(const char *name) {
|
|||
if ((res->fd = FindFirstFile(name16, &res->windata)) != -1) {
|
||||
return res;
|
||||
} else {
|
||||
winerr();
|
||||
__winerr();
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ int closedir(DIR *dir) {
|
|||
if (!IsWindows()) {
|
||||
rc = close(dir->fd);
|
||||
} else {
|
||||
rc = FindClose(dir->fd) ? 0 : winerr();
|
||||
rc = FindClose(dir->fd) ? 0 : __winerr();
|
||||
}
|
||||
free(dir);
|
||||
} else {
|
||||
|
|
|
@ -67,7 +67,7 @@ textwindows void WinMainForked(void) {
|
|||
char16_t *p;
|
||||
uint64_t size;
|
||||
char16_t var[21 + 1 + 21 + 1];
|
||||
uint32_t i, varlen, protect, access;
|
||||
uint32_t i, varlen, protect, access, oldprot;
|
||||
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
|
||||
if (!varlen || varlen >= ARRAYLEN(var)) return;
|
||||
p = var;
|
||||
|
@ -98,11 +98,13 @@ textwindows void WinMainForked(void) {
|
|||
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);
|
||||
MapViewOfFileExNuma((_mmi.p[i].h = CreateFileMappingNuma(
|
||||
-1, NULL, kNtPageExecuteReadwrite, 0, size, NULL,
|
||||
kNtNumaNoPreferredNode)),
|
||||
kNtFileMapRead | kNtFileMapWrite | kNtFileMapExecute,
|
||||
0, 0, size, addr, kNtNumaNoPreferredNode);
|
||||
ReadAll(h, addr, size);
|
||||
VirtualProtect(addr, size, protect, &oldprot);
|
||||
} else {
|
||||
MapViewOfFileExNuma(_mmi.p[i].h, access, 0, 0, size, addr,
|
||||
kNtNumaNoPreferredNode);
|
||||
|
@ -148,7 +150,7 @@ textwindows int fork$nt(void) {
|
|||
}
|
||||
unsetenv("_FORK");
|
||||
} else {
|
||||
rc = winerr();
|
||||
rc = __winerr();
|
||||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
|
|
|
@ -78,7 +78,7 @@ textwindows int ntspawn(
|
|||
opt_out_lpProcessInformation)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = winerr();
|
||||
rc = __winerr();
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
|
|
|
@ -49,14 +49,14 @@ textwindows int spawnve$nt(unsigned flags, int stdiofds[3], const char *program,
|
|||
sti.cb = sizeof(sti);
|
||||
sti.dwFlags = kNtStartfUsestdhandles;
|
||||
|
||||
if ((pid = createfd()) == -1) return -1;
|
||||
if ((pid = __getemptyfd()) == -1) return -1;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
if (stdiofds[i] == -1) {
|
||||
x = &h;
|
||||
y = &sti.stdiofds[i];
|
||||
if (kIoMotion[i]) xchg(&x, &y);
|
||||
if ((tubes[i] = createfd()) != -1 &&
|
||||
if ((tubes[i] = __getemptyfd()) != -1 &&
|
||||
CreatePipe(x, y, &kNtIsInheritable, 0)) {
|
||||
g_fds.p[tubes[i]].handle = h;
|
||||
} else {
|
||||
|
|
|
@ -76,7 +76,7 @@ int ttyname_r(int fd, char *buf, size_t size) {
|
|||
} else if (IsFreebsd()) {
|
||||
return ttyname$freebsd(fd, buf, size);
|
||||
} else if (IsWindows()) {
|
||||
if (isfdkind(fd, kFdFile)) {
|
||||
if (__isfdkind(fd, kFdFile)) {
|
||||
return ttyname$nt(fd, buf, size);
|
||||
} else {
|
||||
return ebadf();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/itimerval.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
|
@ -37,7 +38,7 @@ struct IoctlPtmGet {
|
|||
|
||||
struct Fds {
|
||||
size_t f; // arbitrary free slot start search index
|
||||
size_t n; // capacity
|
||||
size_t n; // monotonic capacity
|
||||
struct Fd {
|
||||
int64_t handle;
|
||||
int64_t extra;
|
||||
|
@ -47,7 +48,9 @@ struct Fds {
|
|||
kFdSocket,
|
||||
kFdProcess,
|
||||
kFdConsole,
|
||||
kFdSerial,
|
||||
kFdZip,
|
||||
kFdEpoll,
|
||||
} kind;
|
||||
unsigned flags;
|
||||
} * p;
|
||||
|
@ -62,20 +65,12 @@ 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;
|
||||
void removefd(int) hidden;
|
||||
ssize_t __getemptyfd(void) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
void __removefd(int) hidden;
|
||||
enum FdKind fdkind(int) hidden nosideeffect;
|
||||
bool isfdopen(int) hidden nosideeffect;
|
||||
bool isfdkind(int, enum FdKind) hidden nosideeffect;
|
||||
|
||||
forceinline bool isfdindex(int fd) {
|
||||
if (!IsTrustworthy()) {
|
||||
return (0 <= fd && fd < g_fds.n);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool __isfdopen(int) hidden nosideeffect;
|
||||
bool __isfdkind(int, enum FdKind) hidden nosideeffect;
|
||||
|
||||
forceinline size_t clampio(size_t size) {
|
||||
if (!IsTrustworthy()) {
|
||||
|
@ -267,7 +262,7 @@ bool32 onntconsoleevent$nt(u32) hidden;
|
|||
void __winalarm(void *, uint32_t, uint32_t) hidden;
|
||||
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
||||
i64 ntreturn(u32);
|
||||
i64 winerr(void) nocallback privileged;
|
||||
i64 __winerr(void) nocallback privileged;
|
||||
|
||||
#define mkntpath(PATH, PATH16) mkntpath2(PATH, -1u, PATH16)
|
||||
#define mkntpath2(PATH, FLAGS, PATH16) \
|
||||
|
@ -280,6 +275,13 @@ i64 winerr(void) nocallback privileged;
|
|||
Count; \
|
||||
})
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » drivers ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
ssize_t readv$serial(struct Fd *, const struct iovec *, int) hidden;
|
||||
ssize_t writev$serial(struct Fd *, const struct iovec *, int) hidden;
|
||||
|
||||
#undef sigset
|
||||
#undef i32
|
||||
#undef i64
|
||||
|
|
|
@ -29,13 +29,13 @@ int ioctl$default(int fd, uint64_t request, void *memory) {
|
|||
int64_t handle;
|
||||
if (!IsWindows()) {
|
||||
return ioctl$sysv(fd, request, memory);
|
||||
} else if (isfdopen(fd)) {
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (g_fds.p[fd].kind == kFdSocket) {
|
||||
handle = g_fds.p[fd].handle;
|
||||
if ((rc = weaken(__ioctlsocket$nt)(handle, request, memory)) != -1) {
|
||||
return rc;
|
||||
} else {
|
||||
return weaken(winsockerr)() |