Add test for sendfile() and reduce branches

This commit is contained in:
Justine Tunney 2022-05-25 22:29:10 -07:00
parent 8f12cd980d
commit 10b97ca630
6 changed files with 165 additions and 43 deletions

View file

@ -11,7 +11,7 @@
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
#define STRACE_PROLOGUE "%rSYS %6P %'18T "
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -61,8 +61,6 @@ privileged void *__initialize_tls(char tib[64]) {
*/
privileged void __install_tls(char tib[64]) {
int ax, dx;
uint64_t magic;
unsigned char *p;
assert(tib);
assert(!__tls_enabled);
assert(*(int *)(tib + 0x38) != -1);

View file

@ -19,35 +19,78 @@
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/sendfile.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
// sendfile() isn't specified as raising eintr
static textwindows int SendfileBlock(int64_t handle,
struct NtOverlapped *overlapped) {
uint32_t i, got, flags = 0;
if (WSAGetLastError() != kNtErrorIoPending) {
NTTRACE("TransmitFile failed %lm");
return __winsockerr();
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
if (i == kNtWaitFailed) {
NTTRACE("WSAWaitForMultipleEvents failed %lm");
return __winsockerr();
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
_check_interrupts(true, g_fds.p);
#if _NTTRACE
POLLTRACE("WSAWaitForMultipleEvents...");
#endif
} else {
break;
}
}
if (!WSAGetOverlappedResult(handle, overlapped, &got, false, &flags)) {
NTTRACE("WSAGetOverlappedResult failed %lm");
return __winsockerr();
}
return got;
}
static textwindows ssize_t sendfile_linux2nt(int outfd, int infd,
int64_t *inout_opt_inoffset,
size_t uptobytes) {
struct NtOverlapped Overlapped;
struct NtOverlapped *lpOverlapped;
if (!__isfdkind(outfd, kFdSocket) || !__isfdkind(outfd, kFdFile))
return ebadf();
ssize_t rc;
int64_t offset;
struct NtOverlapped overlapped;
if (!__isfdkind(outfd, kFdSocket)) return ebadf();
if (!__isfdkind(infd, kFdFile)) return ebadf();
if (inout_opt_inoffset) {
bzero(&Overlapped, sizeof(Overlapped));
Overlapped.Pointer = (void *)(intptr_t)(*inout_opt_inoffset);
lpOverlapped = &Overlapped;
} else {
lpOverlapped = NULL;
offset = *inout_opt_inoffset;
} else if (!SetFilePointerEx(g_fds.p[infd].handle, 0, &offset, SEEK_CUR)) {
return __winerr();
}
/* TODO(jart): Fetch this on a per-socket basis via GUID. */
bzero(&overlapped, sizeof(overlapped));
overlapped.Pointer = (void *)(intptr_t)offset;
overlapped.hEvent = WSACreateEvent();
if (TransmitFile(g_fds.p[outfd].handle, g_fds.p[infd].handle, uptobytes, 0,
lpOverlapped, NULL, 0)) {
return uptobytes;
&overlapped, 0, 0)) {
rc = uptobytes;
} else {
return __winsockerr();
rc = SendfileBlock(g_fds.p[outfd].handle, &overlapped);
}
if (rc != -1 && inout_opt_inoffset) {
*inout_opt_inoffset = offset + rc;
}
WSACloseEvent(overlapped.hEvent);
return rc;
}
static ssize_t sendfile_linux2bsd(int outfd, int infd,
@ -90,7 +133,6 @@ ssize_t sendfile(int outfd, int infd, int64_t *inout_opt_inoffset,
size_t uptobytes) {
if (!uptobytes) return einval();
if (uptobytes > 0x7ffffffe /* Microsoft's off-by-one */) return eoverflow();
if (IsModeDbg() && uptobytes > 1) uptobytes >>= 1;
if (IsLinux()) {
return sys_sendfile(outfd, infd, inout_opt_inoffset, uptobytes);
} else if (IsFreebsd() || IsXnu()) {

View file

@ -0,0 +1,71 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/hyperion.h"
#include "libc/testlib/testlib.h"
char testlib_enable_tmp_setup_teardown;
TEST(sendfile, test) {
int ws;
char *buf;
int64_t inoffset;
uint32_t addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(0x7f000001),
};
ASSERT_SYS(0, 3, creat("hyperion.txt", 0644));
ASSERT_SYS(0, 512, write(3, kHyperion, 512));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(0, 0, bind(3, &addr, sizeof(addr)));
ASSERT_SYS(0, 0, getsockname(3, &addr, &addrsize));
ASSERT_SYS(0, 0, listen(3, 1));
if (!fork()) {
inoffset = 0;
ASSERT_SYS(0, 4, accept(3, &addr, &addrsize));
ASSERT_SYS(0, 5, open("hyperion.txt", O_RDONLY));
ASSERT_SYS(0, 512, sendfile(4, 5, &inoffset, 512));
EXPECT_EQ(512, inoffset);
ASSERT_SYS(0, 0, close(5));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
_Exit(0);
}
buf = gc(malloc(512));
EXPECT_SYS(0, 0, close(3));
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
EXPECT_SYS(0, 0, connect(3, &addr, sizeof(addr)));
EXPECT_SYS(0, 512, read(3, buf, 512));
EXPECT_EQ(0, memcmp(buf, kHyperion, 512));
EXPECT_SYS(0, 0, close(3));
EXPECT_NE(-1, wait(&ws));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/log/check.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/gc.internal.h"
@ -26,6 +27,7 @@
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/math.h"
#include "third_party/mbedtls/profile.h"
#include "third_party/mbedtls/select.h"
/* clang-format off */
static bool
@ -53,17 +55,23 @@ static int
mbedtls_p256_cmp( const uint64_t a[5],
const uint64_t b[5] )
{
if ( (int64_t)a[4] < (int64_t)b[4] ) return -1;
if ( (int64_t)a[4] > (int64_t)b[4] ) return +1;
if ( a[3] < b[3] ) return -1;
if ( a[3] > b[3] ) return +1;
if ( a[2] < b[2] ) return -1;
if ( a[2] > b[2] ) return +1;
if ( a[1] < b[1] ) return -1;
if ( a[1] > b[1] ) return +1;
if ( a[0] < b[0] ) return -1;
if ( a[0] > b[0] ) return +1;
return 0;
int i, x, y, done = 0;
// return -1 if a[4] < b[4]
x = -((int64_t)a[4] < (int64_t)b[4]);
done = x;
// return +1 if a[4] > b[4]
y = (int64_t)a[4] > (int64_t)b[4];
x = Select(x, y, done);
done |= -y;
for (i = 4; i--;) {
y = -(a[i] < b[i]);
x = Select(x, y, done);
done |= y;
y = a[i] > b[i];
x = Select(x, y, done);
done |= -y;
}
return x;
}
static void

View file

@ -28,6 +28,7 @@
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/math.h"
#include "third_party/mbedtls/profile.h"
#include "third_party/mbedtls/select.h"
/* clang-format off */
static bool
@ -59,21 +60,23 @@ static int
mbedtls_p384_cmp( const uint64_t a[7],
const uint64_t b[7] )
{
if( (int64_t)a[6] < (int64_t)b[6] ) return( -1 );
if( (int64_t)a[6] > (int64_t)b[6] ) return( +1 );
if( a[5] < b[5] ) return( -1 );
if( a[5] > b[5] ) return( +1 );
if( a[4] < b[4] ) return( -1 );
if( a[4] > b[4] ) return( +1 );
if( a[3] < b[3] ) return( -1 );
if( a[3] > b[3] ) return( +1 );
if( a[2] < b[2] ) return( -1 );
if( a[2] > b[2] ) return( +1 );
if( a[1] < b[1] ) return( -1 );
if( a[1] > b[1] ) return( +1 );
if( a[0] < b[0] ) return( -1 );
if( a[0] > b[0] ) return( +1 );
return( 0 );
int i, x, y, done = 0;
// return -1 if a[6] < b[6]
x = -((int64_t)a[6] < (int64_t)b[6]);
done = x;
// return +1 if a[6] > b[6]
y = (int64_t)a[6] > (int64_t)b[6];
x = Select(x, y, done);
done |= -y;
for (i = 6; i--;) {
y = -(a[i] < b[i]);
x = Select(x, y, done);
done |= y;
y = a[i] > b[i];
x = Select(x, y, done);
done |= -y;
}
return x;
}
static inline void