Make stderr go faster

This change makes _IONBF (unbuffered) stdio handles go 20x faster for
certain kinds of formatting directives by being smarter about buffers
This commit is contained in:
Justine Tunney 2023-08-11 11:56:35 -07:00
parent 2cbd09b4d4
commit 8fc778162e
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
6 changed files with 70 additions and 38 deletions

View file

@ -18,28 +18,35 @@
*/
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/stdckdint.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
struct buf {
int n;
char p[512];
};
struct state {
FILE *f;
int n;
struct buf b;
};
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
static int __vfprintf_flbuf(const char *s, struct state *t, size_t n) {
int rc;
if (n) {
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
t->f->bufmode != _IONBF) {
if (n == 1 && *s != '\n' && t->f->beg < t->f->size) {
t->f->buf[t->f->beg++] = *s;
t->n += n;
rc = 0;
} else if (!fwrite_unlocked(s, 1, n, t->f)) {
rc = -1;
} else {
t->n += n;
} else if (fwrite_unlocked(s, 1, n, t->f)) {
rc = 0;
} else {
rc = -1;
}
if (ckd_add(&t->n, t->n, n)) {
rc = eoverflow();
}
} else {
rc = 0;
@ -47,15 +54,49 @@ static int vfprintfputchar(const char *s, struct state *t, size_t n) {
return rc;
}
static int __vfprintf_nbuf(const char *s, struct state *t, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
t->b.p[t->b.n++] = s[i];
if (t->b.n == sizeof(t->b.p)) {
if (!fwrite_unlocked(s, 1, t->b.n, t->f)) {
return -1;
}
t->b.n = 0;
}
if (ckd_add(&t->n, t->n, 1)) {
return eoverflow();
}
}
return 0;
}
/**
* Formats and writes text to stream.
* @see printf() for further documentation
*/
int vfprintf_unlocked(FILE *f, const char *fmt, va_list va) {
int rc;
struct state st[1] = {{f, 0}};
if ((rc = __fmt(vfprintfputchar, st, fmt, va)) != -1) {
rc = st->n;
struct state st;
int (*out)(const char *, struct state *, size_t);
if (f->bufmode != _IONBF) {
out = __vfprintf_flbuf;
} else {
out = __vfprintf_nbuf;
}
st.f = f;
st.n = 0;
st.b.n = 0;
if ((rc = __fmt(out, &st, fmt, va)) != -1) {
if (!st.b.n) {
rc = st.n;
} else if (fwrite_unlocked(st.b.p, 1, st.b.n, st.f)) {
if (ckd_add(&rc, st.n, st.b.n)) {
rc = eoverflow();
}
} else {
rc = -1;
}
}
return rc;
}