Use re-entrant locks on stdio

This commit is contained in:
Justine Tunney 2022-05-22 08:13:13 -07:00
parent 4e9662cbc7
commit 1f229e4efc
78 changed files with 427 additions and 179 deletions

View file

@ -28,15 +28,18 @@
_Alignas(64) static int rlock;
static privileged inline bool AcquireInterruptPollLock(void) {
// return 0 on success, or tid of other owner
static privileged inline int AcquireInterruptPollLock(void) {
// any thread can poll for interrupts
// but it's wasteful to have every single thread doing it
int me, owner, tries;
if (!__threaded) return true;
int me, owner = 0;
if (__threaded) {
me = gettid();
if (!_lockcmpxchgp(&rlock, &owner, me) && owner == me) {
owner = 0;
if (_lockcmpxchgp(&rlock, &owner, me)) return true;
return owner == me;
}
}
return owner;
}
static textwindows inline void ReleaseInterruptPollLock(void) {
@ -47,7 +50,7 @@ static textwindows inline void ReleaseInterruptPollLock(void) {
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
bool res;
if (__time_critical) return false;
if (!AcquireInterruptPollLock()) return false;
if (AcquireInterruptPollLock()) return false;
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);

View file

@ -27,6 +27,12 @@ __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
/**
* Returns current thread id.
*
* On Linux, and Linux only, this is guaranteed to be equal to getpid()
* if this is the main thread. On NetBSD, gettid() for the main thread
* is always 1.
*
* @return thread id greater than zero or -1 w/ errno
* @asyncsignalsafe
*/
privileged int gettid(void) {

View file

@ -64,7 +64,7 @@
do { \
autotype(lock) __lock = (lock); \
typeof(*__lock) __x; \
int __tries = 0; \
unsigned __tries = 0; \
for (;;) { \
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
if (!__x && !_trylock_inline(__lock)) { \

View file

@ -7,6 +7,7 @@
#include "libc/calls/struct/winsize.h"
#include "libc/errno.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/*───────────────────────────────────────────────────────────────────────────│─╗
@ -89,7 +90,8 @@ extern unsigned __log_level; /* log level for runtime check */
--__ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
if (weaken(__die)) weaken(__die)(); \
exit(1); \
__restorewintty(); \
_Exit(1); \
unreachable; \
} while (0)

View file

@ -41,24 +41,25 @@
#define kNontrivialSize (8 * 1000 * 1000)
static struct timespec vflogf_ts;
_Alignas(64) static int vflogf_lock;
/**
* Takes corrective action if logging is on the fritz.
*/
void vflogf_onfail(FILE *f) {
static void vflogf_onfail(FILE *f) {
errno_t err;
int64_t size;
if (IsTiny()) return;
err = ferror(f);
if (fileno(f) != -1 && (err == ENOSPC || err == EDQUOT || err == EFBIG) &&
((size = getfiledescriptorsize(fileno(f))) == -1 ||
err = ferror_unlocked(f);
if (fileno_unlocked(f) != -1 &&
(err == ENOSPC || err == EDQUOT || err == EFBIG) &&
((size = getfiledescriptorsize(fileno_unlocked(f))) == -1 ||
size > kNontrivialSize)) {
ftruncate(fileno(f), 0);
fseek(f, SEEK_SET, 0);
ftruncate(fileno_unlocked(f), 0);
fseeko_unlocked(f, SEEK_SET, 0);
f->beg = f->end = 0;
clearerr(f);
(fprintf)(f, "performed emergency log truncation: %s\n", strerror(err));
clearerr_unlocked(f);
(fprintf_unlocked)(f, "performed emergency log truncation: %s\n",
strerror(err));
}
}
@ -88,8 +89,8 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
int64_t secs, nsec, dots;
if (!f) f = __log_file;
if (!f) return;
_spinlock(&vflogf_lock);
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
flockfile(f);
--__strace;
t2 = nowl();
secs = t2;
@ -105,16 +106,17 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
bufmode = f->bufmode;
if (bufmode == _IOLBF) f->bufmode = _IOFBF;
if ((fprintf)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", "FEWIVDNT"[level & 7], buf32,
if ((fprintf_unlocked)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ",
"FEWIVDNT"[level & 7], buf32,
rem1000000int64(div1000int64(dots)), file, line,
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
vflogf_onfail(f);
}
(vfprintf)(f, fmt, va);
fprintf(f, "\n");
(vfprintf_unlocked)(f, fmt, va);
fputc_unlocked('\n', f);
if (bufmode == _IOLBF) {
f->bufmode = _IOLBF;
fflush(f);
fflush_unlocked(f);
}
if (level == kLogFatal) {
@ -122,11 +124,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
strcpy(buf32, "unknown");
gethostname(buf32, sizeof(buf32));
(dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid());
_spunlock(&vflogf_lock);
__die();
unreachable;
}
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
_spunlock(&vflogf_lock);
++__strace;
funlockfile(f);
}

View file

@ -27,6 +27,7 @@
* @return memory address, or NULL w/ errno
* @throw EINVAL if !IS2POW(a)
* @see pvalloc()
* @threadsafe
*/
void *aligned_alloc(size_t a, size_t n) {
if (IS2POW(a)) {

View file

@ -26,6 +26,7 @@
* portability, since that's guaranteed to work with all libraries
* @return bytes written (excluding NUL) or -1 w/ errno
* @see xasprintf() for a better API
* @threadsafe
*/
int(asprintf)(char **strp, const char *fmt, ...) {
int res;

View file

@ -26,5 +26,6 @@
// @return rax is memory address, or NULL w/ errno
// @note overreliance on memalign is a sure way to fragment space
// @see dlcalloc()
// @threadsafe
calloc: jmp *hook_calloc(%rip)
.endfn calloc,globl

View file

@ -28,5 +28,6 @@
//
// @param rdi is allocation address, which may be NULL
// @see dlfree()
// @threadsafe
free: jmp *hook_free(%rip)
.endfn free,globl

View file

@ -28,6 +28,7 @@
* that'll be returned.
*
* @return pointer that must be free()'d, or NULL w/ errno
* @threadsafe
*/
dontdiscard char *get_current_dir_name(void) {
const char *p;

View file

@ -33,5 +33,6 @@
//
// @param rdi is number of bytes needed, coerced to 1+
// @return new memory, or NULL w/ errno
// @threadsafe
malloc: jmp *hook_malloc(%rip)
.endfn malloc,globl

View file

@ -35,6 +35,7 @@
// @param rdi is address of allocation
// @return rax is total number of bytes
// @see dlmalloc_usable_size()
// @threadsafe
malloc_usable_size:
jmp *hook_malloc_usable_size(%rip)
.endfn malloc_usable_size,globl

View file

@ -30,6 +30,7 @@
// @param rsi is number of bytes needed, coerced to 1+
// @return rax is memory address, or NULL w/ errno
// @see valloc(), pvalloc()
// @threadsafe
memalign:
jmp *hook_memalign(%rip)
.endfn memalign,globl

View file

@ -35,6 +35,7 @@
* @param bytes is number of bytes to allocate
* @return return 0 or EINVAL or ENOMEM w/o setting errno
* @see memalign()
* @threadsafe
*/
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
int e;

View file

@ -25,6 +25,7 @@
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @see valloc()
* @threadsafe
*/
void *pvalloc(size_t n) {
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));

View file

@ -53,6 +53,7 @@
// @note realloc(p=0, n=0) → malloc(32)
// @note realloc(p≠0, n=0) → free(p)
// @see dlrealloc()
// @threadsafe
realloc:
jmp *hook_realloc(%rip)
.endfn realloc,globl

View file

@ -32,6 +32,7 @@
// @param rsi (newsize) is number of bytes needed
// @return rax is result, or NULL w/ errno
// @see dlrealloc_in_place()
// @threadsafe
realloc_in_place:
jmp *hook_realloc_in_place(%rip)
.endfn realloc_in_place,globl

View file

@ -26,6 +26,7 @@
* @param ptr may be NULL for malloc() behavior
* @param nmemb may be 0 for free() behavior; shrinking is promised too
* @return new address or NULL w/ errno and ptr is NOT free()'d
* @threadsafe
*/
void *reallocarray(void *ptr, size_t nmemb, size_t itemsize) {
size_t n;

View file

@ -25,6 +25,7 @@
* @param s is a NUL-terminated byte string
* @return new string or NULL w/ errno
* @error ENOMEM
* @threadsafe
*/
char *strdup(const char *s) {
size_t len = strlen(s);

View file

@ -26,6 +26,7 @@
* @param n if less than strlen(s) will truncate the string
* @return new string or NULL w/ errno
* @error ENOMEM
* @threadsafe
*/
char *strndup(const char *s, size_t n) {
char *s2;

View file

@ -24,6 +24,7 @@
* @param n number of bytes needed
* @return memory address, or NULL w/ errno
* @see pvalloc()
* @threadsafe
*/
void *valloc(size_t n) {
return memalign(PAGESIZE, n);

View file

@ -23,6 +23,7 @@
/**
* Formats string w/ dynamic memory allocation.
* @see xasprintf() for a better API
* @threadsafe
*/
int(vasprintf)(char **strp, const char *fmt, va_list va) {
va_list vb;

View file

@ -21,6 +21,7 @@
/**
* Allocates copy of wide string.
* @threadsafe
*/
wchar_t *wcsdup(const wchar_t *s) {
size_t len = wcslen(s);

View file

@ -70,7 +70,8 @@ static privileged inline void ReleaseFtraceLock(void) {
}
static privileged inline bool AcquireFtraceLock(void) {
int me, owner, tries;
int me, owner;
unsigned tries;
if (!__threaded) {
return _cmpxchg(&ftrace_lock, 0, -1);
} else {

View file

@ -19,7 +19,6 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"

View file

@ -33,7 +33,7 @@
/**
* Blocks until data from stream buffer is written out.
*
* @param f is the stream handle
* @param f is the stream handle, or 0 for all streams
* @return is 0 on success or -1 on error
*/
int fflush_unlocked(FILE *f) {

View file

@ -16,12 +16,28 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/spinlock.h"
#include "libc/calls/calls.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
* Acquires lock on stdio object, blocking if needed.
* Acquires reentrant lock on stdio object, blocking if needed.
*/
void flockfile(FILE *f) {
_spinlock(&f->lock);
int me, owner;
unsigned tries;
if (!__threaded) return;
for (tries = 0, me = gettid();;) {
owner = 0;
if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) {
return;
}
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
}

View file

@ -31,11 +31,11 @@ void _flushlbf(void) {
_spinlock(&__fflush.lock);
for (i = 0; i < __fflush.handles.i; ++i) {
if ((f = __fflush.handles.p[i])) {
_spinlock(&f->lock);
flockfile(f);
if (f->bufmode == _IOLBF) {
fflush_unlocked(f);
}
_spunlock(&f->lock);
funlockfile(f);
}
}
_spunlock(&__fflush.lock);

View file

@ -18,11 +18,17 @@
*/
#include "libc/stdio/stdio.h"
/**
* Formats and writes text to stream.
* @see printf() for further documentation
*/
int(fprintf)(FILE *f, const char *fmt, ...) {
int rc;
va_list va;
flockfile(f);
va_start(va, fmt);
rc = (vfprintf)(f, fmt, va);
rc = (vfprintf_unlocked)(f, fmt, va);
va_end(va);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/stdio/stdio.h"
/**
* Formats and writes text to stream.
* @see printf() for further documentation
*/
int(fprintf_unlocked)(FILE *f, const char *fmt, ...) {
int rc;
va_list va;
va_start(va, fmt);
rc = (vfprintf_unlocked)(f, fmt, va);
va_end(va);
return rc;
}

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/intrin/spinlock.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
@ -41,7 +40,7 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
FILE *res;
unsigned flags;
flags = fopenflags(mode);
_spinlock(&stream->lock);
flockfile(stream);
fflush_unlocked(stream);
if (pathname) {
/* open new stream, overwriting existing alloc */
@ -60,6 +59,6 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
fcntl(stream->fd, F_SETFL, flags & ~O_CLOEXEC);
res = stream;
}
_spunlock(&stream->lock);
funlockfile(stream);
return res;
}

View file

@ -18,7 +18,6 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
@ -36,11 +35,10 @@
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
* @returns 0 on success or -1 on error
*/
int fseeko(FILE *f, int64_t offset, int whence) {
int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
int res;
ssize_t rc;
int64_t pos;
_spinlock(&f->lock);
if (f->fd != -1) {
if (__fflush_impl(f) == -1) return -1;
if (whence == SEEK_CUR && f->beg < f->end) {
@ -77,6 +75,5 @@ int fseeko(FILE *f, int64_t offset, int whence) {
res = -1;
}
}
_spunlock(&f->lock);
return res;
}

View file

@ -18,7 +18,6 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
@ -49,8 +48,8 @@ static int64_t ftello_unlocked(FILE *f) {
*/
int64_t ftello(FILE *f) {
int64_t rc;
_spinlock(&f->lock);
flockfile(f);
rc = ftello_unlocked(f);
_spunlock(&f->lock);
funlockfile(f);
return rc;
}

View file

@ -16,13 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/spinlock.h"
#include "libc/calls/calls.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h"
/**
* Tries to acquire stdio object lock.
* @return 0 for success or non-zero if someone else has the lock
* Tries to acquire reentrant stdio object lock.
*
* @return 0 on success, or non-zero if another thread owns the lock
*/
int ftrylockfile(FILE *f) {
return _trylock(&f->lock);
int me, owner = 0;
if (__threaded) {
me = gettid();
if (!_lockcmpxchgp(&f->lock, &owner, me) && owner == me) {
owner = 0;
}
}
return owner;
}

View file

@ -19,7 +19,6 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/spinlock.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
@ -87,8 +86,8 @@ static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) {
*/
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
ssize_t rc;
_spinlock(&f->lock);
flockfile(f);
rc = getdelim_unlocked(s, n, delim, f);
_spunlock(&f->lock);
funlockfile(f);
return rc;
}

View file

@ -19,7 +19,7 @@
#include "libc/stdio/stdio.h"
/**
* Formats and writes string to stdout.
* Formats and writes text to stdout.
*
* Cosmopolitan supports most of the standard formatting behaviors
* described by `man 3 printf`, in addition to the following

View file

@ -18,21 +18,32 @@
*/
#include "libc/stdio/stdio.h"
/**
* Writes string w/ trailing newline to stdout.
*/
int puts(const char *s) {
FILE *f;
static int PutsImpl(const char *s, FILE *f) {
size_t n, r;
f = stdout;
if ((n = strlen(s))) {
r = fwrite(s, 1, n, f);
r = fwrite_unlocked(s, 1, n, f);
if (!r) return -1;
if (r < n) return r;
}
if (fputc('\n', f) == -1) {
if (feof(f)) return n;
if (fputc_unlocked('\n', f) == -1) {
if (feof_unlocked(f)) return n;
return -1;
}
return n + 1;
}
/**
* Writes string w/ trailing newline to stdout.
*
* @return non-negative number on success, or `EOF` on error with
* `errno` set and the `ferror(stdout)` state is updated
*/
int puts(const char *s) {
FILE *f;
int bytes;
f = stdout;
flockfile(f);
bytes = PutsImpl(s, f);
funlockfile(f);
return bytes;
}

View file

@ -26,6 +26,9 @@
* EOF state, without reopening it.
*/
void rewind(FILE *f) {
fseek(f, 0, SEEK_SET);
flockfile(f);
if (!fseeko_unlocked(f, 0, SEEK_SET)) {
f->state = 0;
}
funlockfile(f);
}

View file

@ -30,6 +30,7 @@
* @return 0 on success or -1 on error
*/
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);
@ -38,5 +39,6 @@ int setvbuf(FILE *f, char *buf, int mode, size_t size) {
f->nofree = true;
}
f->bufmode = mode;
funlockfile(f);
return 0;
}

View file

@ -116,30 +116,6 @@ int wprintf(const wchar_t *, ...);
int wscanf(const wchar_t *, ...);
int fwide(FILE *, int);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » optimizations
*/
#define getc(f) fgetc(f)
#define getwc(f) fgetwc(f)
#define putc(c, f) fputc(c, f)
#define putwc(c, f) fputwc(c, f)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA)
#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__)
#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA)
#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA)
#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__)
#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__)
#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA)
#endif
#define stdin SYMBOLIC(stdin)
#define stdout SYMBOLIC(stdout)
#define stderr SYMBOLIC(stderr)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » without mutexes
*/
@ -172,12 +148,45 @@ wchar_t *fgetws_unlocked(wchar_t *, int, FILE *);
int fputws_unlocked(const wchar_t *, FILE *);
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
int ungetc_unlocked(int, FILE *) paramsnonnull();
int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull();
int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
paramsnonnull((1, 2)) dontthrow nocallback;
int vfprintf_unlocked(FILE *, const char *, va_list)
paramsnonnull() dontthrow nocallback;
#define getc_unlocked(f) fgetc_unlocked(f)
#define getwc_unlocked(f) fgetwc_unlocked(f)
#define putc_unlocked(c, f) fputc_unlocked(c, f)
#define putwc_unlocked(c, f) fputwc_unlocked(c, f)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § standard i/o » optimizations
*/
#define getc(f) fgetc(f)
#define getwc(f) fgetwc(f)
#define putc(c, f) fputc(c, f)
#define putwc(c, f) fputwc(c, f)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* clang-format off */
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA)
#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__)
#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA)
#define fprintf_unlocked(F, FMT, ...) (fprintf_unlocked)(F, PFLINK(FMT), ##__VA_ARGS__)
#define vfprintf_unlocked(F, FMT, VA) (vfprintf_unlocked)(F, PFLINK(FMT), VA)
#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA)
#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__)
#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__)
#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA)
/* clang-format on */
#endif
#define stdin SYMBOLIC(stdin)
#define stdout SYMBOLIC(stdout)
#define stderr SYMBOLIC(stderr)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_H_ */

View file

@ -22,6 +22,7 @@
//
// @param rdi has stream pointer
// @see clearerr_unlocked()
// @threadsafe
clearerr:
mov %rdi,%r11
ezlea clearerr_unlocked,ax

View file

@ -23,6 +23,7 @@
// @param rdi has file stream object pointer
// @note EOF doesn't count
// @see feof_unlocked()
// @threadsafe
feof: mov %rdi,%r11
ezlea feof_unlocked,ax
jmp stdio_unlock

View file

@ -23,6 +23,7 @@
// @param rdi has file stream object pointer
// @note EOF doesn't count
// @see ferror_unlocked()
// @threadsafe
ferror: mov %rdi,%r11
ezlea ferror_unlocked,ax
jmp stdio_unlock

View file

@ -20,10 +20,14 @@
// Blocks until data from stream buffer is written out.
//
// @param rdi is the stream handle
// @param rdi is the stream handle, or 0 for all streams
// @return 0 on success or -1 w/ errno
// @see fflush_unlocked()
fflush: mov %rdi,%r11
ezlea fflush_unlocked,ax
// @threadsafe
fflush: ezlea fflush_unlocked,ax
test %rdi,%rdi
jz 1f
mov %rdi,%r11
jmp stdio_unlock
1: jmp *%rax
.endfn fflush,globl

View file

@ -23,6 +23,7 @@
// @param rdi has stream object pointer
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
// @threadsafe
fgetc: mov %rdi,%r11
ezlea fgetc_unlocked,ax
jmp stdio_unlock

View file

@ -30,6 +30,7 @@
// @return rax has rdi on success, NULL on error or
// NULL if EOF happens with zero chars read
// @see fgets_unlocked()
// @threadsafe
fgets: mov %rdx,%r11
ezlea fgets_unlocked,ax
jmp stdio_unlock

View file

@ -23,6 +23,7 @@
// @param rdi has stream object pointer
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
// @threadsafe
fgetwc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock

View file

@ -28,6 +28,7 @@
// @param rsi is size of rdi buffer
// @param rsi is file stream object pointer
// @see fgetws_unlocked()
// @threadsafe
fgetws: mov %rdx,%r11
ezlea fgetws_unlocked,ax
jmp stdio_unlock

View file

@ -22,6 +22,7 @@
//
// @param rdi has file stream object pointer
// @see fileno_unlocked()
// @threadsafe
fileno: mov %rdi,%r11
ezlea fileno_unlocked,ax
jmp stdio_unlock

View file

@ -24,6 +24,7 @@
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
fputc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock

View file

@ -28,6 +28,7 @@
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputs_unlocked()
// @threadsafe
fputs: mov %rsi,%r11
ezlea fputs_unlocked,ax
jmp stdio_unlock

View file

@ -24,6 +24,7 @@
// @param rsi has file object stream pointer
// @return rax is wide character if written or -1 w/ errno
// @see fputwc_unlocked()
// @threadsafe
fputwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock

View file

@ -28,6 +28,7 @@
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputws_unlocked()
// @threadsafe
fputws: mov %rsi,%r11
ezlea fputws_unlocked,ax
jmp stdio_unlock

View file

@ -26,6 +26,7 @@
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fread_unlocked()
// @threadsafe
fread: mov %rcx,%r11
ezlea fread_unlocked,ax
jmp stdio_unlock

View file

@ -0,0 +1,37 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 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/macros.internal.h"
// Repositions open file stream.
//
// This function flushes the buffer (unless it's currently in the EOF
// state) and then calls lseek() on the underlying file. If the stream
// is in the EOF state, this function can be used to restore it without
// needing to reopen the file.
//
// @param rdi is stream handle
// @param rsi is offset is the byte delta
// @param rdx is whence and can be SEET_SET, SEEK_CUR, or SEEK_END
// @return 0 on success or -1 w/ errno
// @see fflush_unlocked()
// @threadsafe
fseeko: mov %rdi,%r11
ezlea fseeko_unlocked,ax
jmp stdio_unlock
.endfn fseeko,globl

View file

@ -26,6 +26,7 @@
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fwrite_unlocked()
// @threadsafe
fwrite: mov %rcx,%r11
ezlea fwrite_unlocked,ax
jmp stdio_unlock

View file

@ -23,6 +23,7 @@
// @param rdi has file stream object pointer
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
// @threadsafe
getc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock

View file

@ -22,6 +22,7 @@
//
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
// @threadsafe
getchar:
mov stdin(%rip),%rdi
mov %rdi,%r11

View file

@ -23,6 +23,7 @@
// @param rdi has file stream object pointer
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
// @threadsafe
getwc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock

View file

@ -22,6 +22,7 @@
//
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
// @threadsafe
getwchar:
mov stdin(%rip),%rdi
mov %rdi,%r11

View file

@ -24,6 +24,7 @@
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
putc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock

View file

@ -23,6 +23,7 @@
// @param rdi has character
// @return c (as unsigned char) if written or -1 w/ errno
// @see fputc_unlocked()
// @threadsafe
putchar:
mov stdout(%rip),%rsi
mov %rsi,%r11

View file

@ -24,6 +24,7 @@
// @param rsi has file object
// @return wc if written or -1 w/ errno
// @see putwc_unlocked()
// @threadsafe
putwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock

View file

@ -23,6 +23,7 @@
// @param rdi has wide character
// @return wc if written or -1 w/ errno
// @see fputwc_unlocked()
// @threadsafe
putwchar:
mov stdout(%rip),%rsi
mov %rsi,%r11

View file

@ -18,53 +18,54 @@
*/
#include "libc/macros.internal.h"
#define LOCK 0x2c /* see struct file in stdio.h */
// Wrapper for applying locking to stdio functions.
//
// This function is intended to be called by thunks.
//
// @param rax has the delegate function pointer
// @param rax is stdio function pointer
// @param rdi is passed along as an arg
// @param rsi is passed along as an arg
// @param rdx is passed along as an arg
// @param rcx is passed along as an arg
// @param r8 is passed along as an arg
// @param r9 is passed along as an arg
// @param r10 is passed along as an arg
// @param r11 has the FILE* obj pointer
// @return rax is passed along as result
// @return rdx is passed along as result
// @threadsafe
stdio_unlock:
push %rbp
mov %rsp,%rbp
.profilable
// acquires mutex
push %rcx
push %rax
push %rdi
push %rsi
push %rdx
mov $1,%cl
0: mov LOCK(%r11),%dl # optimistic
test %dl,%dl
je 2f
1: pause # hyperyield
jmp 0b
2: mov %ecx,%edx
xchg LOCK(%r11),%dl # locks bus!
test %dl,%dl
jne 1b
pop %rdx
push %rcx
push %r11
mov %r11,%rdi
call flockfile
pop %r11
pop %rcx
pop %rdx
pop %rsi
pop %rdi
pop %rax
// calls delegate
push %rsi
push %r11
push %rsi # align stack
call *%rax
pop %r11
pop %rsi
pop %r11
// releases mutex
movb $0,LOCK(%r11)
push %rax
push %rdx
mov %r11,%rdi
call funlockfile
pop %rdx
pop %rax
pop %rbp
ret

View file

@ -24,6 +24,7 @@
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetc_unlocked()
// @threadsafe
ungetc: mov %rsi,%r11
ezlea ungetc_unlocked,ax
jmp stdio_unlock

View file

@ -24,6 +24,7 @@
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetwc_unlocked()
// @threadsafe
ungetwc:
mov %rsi,%r11
ezlea ungetwc_unlocked,ax

View file

@ -16,45 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
struct state {
FILE *f;
int n;
};
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
int rc;
if (n) {
_spinlock(&t->f->lock);
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
t->f->bufmode != _IONBF) {
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;
rc = 0;
}
_spunlock(&t->f->lock);
} else {
rc = 0;
}
return 0;
}
/**
* Formats and writes text to stream.
* @see printf() for further documentation
*/
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
struct state st[1] = {{f, 0}};
if (__fmt(vfprintfputchar, st, fmt, va) != -1) {
return st->n;
} else {
return -1;
}
int rc;
flockfile(f);
rc = (vfprintf_unlocked)(f, fmt, va);
funlockfile(f);
return rc;
}

View file

@ -0,0 +1,61 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
struct state {
FILE *f;
int n;
};
static int vfprintfputchar(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) {
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;
rc = 0;
}
} else {
rc = 0;
}
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;
}
return rc;
}

View file

@ -18,6 +18,10 @@
*/
#include "libc/stdio/stdio.h"
/**
* Formats and writes text to stdout.
* @see printf() for further documentation
*/
int(vprintf)(const char* fmt, va_list va) {
return (vfprintf)(stdout, fmt, va);
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
FILE *f;
@ -60,3 +61,13 @@ TEST(fgetc, testUnbuffered) {
EXPECT_TRUE(feof(f));
EXPECT_NE(-1, fclose(f));
}
BENCH(fputc, bench) {
FILE *f;
ASSERT_NE(NULL, (f = fopen("/dev/null", "w")));
EZBENCH2("fputc", donothing, fputc('E', f));
flockfile(f);
EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f));
funlockfile(f);
fclose(f);
}

View file

@ -12,20 +12,6 @@
COSMOPOLITAN_C_START_
/* clang-format off */
#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /*< Failed to open a socket. */
#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /*< The connection to the given server / port failed. */
#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /*< Binding of the socket failed. */
#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /*< Could not listen on the socket. */
#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /*< Could not accept the incoming connection. */
#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /*< Reading information from the socket failed. */
#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /*< Sending information through the socket failed. */
#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /*< Connection was reset by peer. */
#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /*< Failed to get an IP address for the given hostname. */
#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /*< Buffer is too small to hold the data. */
#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /*< The context is invalid, eg because it was free()ed. */
#define MBEDTLS_ERR_NET_POLL_FAILED -0x0047 /*< Polling the net context failed. */
#define MBEDTLS_ERR_NET_BAD_INPUT_DATA -0x0049 /*< Input invalid. */
/*
* SSL Error codes
*/

View file

@ -29,6 +29,7 @@
#include "third_party/mbedtls/ctr_drbg.h"
#include "third_party/mbedtls/ecp.h"
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/platform.h"
#include "third_party/mbedtls/ssl.h"
#include "tool/build/lib/eztls.h"

View file

@ -51,6 +51,7 @@
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "net/https/https.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/ssl.h"
#include "third_party/zlib/zlib.h"
#include "tool/build/lib/eztls.h"
@ -112,6 +113,7 @@ static const struct addrinfo kResolvHints = {.ai_family = AF_INET,
int g_sock;
char *g_prog;
long g_backoff;
char *g_runitd;
jmp_buf g_jmpbuf;
uint16_t g_sshport;
@ -308,7 +310,7 @@ TryAgain:
freeaddrinfo(ai);
}
static void Send(const void *output, size_t outputsize) {
static bool Send(const void *output, size_t outputsize) {
int rc, have;
static bool once;
static z_stream zs;
@ -326,11 +328,17 @@ static void Send(const void *output, size_t outputsize) {
rc = deflate(&zs, Z_SYNC_FLUSH);
CHECK_NE(Z_STREAM_ERROR, rc);
have = sizeof(zbuf) - zs.avail_out;
CHECK_EQ(have, mbedtls_ssl_write(&ezssl, zbuf, have));
rc = mbedtls_ssl_write(&ezssl, zbuf, have);
if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
usleep((g_backoff = (g_backoff + 1000) * 2));
return false;
}
CHECK_EQ(have, rc);
} while (!zs.avail_out);
return true;
}
void SendRequest(void) {
int SendRequest(void) {
int fd;
char *p;
size_t i;
@ -357,22 +365,30 @@ void SendRequest(void) {
q = mempcpy(q, name, namesize);
assert(hdrsize == q - hdr);
DEBUGF("running %s on %s", g_prog, g_hostname);
Send(hdr, hdrsize);
Send(p, progsize);
CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0));
if (Send(hdr, hdrsize) && Send(p, progsize)) {
if (!(rc = EzTlsFlush(&ezbio, 0, 0))) {
rc = 0;
} else if (rc == MBEDTLS_ERR_NET_CONN_RESET) {
rc = -1;
} else {
CHECK_EQ(0, rc);
}
} else {
rc = -1;
}
CHECK_NE(-1, munmap(p, st.st_size));
CHECK_NE(-1, close(fd));
return rc;
}
bool Recv(unsigned char *p, size_t n) {
size_t i, rc;
static long backoff;
for (i = 0; i < n; i += rc) {
do {
rc = mbedtls_ssl_read(&ezssl, p + i, n - i);
} while (rc == MBEDTLS_ERR_SSL_WANT_READ);
if (!rc || rc == MBEDTLS_ERR_NET_CONN_RESET) {
usleep((backoff = (backoff + 1000) * 2));
usleep((g_backoff = (g_backoff + 1000) * 2));
return false;
} else if (rc < 0) {
TlsDie("read response failed", rc);
@ -442,8 +458,7 @@ int RunOnHost(char *spec) {
WARNF("warning: got connection reset in handshake");
close(g_sock);
}
SendRequest();
} while ((rc = ReadResponse()) == -1);
} while ((rc = SendRequest()) == -1 || (rc = ReadResponse()) == -1);
return rc;
}

View file

@ -42,6 +42,7 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
@ -110,7 +111,12 @@ void OnInterrupt(int sig) {
void OnChildTerminated(int sig) {
int ws, pid;
sigset_t ss, oldss;
sigfillset(&ss);
sigdelset(&ss, SIGTERM);
sigprocmask(SIG_BLOCK, &ss, &oldss);
for (;;) {
INFOF("waitpid");
if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) {
if (pid) {
if (WIFEXITED(ws)) {
@ -127,6 +133,7 @@ void OnChildTerminated(int sig) {
FATALF("waitpid failed in sigchld");
}
}
sigprocmask(SIG_SETMASK, &oldss, 0);
}
wontreturn void ShowUsage(FILE *f, int rc) {
@ -229,6 +236,7 @@ void SendExitMessage(int rc) {
msg[0 + 3] = (RUNITD_MAGIC & 0x000000ff) >> 000;
msg[4] = kRunitExit;
msg[5] = rc;
INFOF("mbedtls_ssl_write");
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0));
}
@ -247,6 +255,7 @@ void SendOutputFragmentMessage(enum RunitCommand kind, unsigned char *buf,
msg[5 + 1] = (size & 0x00ff0000) >> 020;
msg[5 + 2] = (size & 0x0000ff00) >> 010;
msg[5 + 3] = (size & 0x000000ff) >> 000;
INFOF("mbedtls_ssl_write");
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
while (size) {
CHECK_NE(-1, (rc = mbedtls_ssl_write(&ezssl, buf, size)));
@ -294,6 +303,7 @@ void Recv(void *output, size_t outputsize) {
// get another fixed-size data packet from network
// pass along error conditions to caller
// pass along eof condition to zlib
INFOF("mbedtls_ssl_read");
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
if (received < 0) TlsDie("read failed", received);
// decompress packet completely
@ -347,12 +357,14 @@ void HandleClient(void) {
/* read request to run program */
addrsize = sizeof(addr);
INFOF("accept");
CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC)));
if (fork()) {
close(g_clifd);
return;
}
EzFd(g_clifd);
INFOF("EzHandshake");
EzHandshake();
addrstr = gc(DescribeAddress(&addr));
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
@ -376,6 +388,7 @@ void HandleClient(void) {
}
CHECK_NE(-1, (g_exefd = creat(g_exepath, 0700)));
LOGIFNEG1(ftruncate(g_exefd, filesize));
INFOF("xwrite");
CHECK_NE(-1, xwrite(g_exefd, exe, filesize));
LOGIFNEG1(close(g_exefd));
@ -425,6 +438,7 @@ void HandleClient(void) {
fds[0].events = POLLIN;
fds[1].fd = pipefds[0];
fds[1].events = POLLIN;
INFOF("poll");
events = poll(fds, ARRAYLEN(fds), (deadline - now) * 1000);
CHECK_NE(-1, events); // EINTR shouldn't be possible
if (fds[0].revents) {
@ -440,6 +454,7 @@ void HandleClient(void) {
LOGIFNEG1(unlink(g_exepath));
_exit(1);
}
INFOF("read");
got = read(pipefds[0], g_buf, sizeof(g_buf));
CHECK_NE(-1, got); // EINTR shouldn't be possible
if (!got) {
@ -449,6 +464,7 @@ void HandleClient(void) {
fwrite(g_buf, got, 1, stderr);
SendOutputFragmentMessage(kRunitStderr, g_buf, got);
}
INFOF("waitpid");
CHECK_NE(-1, waitpid(child, &wstatus, 0)); // EINTR shouldn't be possible
if (WIFEXITED(wstatus)) {
if (WEXITSTATUS(wstatus)) {
@ -463,6 +479,7 @@ void HandleClient(void) {
}
LOGIFNEG1(unlink(g_exepath));
SendExitMessage(exitcode);
INFOF("mbedtls_ssl_close_notify");
mbedtls_ssl_close_notify(&ezssl);
LOGIFNEG1(close(g_clifd));
_exit(0);
@ -524,7 +541,7 @@ void Daemonize(void) {
int main(int argc, char *argv[]) {
int i;
SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk());
/* __log_level = kLogDebug; */
__log_level = kLogInfo;
GetOpts(argc, argv);
for (i = 3; i < 16; ++i) close(i);
errno = 0;

View file

@ -108,6 +108,7 @@
"protip"
"nxbitsafe"
"vforksafe"
"threadsafe"
"preinitsafe"
"asyncsignalsafe"
"notasyncsignalsafe"

View file

@ -146,6 +146,7 @@
#include "third_party/mbedtls/iana.h"
#include "third_party/mbedtls/md.h"
#include "third_party/mbedtls/md5.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/oid.h"
#include "third_party/mbedtls/pk.h"
#include "third_party/mbedtls/rsa.h"

View file

@ -52,6 +52,7 @@
#include "third_party/mbedtls/ctr_drbg.h"
#include "third_party/mbedtls/debug.h"
#include "third_party/mbedtls/error.h"
#include "third_party/mbedtls/net_sockets.h"
#include "third_party/mbedtls/ssl.h"
#define OPTS "BIqksvzX:H:C:m:"