mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 23:08:31 +00:00
Rearrange code and make a faster sha256sum program
This commit is contained in:
parent
5e60e5ad10
commit
89d1e5b8f2
32 changed files with 933 additions and 517 deletions
|
@ -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__))
|
||||
|
|
|
@ -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
62
libc/stdio/alloc.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue