mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Use re-entrant locks on stdio
This commit is contained in:
parent
4e9662cbc7
commit
1f229e4efc
78 changed files with 427 additions and 179 deletions
|
@ -28,15 +28,18 @@
|
||||||
|
|
||||||
_Alignas(64) static int rlock;
|
_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
|
// any thread can poll for interrupts
|
||||||
// but it's wasteful to have every single thread doing it
|
// but it's wasteful to have every single thread doing it
|
||||||
int me, owner, tries;
|
int me, owner = 0;
|
||||||
if (!__threaded) return true;
|
if (__threaded) {
|
||||||
me = gettid();
|
me = gettid();
|
||||||
owner = 0;
|
if (!_lockcmpxchgp(&rlock, &owner, me) && owner == me) {
|
||||||
if (_lockcmpxchgp(&rlock, &owner, me)) return true;
|
owner = 0;
|
||||||
return owner == me;
|
}
|
||||||
|
}
|
||||||
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows inline void ReleaseInterruptPollLock(void) {
|
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) {
|
textwindows bool _check_interrupts(bool restartable, struct Fd *fd) {
|
||||||
bool res;
|
bool res;
|
||||||
if (__time_critical) return false;
|
if (__time_critical) return false;
|
||||||
if (!AcquireInterruptPollLock()) return false;
|
if (AcquireInterruptPollLock()) return false;
|
||||||
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
|
if (weaken(_check_sigalrm)) weaken(_check_sigalrm)();
|
||||||
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
|
if (weaken(_check_sigchld)) weaken(_check_sigchld)();
|
||||||
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);
|
if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd);
|
||||||
|
|
|
@ -27,6 +27,12 @@ __msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns current thread id.
|
* 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
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
privileged int gettid(void) {
|
privileged int gettid(void) {
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
do { \
|
do { \
|
||||||
autotype(lock) __lock = (lock); \
|
autotype(lock) __lock = (lock); \
|
||||||
typeof(*__lock) __x; \
|
typeof(*__lock) __x; \
|
||||||
int __tries = 0; \
|
unsigned __tries = 0; \
|
||||||
for (;;) { \
|
for (;;) { \
|
||||||
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
|
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
|
||||||
if (!__x && !_trylock_inline(__lock)) { \
|
if (!__x && !_trylock_inline(__lock)) { \
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "libc/calls/struct/winsize.h"
|
#include "libc/calls/struct/winsize.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nexgen32e/stackframe.h"
|
#include "libc/nexgen32e/stackframe.h"
|
||||||
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
|
@ -89,7 +90,8 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
--__ftrace; \
|
--__ftrace; \
|
||||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
if (weaken(__die)) weaken(__die)(); \
|
if (weaken(__die)) weaken(__die)(); \
|
||||||
exit(1); \
|
__restorewintty(); \
|
||||||
|
_Exit(1); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
|
@ -41,24 +41,25 @@
|
||||||
#define kNontrivialSize (8 * 1000 * 1000)
|
#define kNontrivialSize (8 * 1000 * 1000)
|
||||||
|
|
||||||
static struct timespec vflogf_ts;
|
static struct timespec vflogf_ts;
|
||||||
_Alignas(64) static int vflogf_lock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes corrective action if logging is on the fritz.
|
* Takes corrective action if logging is on the fritz.
|
||||||
*/
|
*/
|
||||||
void vflogf_onfail(FILE *f) {
|
static void vflogf_onfail(FILE *f) {
|
||||||
errno_t err;
|
errno_t err;
|
||||||
int64_t size;
|
int64_t size;
|
||||||
if (IsTiny()) return;
|
if (IsTiny()) return;
|
||||||
err = ferror(f);
|
err = ferror_unlocked(f);
|
||||||
if (fileno(f) != -1 && (err == ENOSPC || err == EDQUOT || err == EFBIG) &&
|
if (fileno_unlocked(f) != -1 &&
|
||||||
((size = getfiledescriptorsize(fileno(f))) == -1 ||
|
(err == ENOSPC || err == EDQUOT || err == EFBIG) &&
|
||||||
|
((size = getfiledescriptorsize(fileno_unlocked(f))) == -1 ||
|
||||||
size > kNontrivialSize)) {
|
size > kNontrivialSize)) {
|
||||||
ftruncate(fileno(f), 0);
|
ftruncate(fileno_unlocked(f), 0);
|
||||||
fseek(f, SEEK_SET, 0);
|
fseeko_unlocked(f, SEEK_SET, 0);
|
||||||
f->beg = f->end = 0;
|
f->beg = f->end = 0;
|
||||||
clearerr(f);
|
clearerr_unlocked(f);
|
||||||
(fprintf)(f, "performed emergency log truncation: %s\n", strerror(err));
|
(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;
|
int64_t secs, nsec, dots;
|
||||||
if (!f) f = __log_file;
|
if (!f) f = __log_file;
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
_spinlock(&vflogf_lock);
|
flockfile(f);
|
||||||
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
|
--__strace;
|
||||||
|
|
||||||
t2 = nowl();
|
t2 = nowl();
|
||||||
secs = t2;
|
secs = t2;
|
||||||
|
@ -105,16 +106,17 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||||
bufmode = f->bufmode;
|
bufmode = f->bufmode;
|
||||||
if (bufmode == _IOLBF) f->bufmode = _IOFBF;
|
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] ",
|
||||||
rem1000000int64(div1000int64(dots)), file, line,
|
"FEWIVDNT"[level & 7], buf32,
|
||||||
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
rem1000000int64(div1000int64(dots)), file, line,
|
||||||
|
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
||||||
vflogf_onfail(f);
|
vflogf_onfail(f);
|
||||||
}
|
}
|
||||||
(vfprintf)(f, fmt, va);
|
(vfprintf_unlocked)(f, fmt, va);
|
||||||
fprintf(f, "\n");
|
fputc_unlocked('\n', f);
|
||||||
if (bufmode == _IOLBF) {
|
if (bufmode == _IOLBF) {
|
||||||
f->bufmode = _IOLBF;
|
f->bufmode = _IOLBF;
|
||||||
fflush(f);
|
fflush_unlocked(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == kLogFatal) {
|
if (level == kLogFatal) {
|
||||||
|
@ -122,11 +124,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||||
strcpy(buf32, "unknown");
|
strcpy(buf32, "unknown");
|
||||||
gethostname(buf32, sizeof(buf32));
|
gethostname(buf32, sizeof(buf32));
|
||||||
(dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid());
|
(dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid());
|
||||||
_spunlock(&vflogf_lock);
|
|
||||||
__die();
|
__die();
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
|
++__strace;
|
||||||
_spunlock(&vflogf_lock);
|
funlockfile(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
* @return memory address, or NULL w/ errno
|
* @return memory address, or NULL w/ errno
|
||||||
* @throw EINVAL if !IS2POW(a)
|
* @throw EINVAL if !IS2POW(a)
|
||||||
* @see pvalloc()
|
* @see pvalloc()
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
void *aligned_alloc(size_t a, size_t n) {
|
void *aligned_alloc(size_t a, size_t n) {
|
||||||
if (IS2POW(a)) {
|
if (IS2POW(a)) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
* portability, since that's guaranteed to work with all libraries
|
* portability, since that's guaranteed to work with all libraries
|
||||||
* @return bytes written (excluding NUL) or -1 w/ errno
|
* @return bytes written (excluding NUL) or -1 w/ errno
|
||||||
* @see xasprintf() for a better API
|
* @see xasprintf() for a better API
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
int(asprintf)(char **strp, const char *fmt, ...) {
|
int(asprintf)(char **strp, const char *fmt, ...) {
|
||||||
int res;
|
int res;
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
// @return rax is memory address, or NULL w/ errno
|
// @return rax is memory address, or NULL w/ errno
|
||||||
// @note overreliance on memalign is a sure way to fragment space
|
// @note overreliance on memalign is a sure way to fragment space
|
||||||
// @see dlcalloc()
|
// @see dlcalloc()
|
||||||
|
// @threadsafe
|
||||||
calloc: jmp *hook_calloc(%rip)
|
calloc: jmp *hook_calloc(%rip)
|
||||||
.endfn calloc,globl
|
.endfn calloc,globl
|
||||||
|
|
|
@ -28,5 +28,6 @@
|
||||||
//
|
//
|
||||||
// @param rdi is allocation address, which may be NULL
|
// @param rdi is allocation address, which may be NULL
|
||||||
// @see dlfree()
|
// @see dlfree()
|
||||||
|
// @threadsafe
|
||||||
free: jmp *hook_free(%rip)
|
free: jmp *hook_free(%rip)
|
||||||
.endfn free,globl
|
.endfn free,globl
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
* that'll be returned.
|
* that'll be returned.
|
||||||
*
|
*
|
||||||
* @return pointer that must be free()'d, or NULL w/ errno
|
* @return pointer that must be free()'d, or NULL w/ errno
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
dontdiscard char *get_current_dir_name(void) {
|
dontdiscard char *get_current_dir_name(void) {
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
|
@ -33,5 +33,6 @@
|
||||||
//
|
//
|
||||||
// @param rdi is number of bytes needed, coerced to 1+
|
// @param rdi is number of bytes needed, coerced to 1+
|
||||||
// @return new memory, or NULL w/ errno
|
// @return new memory, or NULL w/ errno
|
||||||
|
// @threadsafe
|
||||||
malloc: jmp *hook_malloc(%rip)
|
malloc: jmp *hook_malloc(%rip)
|
||||||
.endfn malloc,globl
|
.endfn malloc,globl
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
// @param rdi is address of allocation
|
// @param rdi is address of allocation
|
||||||
// @return rax is total number of bytes
|
// @return rax is total number of bytes
|
||||||
// @see dlmalloc_usable_size()
|
// @see dlmalloc_usable_size()
|
||||||
|
// @threadsafe
|
||||||
malloc_usable_size:
|
malloc_usable_size:
|
||||||
jmp *hook_malloc_usable_size(%rip)
|
jmp *hook_malloc_usable_size(%rip)
|
||||||
.endfn malloc_usable_size,globl
|
.endfn malloc_usable_size,globl
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
// @param rsi is number of bytes needed, coerced to 1+
|
// @param rsi is number of bytes needed, coerced to 1+
|
||||||
// @return rax is memory address, or NULL w/ errno
|
// @return rax is memory address, or NULL w/ errno
|
||||||
// @see valloc(), pvalloc()
|
// @see valloc(), pvalloc()
|
||||||
|
// @threadsafe
|
||||||
memalign:
|
memalign:
|
||||||
jmp *hook_memalign(%rip)
|
jmp *hook_memalign(%rip)
|
||||||
.endfn memalign,globl
|
.endfn memalign,globl
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
* @param bytes is number of bytes to allocate
|
* @param bytes is number of bytes to allocate
|
||||||
* @return return 0 or EINVAL or ENOMEM w/o setting errno
|
* @return return 0 or EINVAL or ENOMEM w/o setting errno
|
||||||
* @see memalign()
|
* @see memalign()
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
|
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
|
||||||
int e;
|
int e;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
* @param n number of bytes needed
|
* @param n number of bytes needed
|
||||||
* @return memory address, or NULL w/ errno
|
* @return memory address, or NULL w/ errno
|
||||||
* @see valloc()
|
* @see valloc()
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
void *pvalloc(size_t n) {
|
void *pvalloc(size_t n) {
|
||||||
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
|
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
// @note realloc(p=0, n=0) → malloc(32)
|
// @note realloc(p=0, n=0) → malloc(32)
|
||||||
// @note realloc(p≠0, n=0) → free(p)
|
// @note realloc(p≠0, n=0) → free(p)
|
||||||
// @see dlrealloc()
|
// @see dlrealloc()
|
||||||
|
// @threadsafe
|
||||||
realloc:
|
realloc:
|
||||||
jmp *hook_realloc(%rip)
|
jmp *hook_realloc(%rip)
|
||||||
.endfn realloc,globl
|
.endfn realloc,globl
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
// @param rsi (newsize) is number of bytes needed
|
// @param rsi (newsize) is number of bytes needed
|
||||||
// @return rax is result, or NULL w/ errno
|
// @return rax is result, or NULL w/ errno
|
||||||
// @see dlrealloc_in_place()
|
// @see dlrealloc_in_place()
|
||||||
|
// @threadsafe
|
||||||
realloc_in_place:
|
realloc_in_place:
|
||||||
jmp *hook_realloc_in_place(%rip)
|
jmp *hook_realloc_in_place(%rip)
|
||||||
.endfn realloc_in_place,globl
|
.endfn realloc_in_place,globl
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
* @param ptr may be NULL for malloc() behavior
|
* @param ptr may be NULL for malloc() behavior
|
||||||
* @param nmemb may be 0 for free() behavior; shrinking is promised too
|
* @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
|
* @return new address or NULL w/ errno and ptr is NOT free()'d
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
void *reallocarray(void *ptr, size_t nmemb, size_t itemsize) {
|
void *reallocarray(void *ptr, size_t nmemb, size_t itemsize) {
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
* @param s is a NUL-terminated byte string
|
* @param s is a NUL-terminated byte string
|
||||||
* @return new string or NULL w/ errno
|
* @return new string or NULL w/ errno
|
||||||
* @error ENOMEM
|
* @error ENOMEM
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
char *strdup(const char *s) {
|
char *strdup(const char *s) {
|
||||||
size_t len = strlen(s);
|
size_t len = strlen(s);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
* @param n if less than strlen(s) will truncate the string
|
* @param n if less than strlen(s) will truncate the string
|
||||||
* @return new string or NULL w/ errno
|
* @return new string or NULL w/ errno
|
||||||
* @error ENOMEM
|
* @error ENOMEM
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
char *strndup(const char *s, size_t n) {
|
char *strndup(const char *s, size_t n) {
|
||||||
char *s2;
|
char *s2;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
* @param n number of bytes needed
|
* @param n number of bytes needed
|
||||||
* @return memory address, or NULL w/ errno
|
* @return memory address, or NULL w/ errno
|
||||||
* @see pvalloc()
|
* @see pvalloc()
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
void *valloc(size_t n) {
|
void *valloc(size_t n) {
|
||||||
return memalign(PAGESIZE, n);
|
return memalign(PAGESIZE, n);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
/**
|
/**
|
||||||
* Formats string w/ dynamic memory allocation.
|
* Formats string w/ dynamic memory allocation.
|
||||||
* @see xasprintf() for a better API
|
* @see xasprintf() for a better API
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
||||||
va_list vb;
|
va_list vb;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates copy of wide string.
|
* Allocates copy of wide string.
|
||||||
|
* @threadsafe
|
||||||
*/
|
*/
|
||||||
wchar_t *wcsdup(const wchar_t *s) {
|
wchar_t *wcsdup(const wchar_t *s) {
|
||||||
size_t len = wcslen(s);
|
size_t len = wcslen(s);
|
||||||
|
|
|
@ -70,7 +70,8 @@ static privileged inline void ReleaseFtraceLock(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static privileged inline bool AcquireFtraceLock(void) {
|
static privileged inline bool AcquireFtraceLock(void) {
|
||||||
int me, owner, tries;
|
int me, owner;
|
||||||
|
unsigned tries;
|
||||||
if (!__threaded) {
|
if (!__threaded) {
|
||||||
return _cmpxchg(&ftrace_lock, 0, -1);
|
return _cmpxchg(&ftrace_lock, 0, -1);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
/**
|
/**
|
||||||
* Blocks until data from stream buffer is written out.
|
* 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
|
* @return is 0 on success or -1 on error
|
||||||
*/
|
*/
|
||||||
int fflush_unlocked(FILE *f) {
|
int fflush_unlocked(FILE *f) {
|
||||||
|
|
|
@ -16,12 +16,28 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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"
|
#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) {
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@ void _flushlbf(void) {
|
||||||
_spinlock(&__fflush.lock);
|
_spinlock(&__fflush.lock);
|
||||||
for (i = 0; i < __fflush.handles.i; ++i) {
|
for (i = 0; i < __fflush.handles.i; ++i) {
|
||||||
if ((f = __fflush.handles.p[i])) {
|
if ((f = __fflush.handles.p[i])) {
|
||||||
_spinlock(&f->lock);
|
flockfile(f);
|
||||||
if (f->bufmode == _IOLBF) {
|
if (f->bufmode == _IOLBF) {
|
||||||
fflush_unlocked(f);
|
fflush_unlocked(f);
|
||||||
}
|
}
|
||||||
_spunlock(&f->lock);
|
funlockfile(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_spunlock(&__fflush.lock);
|
_spunlock(&__fflush.lock);
|
||||||
|
|
|
@ -18,11 +18,17 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats and writes text to stream.
|
||||||
|
* @see printf() for further documentation
|
||||||
|
*/
|
||||||
int(fprintf)(FILE *f, const char *fmt, ...) {
|
int(fprintf)(FILE *f, const char *fmt, ...) {
|
||||||
int rc;
|
int rc;
|
||||||
va_list va;
|
va_list va;
|
||||||
|
flockfile(f);
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
rc = (vfprintf)(f, fmt, va);
|
rc = (vfprintf_unlocked)(f, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
funlockfile(f);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
32
libc/stdio/fprintf_unlocked.c
Normal file
32
libc/stdio/fprintf_unlocked.c
Normal 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;
|
||||||
|
}
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
|
@ -41,7 +40,7 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
|
||||||
FILE *res;
|
FILE *res;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
flags = fopenflags(mode);
|
flags = fopenflags(mode);
|
||||||
_spinlock(&stream->lock);
|
flockfile(stream);
|
||||||
fflush_unlocked(stream);
|
fflush_unlocked(stream);
|
||||||
if (pathname) {
|
if (pathname) {
|
||||||
/* open new stream, overwriting existing alloc */
|
/* 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);
|
fcntl(stream->fd, F_SETFL, flags & ~O_CLOEXEC);
|
||||||
res = stream;
|
res = stream;
|
||||||
}
|
}
|
||||||
_spunlock(&stream->lock);
|
funlockfile(stream);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
@ -36,11 +35,10 @@
|
||||||
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
|
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
|
||||||
* @returns 0 on success or -1 on error
|
* @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;
|
int res;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
int64_t pos;
|
int64_t pos;
|
||||||
_spinlock(&f->lock);
|
|
||||||
if (f->fd != -1) {
|
if (f->fd != -1) {
|
||||||
if (__fflush_impl(f) == -1) return -1;
|
if (__fflush_impl(f) == -1) return -1;
|
||||||
if (whence == SEEK_CUR && f->beg < f->end) {
|
if (whence == SEEK_CUR && f->beg < f->end) {
|
||||||
|
@ -77,6 +75,5 @@ int fseeko(FILE *f, int64_t offset, int whence) {
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_spunlock(&f->lock);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
@ -49,8 +48,8 @@ static int64_t ftello_unlocked(FILE *f) {
|
||||||
*/
|
*/
|
||||||
int64_t ftello(FILE *f) {
|
int64_t ftello(FILE *f) {
|
||||||
int64_t rc;
|
int64_t rc;
|
||||||
_spinlock(&f->lock);
|
flockfile(f);
|
||||||
rc = ftello_unlocked(f);
|
rc = ftello_unlocked(f);
|
||||||
_spunlock(&f->lock);
|
funlockfile(f);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,23 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to acquire stdio object lock.
|
* Tries to acquire reentrant stdio object lock.
|
||||||
* @return 0 for success or non-zero if someone else has the lock
|
*
|
||||||
|
* @return 0 on success, or non-zero if another thread owns the lock
|
||||||
*/
|
*/
|
||||||
int ftrylockfile(FILE *f) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.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 getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
_spinlock(&f->lock);
|
flockfile(f);
|
||||||
rc = getdelim_unlocked(s, n, delim, f);
|
rc = getdelim_unlocked(s, n, delim, f);
|
||||||
_spunlock(&f->lock);
|
funlockfile(f);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/stdio/stdio.h"
|
#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
|
* Cosmopolitan supports most of the standard formatting behaviors
|
||||||
* described by `man 3 printf`, in addition to the following
|
* described by `man 3 printf`, in addition to the following
|
||||||
|
|
|
@ -18,21 +18,32 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
static int PutsImpl(const char *s, FILE *f) {
|
||||||
* Writes string w/ trailing newline to stdout.
|
|
||||||
*/
|
|
||||||
int puts(const char *s) {
|
|
||||||
FILE *f;
|
|
||||||
size_t n, r;
|
size_t n, r;
|
||||||
f = stdout;
|
|
||||||
if ((n = strlen(s))) {
|
if ((n = strlen(s))) {
|
||||||
r = fwrite(s, 1, n, f);
|
r = fwrite_unlocked(s, 1, n, f);
|
||||||
if (!r) return -1;
|
if (!r) return -1;
|
||||||
if (r < n) return r;
|
if (r < n) return r;
|
||||||
}
|
}
|
||||||
if (fputc('\n', f) == -1) {
|
if (fputc_unlocked('\n', f) == -1) {
|
||||||
if (feof(f)) return n;
|
if (feof_unlocked(f)) return n;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return n + 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;
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
* EOF state, without reopening it.
|
* EOF state, without reopening it.
|
||||||
*/
|
*/
|
||||||
void rewind(FILE *f) {
|
void rewind(FILE *f) {
|
||||||
fseek(f, 0, SEEK_SET);
|
flockfile(f);
|
||||||
f->state = 0;
|
if (!fseeko_unlocked(f, 0, SEEK_SET)) {
|
||||||
|
f->state = 0;
|
||||||
|
}
|
||||||
|
funlockfile(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
* @return 0 on success or -1 on error
|
* @return 0 on success or -1 on error
|
||||||
*/
|
*/
|
||||||
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
|
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
|
||||||
|
flockfile(f);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
if (!size) size = BUFSIZ;
|
if (!size) size = BUFSIZ;
|
||||||
if (!f->nofree && f->buf != buf) free_s(&f->buf);
|
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->nofree = true;
|
||||||
}
|
}
|
||||||
f->bufmode = mode;
|
f->bufmode = mode;
|
||||||
|
funlockfile(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,30 +116,6 @@ int wprintf(const wchar_t *, ...);
|
||||||
int wscanf(const wchar_t *, ...);
|
int wscanf(const wchar_t *, ...);
|
||||||
int fwide(FILE *, int);
|
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 ─╬─│┼
|
│ 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 *);
|
int fputws_unlocked(const wchar_t *, FILE *);
|
||||||
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
|
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
|
||||||
int ungetc_unlocked(int, 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 getc_unlocked(f) fgetc_unlocked(f)
|
||||||
#define getwc_unlocked(f) fgetwc_unlocked(f)
|
#define getwc_unlocked(f) fgetwc_unlocked(f)
|
||||||
#define putc_unlocked(c, f) fputc_unlocked(c, f)
|
#define putc_unlocked(c, f) fputc_unlocked(c, f)
|
||||||
#define putwc_unlocked(c, f) fputwc_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_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_H_ */
|
#endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_H_ */
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
//
|
//
|
||||||
// @param rdi has stream pointer
|
// @param rdi has stream pointer
|
||||||
// @see clearerr_unlocked()
|
// @see clearerr_unlocked()
|
||||||
|
// @threadsafe
|
||||||
clearerr:
|
clearerr:
|
||||||
mov %rdi,%r11
|
mov %rdi,%r11
|
||||||
ezlea clearerr_unlocked,ax
|
ezlea clearerr_unlocked,ax
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has file stream object pointer
|
// @param rdi has file stream object pointer
|
||||||
// @note EOF doesn't count
|
// @note EOF doesn't count
|
||||||
// @see feof_unlocked()
|
// @see feof_unlocked()
|
||||||
|
// @threadsafe
|
||||||
feof: mov %rdi,%r11
|
feof: mov %rdi,%r11
|
||||||
ezlea feof_unlocked,ax
|
ezlea feof_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has file stream object pointer
|
// @param rdi has file stream object pointer
|
||||||
// @note EOF doesn't count
|
// @note EOF doesn't count
|
||||||
// @see ferror_unlocked()
|
// @see ferror_unlocked()
|
||||||
|
// @threadsafe
|
||||||
ferror: mov %rdi,%r11
|
ferror: mov %rdi,%r11
|
||||||
ezlea ferror_unlocked,ax
|
ezlea ferror_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -20,10 +20,14 @@
|
||||||
|
|
||||||
// Blocks until data from stream buffer is written out.
|
// 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
|
// @return 0 on success or -1 w/ errno
|
||||||
// @see fflush_unlocked()
|
// @see fflush_unlocked()
|
||||||
fflush: mov %rdi,%r11
|
// @threadsafe
|
||||||
ezlea fflush_unlocked,ax
|
fflush: ezlea fflush_unlocked,ax
|
||||||
|
test %rdi,%rdi
|
||||||
|
jz 1f
|
||||||
|
mov %rdi,%r11
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
1: jmp *%rax
|
||||||
.endfn fflush,globl
|
.endfn fflush,globl
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has stream object pointer
|
// @param rdi has stream object pointer
|
||||||
// @return byte in range 0..255, or -1 w/ errno
|
// @return byte in range 0..255, or -1 w/ errno
|
||||||
// @see fgetc_unlocked()
|
// @see fgetc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fgetc: mov %rdi,%r11
|
fgetc: mov %rdi,%r11
|
||||||
ezlea fgetc_unlocked,ax
|
ezlea fgetc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
// @return rax has rdi on success, NULL on error or
|
// @return rax has rdi on success, NULL on error or
|
||||||
// NULL if EOF happens with zero chars read
|
// NULL if EOF happens with zero chars read
|
||||||
// @see fgets_unlocked()
|
// @see fgets_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fgets: mov %rdx,%r11
|
fgets: mov %rdx,%r11
|
||||||
ezlea fgets_unlocked,ax
|
ezlea fgets_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has stream object pointer
|
// @param rdi has stream object pointer
|
||||||
// @return wide character or -1 on EOF or error
|
// @return wide character or -1 on EOF or error
|
||||||
// @see fgetwc_unlocked()
|
// @see fgetwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fgetwc: mov %rdi,%r11
|
fgetwc: mov %rdi,%r11
|
||||||
ezlea fgetwc_unlocked,ax
|
ezlea fgetwc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
// @param rsi is size of rdi buffer
|
// @param rsi is size of rdi buffer
|
||||||
// @param rsi is file stream object pointer
|
// @param rsi is file stream object pointer
|
||||||
// @see fgetws_unlocked()
|
// @see fgetws_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fgetws: mov %rdx,%r11
|
fgetws: mov %rdx,%r11
|
||||||
ezlea fgetws_unlocked,ax
|
ezlea fgetws_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
//
|
//
|
||||||
// @param rdi has file stream object pointer
|
// @param rdi has file stream object pointer
|
||||||
// @see fileno_unlocked()
|
// @see fileno_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fileno: mov %rdi,%r11
|
fileno: mov %rdi,%r11
|
||||||
ezlea fileno_unlocked,ax
|
ezlea fileno_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rsi has stream object pointer
|
// @param rsi has stream object pointer
|
||||||
// @return c as unsigned char if written or -1 w/ errno
|
// @return c as unsigned char if written or -1 w/ errno
|
||||||
// @see fputc_unlocked()
|
// @see fputc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fputc: mov %rsi,%r11
|
fputc: mov %rsi,%r11
|
||||||
ezlea fputc_unlocked,ax
|
ezlea fputc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
// @param rsi is file object stream pointer
|
// @param rsi is file object stream pointer
|
||||||
// @return strlen(rdi) on success or -1 w/ errno
|
// @return strlen(rdi) on success or -1 w/ errno
|
||||||
// @see fputs_unlocked()
|
// @see fputs_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fputs: mov %rsi,%r11
|
fputs: mov %rsi,%r11
|
||||||
ezlea fputs_unlocked,ax
|
ezlea fputs_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rsi has file object stream pointer
|
// @param rsi has file object stream pointer
|
||||||
// @return rax is wide character if written or -1 w/ errno
|
// @return rax is wide character if written or -1 w/ errno
|
||||||
// @see fputwc_unlocked()
|
// @see fputwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fputwc: mov %rsi,%r11
|
fputwc: mov %rsi,%r11
|
||||||
ezlea fputwc_unlocked,ax
|
ezlea fputwc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
// @param rsi is file object stream pointer
|
// @param rsi is file object stream pointer
|
||||||
// @return strlen(rdi) on success or -1 w/ errno
|
// @return strlen(rdi) on success or -1 w/ errno
|
||||||
// @see fputws_unlocked()
|
// @see fputws_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fputws: mov %rsi,%r11
|
fputws: mov %rsi,%r11
|
||||||
ezlea fputws_unlocked,ax
|
ezlea fputws_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
// @param rcx has file object stream pointer
|
// @param rcx has file object stream pointer
|
||||||
// @return count on success, [0,count) on EOF, 0 on error or count==0
|
// @return count on success, [0,count) on EOF, 0 on error or count==0
|
||||||
// @see fread_unlocked()
|
// @see fread_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fread: mov %rcx,%r11
|
fread: mov %rcx,%r11
|
||||||
ezlea fread_unlocked,ax
|
ezlea fread_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
37
libc/stdio/unlocked/fseeko_unlocked.S
Normal file
37
libc/stdio/unlocked/fseeko_unlocked.S
Normal 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
|
|
@ -26,6 +26,7 @@
|
||||||
// @param rcx has file object stream pointer
|
// @param rcx has file object stream pointer
|
||||||
// @return count on success, [0,count) on EOF, 0 on error or count==0
|
// @return count on success, [0,count) on EOF, 0 on error or count==0
|
||||||
// @see fwrite_unlocked()
|
// @see fwrite_unlocked()
|
||||||
|
// @threadsafe
|
||||||
fwrite: mov %rcx,%r11
|
fwrite: mov %rcx,%r11
|
||||||
ezlea fwrite_unlocked,ax
|
ezlea fwrite_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has file stream object pointer
|
// @param rdi has file stream object pointer
|
||||||
// @return byte in range 0..255, or -1 w/ errno
|
// @return byte in range 0..255, or -1 w/ errno
|
||||||
// @see fgetc_unlocked()
|
// @see fgetc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
getc: mov %rdi,%r11
|
getc: mov %rdi,%r11
|
||||||
ezlea fgetwc_unlocked,ax
|
ezlea fgetwc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
//
|
//
|
||||||
// @return byte in range 0..255, or -1 w/ errno
|
// @return byte in range 0..255, or -1 w/ errno
|
||||||
// @see fgetc_unlocked()
|
// @see fgetc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
getchar:
|
getchar:
|
||||||
mov stdin(%rip),%rdi
|
mov stdin(%rip),%rdi
|
||||||
mov %rdi,%r11
|
mov %rdi,%r11
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has file stream object pointer
|
// @param rdi has file stream object pointer
|
||||||
// @return wide character or -1 on EOF or error
|
// @return wide character or -1 on EOF or error
|
||||||
// @see fgetwc_unlocked()
|
// @see fgetwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
getwc: mov %rdi,%r11
|
getwc: mov %rdi,%r11
|
||||||
ezlea fgetwc_unlocked,ax
|
ezlea fgetwc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
//
|
//
|
||||||
// @return wide character or -1 on EOF or error
|
// @return wide character or -1 on EOF or error
|
||||||
// @see fgetwc_unlocked()
|
// @see fgetwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
getwchar:
|
getwchar:
|
||||||
mov stdin(%rip),%rdi
|
mov stdin(%rip),%rdi
|
||||||
mov %rdi,%r11
|
mov %rdi,%r11
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rsi has stream object pointer
|
// @param rsi has stream object pointer
|
||||||
// @return c as unsigned char if written or -1 w/ errno
|
// @return c as unsigned char if written or -1 w/ errno
|
||||||
// @see fputc_unlocked()
|
// @see fputc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
putc: mov %rsi,%r11
|
putc: mov %rsi,%r11
|
||||||
ezlea fputc_unlocked,ax
|
ezlea fputc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has character
|
// @param rdi has character
|
||||||
// @return c (as unsigned char) if written or -1 w/ errno
|
// @return c (as unsigned char) if written or -1 w/ errno
|
||||||
// @see fputc_unlocked()
|
// @see fputc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
putchar:
|
putchar:
|
||||||
mov stdout(%rip),%rsi
|
mov stdout(%rip),%rsi
|
||||||
mov %rsi,%r11
|
mov %rsi,%r11
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rsi has file object
|
// @param rsi has file object
|
||||||
// @return wc if written or -1 w/ errno
|
// @return wc if written or -1 w/ errno
|
||||||
// @see putwc_unlocked()
|
// @see putwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
putwc: mov %rsi,%r11
|
putwc: mov %rsi,%r11
|
||||||
ezlea fputwc_unlocked,ax
|
ezlea fputwc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
// @param rdi has wide character
|
// @param rdi has wide character
|
||||||
// @return wc if written or -1 w/ errno
|
// @return wc if written or -1 w/ errno
|
||||||
// @see fputwc_unlocked()
|
// @see fputwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
putwchar:
|
putwchar:
|
||||||
mov stdout(%rip),%rsi
|
mov stdout(%rip),%rsi
|
||||||
mov %rsi,%r11
|
mov %rsi,%r11
|
||||||
|
|
|
@ -18,53 +18,54 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
#define LOCK 0x2c /* see struct file in stdio.h */
|
|
||||||
|
|
||||||
// Wrapper for applying locking to stdio functions.
|
// Wrapper for applying locking to stdio functions.
|
||||||
//
|
//
|
||||||
// This function is intended to be called by thunks.
|
// 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 rdi is passed along as an arg
|
||||||
// @param rsi is passed along as an arg
|
// @param rsi is passed along as an arg
|
||||||
// @param rdx is passed along as an arg
|
// @param rdx is passed along as an arg
|
||||||
// @param rcx 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
|
// @param r11 has the FILE* obj pointer
|
||||||
// @return rax is passed along as result
|
// @return rax is passed along as result
|
||||||
// @return rdx is passed along as result
|
// @return rdx is passed along as result
|
||||||
|
// @threadsafe
|
||||||
stdio_unlock:
|
stdio_unlock:
|
||||||
push %rbp
|
push %rbp
|
||||||
mov %rsp,%rbp
|
mov %rsp,%rbp
|
||||||
.profilable
|
.profilable
|
||||||
|
|
||||||
// acquires mutex
|
// acquires mutex
|
||||||
push %rcx
|
push %rax
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
push %rdx
|
push %rdx
|
||||||
mov $1,%cl
|
push %rcx
|
||||||
0: mov LOCK(%r11),%dl # optimistic
|
push %r11
|
||||||
test %dl,%dl
|
mov %r11,%rdi
|
||||||
je 2f
|
call flockfile
|
||||||
1: pause # hyperyield
|
pop %r11
|
||||||
jmp 0b
|
|
||||||
2: mov %ecx,%edx
|
|
||||||
xchg LOCK(%r11),%dl # locks bus!
|
|
||||||
test %dl,%dl
|
|
||||||
jne 1b
|
|
||||||
pop %rdx
|
|
||||||
pop %rcx
|
pop %rcx
|
||||||
|
pop %rdx
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
pop %rax
|
||||||
|
|
||||||
// calls delegate
|
// calls delegate
|
||||||
push %rsi
|
|
||||||
push %r11
|
push %r11
|
||||||
|
push %rsi # align stack
|
||||||
call *%rax
|
call *%rax
|
||||||
pop %r11
|
|
||||||
pop %rsi
|
pop %rsi
|
||||||
|
pop %r11
|
||||||
|
|
||||||
// releases mutex
|
// releases mutex
|
||||||
movb $0,LOCK(%r11)
|
push %rax
|
||||||
|
push %rdx
|
||||||
|
mov %r11,%rdi
|
||||||
|
call funlockfile
|
||||||
|
pop %rdx
|
||||||
|
pop %rax
|
||||||
|
|
||||||
pop %rbp
|
pop %rbp
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rds has stream object pointer
|
// @param rds has stream object pointer
|
||||||
// @return rax has rdi on success or -1 w/ errno
|
// @return rax has rdi on success or -1 w/ errno
|
||||||
// @see ungetc_unlocked()
|
// @see ungetc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
ungetc: mov %rsi,%r11
|
ungetc: mov %rsi,%r11
|
||||||
ezlea ungetc_unlocked,ax
|
ezlea ungetc_unlocked,ax
|
||||||
jmp stdio_unlock
|
jmp stdio_unlock
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// @param rds has stream object pointer
|
// @param rds has stream object pointer
|
||||||
// @return rax has rdi on success or -1 w/ errno
|
// @return rax has rdi on success or -1 w/ errno
|
||||||
// @see ungetwc_unlocked()
|
// @see ungetwc_unlocked()
|
||||||
|
// @threadsafe
|
||||||
ungetwc:
|
ungetwc:
|
||||||
mov %rsi,%r11
|
mov %rsi,%r11
|
||||||
ezlea ungetwc_unlocked,ax
|
ezlea ungetwc_unlocked,ax
|
||||||
|
|
|
@ -16,45 +16,16 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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/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) {
|
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
||||||
struct state st[1] = {{f, 0}};
|
int rc;
|
||||||
if (__fmt(vfprintfputchar, st, fmt, va) != -1) {
|
flockfile(f);
|
||||||
return st->n;
|
rc = (vfprintf_unlocked)(f, fmt, va);
|
||||||
} else {
|
funlockfile(f);
|
||||||
return -1;
|
return rc;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
61
libc/stdio/vfprintf_unlocked.c
Normal file
61
libc/stdio/vfprintf_unlocked.c
Normal 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;
|
||||||
|
}
|
|
@ -18,6 +18,10 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats and writes text to stdout.
|
||||||
|
* @see printf() for further documentation
|
||||||
|
*/
|
||||||
int(vprintf)(const char* fmt, va_list va) {
|
int(vprintf)(const char* fmt, va_list va) {
|
||||||
return (vfprintf)(stdout, fmt, va);
|
return (vfprintf)(stdout, fmt, va);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
@ -60,3 +61,13 @@ TEST(fgetc, testUnbuffered) {
|
||||||
EXPECT_TRUE(feof(f));
|
EXPECT_TRUE(feof(f));
|
||||||
EXPECT_NE(-1, fclose(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);
|
||||||
|
}
|
||||||
|
|
14
third_party/mbedtls/ssl.h
vendored
14
third_party/mbedtls/ssl.h
vendored
|
@ -12,20 +12,6 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
/* clang-format off */
|
/* 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
|
* SSL Error codes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "third_party/mbedtls/ctr_drbg.h"
|
#include "third_party/mbedtls/ctr_drbg.h"
|
||||||
#include "third_party/mbedtls/ecp.h"
|
#include "third_party/mbedtls/ecp.h"
|
||||||
#include "third_party/mbedtls/error.h"
|
#include "third_party/mbedtls/error.h"
|
||||||
|
#include "third_party/mbedtls/net_sockets.h"
|
||||||
#include "third_party/mbedtls/platform.h"
|
#include "third_party/mbedtls/platform.h"
|
||||||
#include "third_party/mbedtls/ssl.h"
|
#include "third_party/mbedtls/ssl.h"
|
||||||
#include "tool/build/lib/eztls.h"
|
#include "tool/build/lib/eztls.h"
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "net/https/https.h"
|
#include "net/https/https.h"
|
||||||
|
#include "third_party/mbedtls/net_sockets.h"
|
||||||
#include "third_party/mbedtls/ssl.h"
|
#include "third_party/mbedtls/ssl.h"
|
||||||
#include "third_party/zlib/zlib.h"
|
#include "third_party/zlib/zlib.h"
|
||||||
#include "tool/build/lib/eztls.h"
|
#include "tool/build/lib/eztls.h"
|
||||||
|
@ -112,6 +113,7 @@ static const struct addrinfo kResolvHints = {.ai_family = AF_INET,
|
||||||
|
|
||||||
int g_sock;
|
int g_sock;
|
||||||
char *g_prog;
|
char *g_prog;
|
||||||
|
long g_backoff;
|
||||||
char *g_runitd;
|
char *g_runitd;
|
||||||
jmp_buf g_jmpbuf;
|
jmp_buf g_jmpbuf;
|
||||||
uint16_t g_sshport;
|
uint16_t g_sshport;
|
||||||
|
@ -308,7 +310,7 @@ TryAgain:
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Send(const void *output, size_t outputsize) {
|
static bool Send(const void *output, size_t outputsize) {
|
||||||
int rc, have;
|
int rc, have;
|
||||||
static bool once;
|
static bool once;
|
||||||
static z_stream zs;
|
static z_stream zs;
|
||||||
|
@ -326,11 +328,17 @@ static void Send(const void *output, size_t outputsize) {
|
||||||
rc = deflate(&zs, Z_SYNC_FLUSH);
|
rc = deflate(&zs, Z_SYNC_FLUSH);
|
||||||
CHECK_NE(Z_STREAM_ERROR, rc);
|
CHECK_NE(Z_STREAM_ERROR, rc);
|
||||||
have = sizeof(zbuf) - zs.avail_out;
|
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);
|
} while (!zs.avail_out);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendRequest(void) {
|
int SendRequest(void) {
|
||||||
int fd;
|
int fd;
|
||||||
char *p;
|
char *p;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -357,22 +365,30 @@ void SendRequest(void) {
|
||||||
q = mempcpy(q, name, namesize);
|
q = mempcpy(q, name, namesize);
|
||||||
assert(hdrsize == q - hdr);
|
assert(hdrsize == q - hdr);
|
||||||
DEBUGF("running %s on %s", g_prog, g_hostname);
|
DEBUGF("running %s on %s", g_prog, g_hostname);
|
||||||
Send(hdr, hdrsize);
|
if (Send(hdr, hdrsize) && Send(p, progsize)) {
|
||||||
Send(p, progsize);
|
if (!(rc = EzTlsFlush(&ezbio, 0, 0))) {
|
||||||
CHECK_EQ(0, 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, munmap(p, st.st_size));
|
||||||
CHECK_NE(-1, close(fd));
|
CHECK_NE(-1, close(fd));
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Recv(unsigned char *p, size_t n) {
|
bool Recv(unsigned char *p, size_t n) {
|
||||||
size_t i, rc;
|
size_t i, rc;
|
||||||
static long backoff;
|
|
||||||
for (i = 0; i < n; i += rc) {
|
for (i = 0; i < n; i += rc) {
|
||||||
do {
|
do {
|
||||||
rc = mbedtls_ssl_read(&ezssl, p + i, n - i);
|
rc = mbedtls_ssl_read(&ezssl, p + i, n - i);
|
||||||
} while (rc == MBEDTLS_ERR_SSL_WANT_READ);
|
} while (rc == MBEDTLS_ERR_SSL_WANT_READ);
|
||||||
if (!rc || rc == MBEDTLS_ERR_NET_CONN_RESET) {
|
if (!rc || rc == MBEDTLS_ERR_NET_CONN_RESET) {
|
||||||
usleep((backoff = (backoff + 1000) * 2));
|
usleep((g_backoff = (g_backoff + 1000) * 2));
|
||||||
return false;
|
return false;
|
||||||
} else if (rc < 0) {
|
} else if (rc < 0) {
|
||||||
TlsDie("read response failed", rc);
|
TlsDie("read response failed", rc);
|
||||||
|
@ -442,8 +458,7 @@ int RunOnHost(char *spec) {
|
||||||
WARNF("warning: got connection reset in handshake");
|
WARNF("warning: got connection reset in handshake");
|
||||||
close(g_sock);
|
close(g_sock);
|
||||||
}
|
}
|
||||||
SendRequest();
|
} while ((rc = SendRequest()) == -1 || (rc = ReadResponse()) == -1);
|
||||||
} while ((rc = ReadResponse()) == -1);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/so.h"
|
#include "libc/sysv/consts/so.h"
|
||||||
#include "libc/sysv/consts/sock.h"
|
#include "libc/sysv/consts/sock.h"
|
||||||
#include "libc/sysv/consts/sol.h"
|
#include "libc/sysv/consts/sol.h"
|
||||||
|
@ -110,7 +111,12 @@ void OnInterrupt(int sig) {
|
||||||
|
|
||||||
void OnChildTerminated(int sig) {
|
void OnChildTerminated(int sig) {
|
||||||
int ws, pid;
|
int ws, pid;
|
||||||
|
sigset_t ss, oldss;
|
||||||
|
sigfillset(&ss);
|
||||||
|
sigdelset(&ss, SIGTERM);
|
||||||
|
sigprocmask(SIG_BLOCK, &ss, &oldss);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
INFOF("waitpid");
|
||||||
if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) {
|
if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) {
|
||||||
if (pid) {
|
if (pid) {
|
||||||
if (WIFEXITED(ws)) {
|
if (WIFEXITED(ws)) {
|
||||||
|
@ -127,6 +133,7 @@ void OnChildTerminated(int sig) {
|
||||||
FATALF("waitpid failed in sigchld");
|
FATALF("waitpid failed in sigchld");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sigprocmask(SIG_SETMASK, &oldss, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wontreturn void ShowUsage(FILE *f, int rc) {
|
wontreturn void ShowUsage(FILE *f, int rc) {
|
||||||
|
@ -229,6 +236,7 @@ void SendExitMessage(int rc) {
|
||||||
msg[0 + 3] = (RUNITD_MAGIC & 0x000000ff) >> 000;
|
msg[0 + 3] = (RUNITD_MAGIC & 0x000000ff) >> 000;
|
||||||
msg[4] = kRunitExit;
|
msg[4] = kRunitExit;
|
||||||
msg[5] = rc;
|
msg[5] = rc;
|
||||||
|
INFOF("mbedtls_ssl_write");
|
||||||
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
|
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
|
||||||
CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0));
|
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 + 1] = (size & 0x00ff0000) >> 020;
|
||||||
msg[5 + 2] = (size & 0x0000ff00) >> 010;
|
msg[5 + 2] = (size & 0x0000ff00) >> 010;
|
||||||
msg[5 + 3] = (size & 0x000000ff) >> 000;
|
msg[5 + 3] = (size & 0x000000ff) >> 000;
|
||||||
|
INFOF("mbedtls_ssl_write");
|
||||||
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
|
CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg)));
|
||||||
while (size) {
|
while (size) {
|
||||||
CHECK_NE(-1, (rc = mbedtls_ssl_write(&ezssl, buf, 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
|
// get another fixed-size data packet from network
|
||||||
// pass along error conditions to caller
|
// pass along error conditions to caller
|
||||||
// pass along eof condition to zlib
|
// pass along eof condition to zlib
|
||||||
|
INFOF("mbedtls_ssl_read");
|
||||||
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
|
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
|
||||||
if (received < 0) TlsDie("read failed", received);
|
if (received < 0) TlsDie("read failed", received);
|
||||||
// decompress packet completely
|
// decompress packet completely
|
||||||
|
@ -347,12 +357,14 @@ void HandleClient(void) {
|
||||||
|
|
||||||
/* read request to run program */
|
/* read request to run program */
|
||||||
addrsize = sizeof(addr);
|
addrsize = sizeof(addr);
|
||||||
|
INFOF("accept");
|
||||||
CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC)));
|
CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC)));
|
||||||
if (fork()) {
|
if (fork()) {
|
||||||
close(g_clifd);
|
close(g_clifd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EzFd(g_clifd);
|
EzFd(g_clifd);
|
||||||
|
INFOF("EzHandshake");
|
||||||
EzHandshake();
|
EzHandshake();
|
||||||
addrstr = gc(DescribeAddress(&addr));
|
addrstr = gc(DescribeAddress(&addr));
|
||||||
DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr);
|
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)));
|
CHECK_NE(-1, (g_exefd = creat(g_exepath, 0700)));
|
||||||
LOGIFNEG1(ftruncate(g_exefd, filesize));
|
LOGIFNEG1(ftruncate(g_exefd, filesize));
|
||||||
|
INFOF("xwrite");
|
||||||
CHECK_NE(-1, xwrite(g_exefd, exe, filesize));
|
CHECK_NE(-1, xwrite(g_exefd, exe, filesize));
|
||||||
LOGIFNEG1(close(g_exefd));
|
LOGIFNEG1(close(g_exefd));
|
||||||
|
|
||||||
|
@ -425,6 +438,7 @@ void HandleClient(void) {
|
||||||
fds[0].events = POLLIN;
|
fds[0].events = POLLIN;
|
||||||
fds[1].fd = pipefds[0];
|
fds[1].fd = pipefds[0];
|
||||||
fds[1].events = POLLIN;
|
fds[1].events = POLLIN;
|
||||||
|
INFOF("poll");
|
||||||
events = poll(fds, ARRAYLEN(fds), (deadline - now) * 1000);
|
events = poll(fds, ARRAYLEN(fds), (deadline - now) * 1000);
|
||||||
CHECK_NE(-1, events); // EINTR shouldn't be possible
|
CHECK_NE(-1, events); // EINTR shouldn't be possible
|
||||||
if (fds[0].revents) {
|
if (fds[0].revents) {
|
||||||
|
@ -440,6 +454,7 @@ void HandleClient(void) {
|
||||||
LOGIFNEG1(unlink(g_exepath));
|
LOGIFNEG1(unlink(g_exepath));
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
INFOF("read");
|
||||||
got = read(pipefds[0], g_buf, sizeof(g_buf));
|
got = read(pipefds[0], g_buf, sizeof(g_buf));
|
||||||
CHECK_NE(-1, got); // EINTR shouldn't be possible
|
CHECK_NE(-1, got); // EINTR shouldn't be possible
|
||||||
if (!got) {
|
if (!got) {
|
||||||
|
@ -449,6 +464,7 @@ void HandleClient(void) {
|
||||||
fwrite(g_buf, got, 1, stderr);
|
fwrite(g_buf, got, 1, stderr);
|
||||||
SendOutputFragmentMessage(kRunitStderr, g_buf, got);
|
SendOutputFragmentMessage(kRunitStderr, g_buf, got);
|
||||||
}
|
}
|
||||||
|
INFOF("waitpid");
|
||||||
CHECK_NE(-1, waitpid(child, &wstatus, 0)); // EINTR shouldn't be possible
|
CHECK_NE(-1, waitpid(child, &wstatus, 0)); // EINTR shouldn't be possible
|
||||||
if (WIFEXITED(wstatus)) {
|
if (WIFEXITED(wstatus)) {
|
||||||
if (WEXITSTATUS(wstatus)) {
|
if (WEXITSTATUS(wstatus)) {
|
||||||
|
@ -463,6 +479,7 @@ void HandleClient(void) {
|
||||||
}
|
}
|
||||||
LOGIFNEG1(unlink(g_exepath));
|
LOGIFNEG1(unlink(g_exepath));
|
||||||
SendExitMessage(exitcode);
|
SendExitMessage(exitcode);
|
||||||
|
INFOF("mbedtls_ssl_close_notify");
|
||||||
mbedtls_ssl_close_notify(&ezssl);
|
mbedtls_ssl_close_notify(&ezssl);
|
||||||
LOGIFNEG1(close(g_clifd));
|
LOGIFNEG1(close(g_clifd));
|
||||||
_exit(0);
|
_exit(0);
|
||||||
|
@ -524,7 +541,7 @@ void Daemonize(void) {
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int i;
|
int i;
|
||||||
SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk());
|
SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk());
|
||||||
/* __log_level = kLogDebug; */
|
__log_level = kLogInfo;
|
||||||
GetOpts(argc, argv);
|
GetOpts(argc, argv);
|
||||||
for (i = 3; i < 16; ++i) close(i);
|
for (i = 3; i < 16; ++i) close(i);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
"protip"
|
"protip"
|
||||||
"nxbitsafe"
|
"nxbitsafe"
|
||||||
"vforksafe"
|
"vforksafe"
|
||||||
|
"threadsafe"
|
||||||
"preinitsafe"
|
"preinitsafe"
|
||||||
"asyncsignalsafe"
|
"asyncsignalsafe"
|
||||||
"notasyncsignalsafe"
|
"notasyncsignalsafe"
|
||||||
|
|
|
@ -146,6 +146,7 @@
|
||||||
#include "third_party/mbedtls/iana.h"
|
#include "third_party/mbedtls/iana.h"
|
||||||
#include "third_party/mbedtls/md.h"
|
#include "third_party/mbedtls/md.h"
|
||||||
#include "third_party/mbedtls/md5.h"
|
#include "third_party/mbedtls/md5.h"
|
||||||
|
#include "third_party/mbedtls/net_sockets.h"
|
||||||
#include "third_party/mbedtls/oid.h"
|
#include "third_party/mbedtls/oid.h"
|
||||||
#include "third_party/mbedtls/pk.h"
|
#include "third_party/mbedtls/pk.h"
|
||||||
#include "third_party/mbedtls/rsa.h"
|
#include "third_party/mbedtls/rsa.h"
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "third_party/mbedtls/ctr_drbg.h"
|
#include "third_party/mbedtls/ctr_drbg.h"
|
||||||
#include "third_party/mbedtls/debug.h"
|
#include "third_party/mbedtls/debug.h"
|
||||||
#include "third_party/mbedtls/error.h"
|
#include "third_party/mbedtls/error.h"
|
||||||
|
#include "third_party/mbedtls/net_sockets.h"
|
||||||
#include "third_party/mbedtls/ssl.h"
|
#include "third_party/mbedtls/ssl.h"
|
||||||
|
|
||||||
#define OPTS "BIqksvzX:H:C:m:"
|
#define OPTS "BIqksvzX:H:C:m:"
|
||||||
|
|
Loading…
Add table
Reference in a new issue