Rearrange code and make a faster sha256sum program

This commit is contained in:
Justine Tunney 2022-11-02 23:12:32 -07:00
parent 5e60e5ad10
commit 89d1e5b8f2
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
32 changed files with 933 additions and 517 deletions

View file

@ -52,8 +52,11 @@
#endif
#endif
#if defined(__STRICT_ANSI__) || \
(!defined(__GNUC__) && !__has_builtin(unreachable))
#ifdef _MSC_VER
#define __builtin_unreachable() __assume(0)
#elif defined(__STRICT_ANSI__) || \
!((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 || \
defined(__clang__) || defined(__INTEL_COMPILER))
#define __builtin_unreachable() \
for (;;) { \
}
@ -234,7 +237,9 @@ typedef struct {
#endif
#ifndef dontinline
#if !defined(__STRICT_ANSI__) && \
#ifdef _MSC_VER
#define dontinline __declspec(noinline)
#elif !defined(__STRICT_ANSI__) && \
(__has_attribute(__noinline__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301)
#define dontinline __attribute__((__noinline__))

View file

@ -83,9 +83,9 @@ static void Log(const char *s, ...) {
va_start(va, s);
errbuf[0] = 0;
do {
strlcat(errbuf, s, sizeof(argbuf));
strlcat(errbuf, s, sizeof(errbuf));
} while ((s = va_arg(va, const char *)));
strlcat(errbuf, "\n", sizeof(argbuf));
strlcat(errbuf, "\n", sizeof(errbuf));
Write(2, errbuf);
va_end(va);
}
@ -95,7 +95,7 @@ static wontreturn void Wexit(int rc, const char *s, ...) {
va_start(va, s);
errbuf[0] = 0;
do {
strlcat(errbuf, s, sizeof(argbuf));
strlcat(errbuf, s, sizeof(errbuf));
} while ((s = va_arg(va, const char *)));
Write(2, errbuf);
va_end(va);

62
libc/stdio/alloc.c Normal file
View file

@ -0,0 +1,62 @@
/*-*- 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/assert.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/kmalloc.h"
#include "libc/stdio/internal.h"
#include "libc/str/str.h"
#include "libc/thread/thread.h"
static _Atomic(FILE *) __stdio_freelist;
FILE *__stdio_alloc(void) {
FILE *f;
f = atomic_load_explicit(&__stdio_freelist, memory_order_relaxed);
while (f) {
if (atomic_compare_exchange_weak_explicit(
&__stdio_freelist, &f,
atomic_load_explicit(&f->next, memory_order_relaxed),
memory_order_relaxed, memory_order_relaxed)) {
atomic_store_explicit(&f->next, 0, memory_order_relaxed);
break;
}
}
if (!f) {
f = kmalloc(sizeof(FILE));
}
if (f) {
((pthread_mutex_t *)f->lock)->_type = PTHREAD_MUTEX_RECURSIVE;
}
return f;
}
void __stdio_free(FILE *f) {
FILE *g;
_unassert(!atomic_load_explicit(&f->next, memory_order_relaxed));
bzero(f, sizeof(*f));
g = atomic_load_explicit(&__stdio_freelist, memory_order_relaxed);
for (;;) {
atomic_store_explicit(&f->next, g, memory_order_relaxed);
if (atomic_compare_exchange_weak_explicit(&__stdio_freelist, &g, f,
memory_order_relaxed,
memory_order_relaxed)) {
break;
}
}
}

View file

@ -19,6 +19,7 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"
@ -27,21 +28,21 @@
/**
* Closes standard i/o stream and its underlying thing.
*
* @param f is the file object, which is always free if it's heap,
* otherwise its resources are released and fields updated
* @param f is the file object
* @return 0 on success or -1 on error, which can be a trick for
* differentiating between EOF and real errors during previous
* i/o calls, without needing to call ferror()
* @see fclose_s()
*/
int fclose(FILE *f) {
int rc;
if (!f) return 0;
__fflush_unregister(f);
fflush(f);
free_s(&f->getln);
if (!f->nofree) {
free_s(&f->buf);
if (_weaken(free)) {
_weaken(free)(f->getln);
if (!f->nofree && f->buf != f->mem) {
_weaken(free)(f->buf);
}
}
f->state = EOF;
if (f->noclose) {
@ -55,6 +56,6 @@ int fclose(FILE *f) {
errno = f->state;
rc = EOF;
}
free_s(&f);
__stdio_free(f);
return rc;
}

View file

@ -19,14 +19,8 @@
#include "libc/intrin/lockxchg.h"
#include "libc/stdio/stdio.h"
/**
* Closes standard i/o stream and its underlying thing.
*
* @param f is the heap file object pointer, to close+free+clear
* @return 0 on success or -1 on error, which can be a trick for
* differentiating between EOF and real errors during previous
* i/o calls, without needing to call ferror()
*/
// TODO(jart): delete
int fclose_s(FILE **fp) {
FILE *f = NULL;
return fclose(lockxchg(fp, &f));

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
@ -34,19 +33,16 @@
*/
FILE *fdopen(int fd, const char *mode) {
FILE *f;
if ((f = calloc(1, sizeof(FILE)))) {
if ((f = __stdio_alloc())) {
f->fd = fd;
f->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
f->iomode = fopenflags(mode);
((pthread_mutex_t *)f->lock)->_type = PTHREAD_MUTEX_RECURSIVE;
f->buf = f->mem;
f->size = BUFSIZ;
if ((f->buf = malloc(f->size))) {
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
__fflush_register(f);
}
return f;
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
__fflush_register(f);
}
free(f);
return f;
}
return NULL;
}

View file

@ -16,16 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
* Returns nonzero if stream is in error state.
*
* @param f is file stream pointer
* @return non-zero if and only if it's an error state
* @return non-zero w/ errno only if `f` is in error state
* @note EOF doesn't count
* @see ferror(), feof()
*/
errno_t ferror_unlocked(FILE *f) {
return f->state > 0 ? f->state : 0;
return f->state > 0 ? (errno = f->state) : 0;
}

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/thread/thread.h"
#include "libc/stdio/fflush.internal.h"
#include "libc/stdio/lock.internal.h"
#include "libc/stdio/stdio.h"

View file

@ -16,36 +16,48 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
// TODO(jart): POSIX says buffer needs to grow in write modes?
/**
* Opens buffer as stream.
*
* @param buf becomes owned by this function, and is allocated if NULL
* @return new stream or NULL w/ errno
* @raise ENOMEM if `buf` is NULL and we failed to allocate it
* @raise ENOMEM if `buf` is NULL and malloc() wasn't linked
* @raise EINVAL if `buf` is NULL when `+` isn't in `mode`
*/
FILE *fmemopen(void *buf, size_t size, const char *mode) {
FILE *f;
char *p;
int iomode;
unsigned flags;
if (size && size > 0x7ffff000) {
iomode = fopenflags(mode);
if ((size && size > 0x7ffff000) || //
(!buf && (iomode & O_ACCMODE) != O_RDWR)) {
einval();
return NULL;
}
if (!(f = calloc(1, sizeof(FILE)))) {
if (!(f = __stdio_alloc())) {
return NULL;
}
if (buf) {
f->nofree = true;
} else {
if (!size) size = BUFSIZ;
if (!(buf = calloc(1, size))) {
free(f);
// TODO(jart): Why do we need calloc()?
if (!_weaken(calloc) || !(buf = _weaken(calloc)(1, size))) {
__stdio_free(f);
enomem();
return NULL;
}
}
@ -53,9 +65,8 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
f->buf = buf;
f->end = size;
f->size = size;
f->iomode = fopenflags(mode);
((pthread_mutex_t *)f->lock)->_type = PTHREAD_MUTEX_RECURSIVE;
if (f->iomode & O_APPEND) {
f->iomode = iomode;
if (iomode & O_APPEND) {
if ((p = memchr(buf, '\0', size))) {
f->beg = p - (char *)buf;
} else {

View file

@ -7,16 +7,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern char g_stdinbuf[BUFSIZ];
extern char g_stdoutbuf[BUFSIZ];
extern char g_stderrbuf[BUFSIZ];
hidden extern uint64_t g_rando;
int __fflush_impl(FILE *) hidden;
int __fflush_register(FILE *) hidden;
void __fflush_unregister(FILE *) hidden;
bool __stdio_isok(FILE *) hidden;
FILE *__stdio_alloc(void) hidden;
void __stdio_free(FILE *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,6 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/lock.internal.h"
#include "libc/stdio/stdio.h"
@ -35,7 +37,12 @@ int setvbuf(FILE *f, char *buf, int mode, size_t size) {
flockfile(f);
if (buf) {
if (!size) size = BUFSIZ;
if (!f->nofree && f->buf != buf) free_s(&f->buf);
if (!f->nofree && //
f->buf != buf && //
f->buf != f->mem && //
_weaken(free)) {
_weaken(free)(f->buf);
}
f->buf = buf;
f->size = size;
f->nofree = true;

View file

@ -31,7 +31,7 @@
pop 12(%rax)
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
ezlea __stderr_buf,cx
lea 0x50(%rax),%rcx # f.mem
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
movb $PTHREAD_MUTEX_RECURSIVE,0x38+4(%rax) # f.lock._type

View file

@ -27,7 +27,6 @@ STATIC_YOINK("_init_stderr");
FILE *stderr;
hidden FILE __stderr;
hidden unsigned char __stderr_buf[BUFSIZ];
static textstartup void __stderr_init() {
__fflush_register(stderr);

View file

@ -27,7 +27,7 @@
ezlea __stdin,ax
mov O_RDONLY,%edx
mov %edx,4(%rax) # f.iomode
ezlea __stdin_buf,cx
lea 0x50(%rax),%rcx # f.mem
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
movb $PTHREAD_MUTEX_RECURSIVE,0x38+4(%rax) # f.lock._type

View file

@ -27,7 +27,6 @@ STATIC_YOINK("_init_stdin");
FILE *stdin;
hidden FILE __stdin;
hidden unsigned char __stdin_buf[BUFSIZ];
static textstartup void __stdin_init() {
__fflush_register(stdin);

View file

@ -15,19 +15,21 @@ COSMOPOLITAN_C_START_
*/
typedef struct FILE {
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln; /* 0x30 */
char lock[16]; /* 0x38 */
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln; /* 0x30 */
char lock[16]; /* 0x38 */
_Atomic(struct FILE *) next; /* 0x48 */
char mem[BUFSIZ]; /* 0x50 */
} FILE;
extern FILE *stdin;

View file

@ -29,7 +29,7 @@
pop 0x0c(%rax) # f.fd
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
ezlea __stdout_buf,cx
lea 0x50(%rax),%rcx # f.mem
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
movb $PTHREAD_MUTEX_RECURSIVE,0x38+4(%rax) # f.lock._type

View file

@ -16,9 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pushpop.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/pushpop.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
@ -30,7 +30,6 @@ STATIC_YOINK("_init_stdout");
FILE *stdout;
hidden FILE __stdout;
hidden unsigned char __stdout_buf[BUFSIZ];
static textstartup void __stdout_init() {
struct FILE *sf;

View file

@ -38,7 +38,6 @@
#include "libc/runtime/clone.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/fflush.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h"