Apply even more fixups

- Finish cleaning up the stdio unlocked APIs
- Make __cxa_finalize() properly thread safe
- Don't log locks if threads aren't being used
- Add some more mutex guards to places using _mmi
- Specific lock names now appear in the --ftrace logs
- Fix mkdeps.com generating invalid Makefiles sometimes
- Simplify and fix bugs in the test runner infrastructure
- Fix issue where sometimes some functions wouldn't be logged
This commit is contained in:
Justine Tunney 2022-06-12 11:47:20 -07:00
parent 4ddfc47d6e
commit 8cdec62f5b
87 changed files with 955 additions and 899 deletions

View file

@ -1607,6 +1607,9 @@ ape_pad_text:
.type ape_pad_privileged,@object .type ape_pad_privileged,@object
.hidden ape_pad_privileged .hidden ape_pad_privileged
ape_pad_privileged: ape_pad_privileged:
#if !IsTiny()
.align 4096
#endif
.previous .previous
.section .ape.pad.rodata,"a",@progbits .section .ape.pad.rodata,"a",@progbits

Binary file not shown.

View file

@ -37,7 +37,8 @@ EXAMPLES_COMS = \
EXAMPLES_BINS = \ EXAMPLES_BINS = \
$(EXAMPLES_COMS) \ $(EXAMPLES_COMS) \
$(EXAMPLES_COMS:%=%.dbg) \ $(EXAMPLES_COMS:%=%.dbg) \
o/$(MODE)/examples/life-nomod.com o/$(MODE)/examples/life-nomod.com \
o/$(MODE)/examples/life-classic.com
EXAMPLES_DIRECTDEPS = \ EXAMPLES_DIRECTDEPS = \
DSP_CORE \ DSP_CORE \

View file

@ -61,7 +61,6 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
size_t i; size_t i;
uint32_t dwExitCode; uint32_t dwExitCode;
char progbuf[PATH_MAX]; char progbuf[PATH_MAX];
struct MemoryIntervals *mm;
struct NtStartupInfo startinfo; struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo; struct NtProcessInformation procinfo;

View file

@ -16,8 +16,18 @@
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/state.internal.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
unsigned __sighandrvas[NSIG]; unsigned __sighandrvas[NSIG];
unsigned __sighandflags[NSIG]; unsigned __sighandflags[NSIG];
pthread_mutex_t __sig_lock_obj;
static pthread_mutex_t __sig_lock_obj;
void(__sig_lock)(void) {
pthread_mutex_lock(&__sig_lock_obj);
}
void(__sig_unlock)(void) {
pthread_mutex_unlock(&__sig_lock_obj);
}

View file

@ -1,6 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_
#include "libc/intrin/pthread.h" #include "libc/nexgen32e/threaded.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -8,14 +8,17 @@ hidden extern int __vforked;
hidden extern bool __time_critical; hidden extern bool __time_critical;
hidden extern unsigned __sighandrvas[NSIG]; hidden extern unsigned __sighandrvas[NSIG];
hidden extern unsigned __sighandflags[NSIG]; hidden extern unsigned __sighandflags[NSIG];
hidden extern pthread_mutex_t __sig_lock_obj;
hidden extern pthread_mutex_t __fds_lock_obj;
hidden extern const struct NtSecurityAttributes kNtIsInheritable; hidden extern const struct NtSecurityAttributes kNtIsInheritable;
#define __fds_lock() pthread_mutex_lock(&__fds_lock_obj) void __fds_lock(void);
#define __fds_unlock() pthread_mutex_unlock(&__fds_lock_obj) void __fds_unlock(void);
#define __sig_lock() pthread_mutex_lock(&__sig_lock_obj) void __sig_lock(void);
#define __sig_unlock() pthread_mutex_unlock(&__sig_lock_obj) void __sig_unlock(void);
#define __fds_lock() (__threaded ? __fds_lock() : 0)
#define __fds_unlock() (__threaded ? __fds_unlock() : 0)
#define __sig_lock() (__threaded ? __sig_lock() : 0)
#define __sig_unlock() (__threaded ? __sig_unlock() : 0)
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -858,25 +858,25 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
void *__asan_morgue_add(void *p) { void *__asan_morgue_add(void *p) {
int i; int i;
void *r; void *r;
pthread_mutex_lock(&__asan_lock); if (__threaded) pthread_mutex_lock(&__asan_lock);
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1); i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
r = __asan_morgue.p[i]; r = __asan_morgue.p[i];
__asan_morgue.p[i] = p; __asan_morgue.p[i] = p;
pthread_mutex_unlock(&__asan_lock); if (__threaded) pthread_mutex_unlock(&__asan_lock);
return r; return r;
} }
static void __asan_morgue_flush(void) { static void __asan_morgue_flush(void) {
int i; int i;
void *p; void *p;
pthread_mutex_lock(&__asan_lock); if (__threaded) pthread_mutex_lock(&__asan_lock);
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) { for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
if (__asan_morgue.p[i] && weaken(dlfree)) { if (__asan_morgue.p[i] && weaken(dlfree)) {
weaken(dlfree)(__asan_morgue.p[i]); weaken(dlfree)(__asan_morgue.p[i]);
} }
__asan_morgue.p[i] = 0; __asan_morgue.p[i] = 0;
} }
pthread_mutex_unlock(&__asan_lock); if (__threaded) pthread_mutex_unlock(&__asan_lock);
} }
static size_t __asan_user_size(size_t n) { static size_t __asan_user_size(size_t n) {

View file

@ -16,6 +16,15 @@
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/pthread.h"
#include "libc/runtime/cxaatexit.internal.h" #include "libc/runtime/cxaatexit.internal.h"
pthread_mutex_t __cxa_lock_obj; static pthread_mutex_t __cxa_lock_obj;
void(__cxa_lock)(void) {
pthread_mutex_lock(&__cxa_lock_obj);
}
void(__cxa_unlock)(void) {
pthread_mutex_unlock(&__cxa_lock_obj);
}

View file

@ -27,7 +27,15 @@
STATIC_YOINK("_init_g_fds"); STATIC_YOINK("_init_g_fds");
struct Fds g_fds; struct Fds g_fds;
pthread_mutex_t __fds_lock_obj; static pthread_mutex_t __fds_lock_obj;
void(__fds_lock)(void) {
pthread_mutex_lock(&__fds_lock_obj);
}
void(__fds_unlock)(void) {
pthread_mutex_unlock(&__fds_lock_obj);
}
textstartup void InitializeFileDescriptors(void) { textstartup void InitializeFileDescriptors(void) {
struct Fds *fds; struct Fds *fds;

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/nexgen32e/gettls.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"

View file

@ -72,6 +72,21 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
-fno-sanitize=all \ -fno-sanitize=all \
-fno-stack-protector -fno-stack-protector
# synchronization primitives are intended to be magic free
o/$(MODE)/libc/intrin/gettid.greg.o \
o/$(MODE)/libc/intrin/pthread_mutex_lock.o \
o/$(MODE)/libc/intrin/pthread_mutex_unlock.o \
o/$(MODE)/libc/intrin/pthread_mutex_trylock.o \
o/$(MODE)/libc/intrin/_trylock_debug_4.o \
o/$(MODE)/libc/intrin/_spinlock_debug_4.o: \
OVERRIDE_CFLAGS += \
-fwrapv \
-x-no-pg \
-mno-fentry \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
o/$(MODE)/libc/intrin/tls.greg.o \ o/$(MODE)/libc/intrin/tls.greg.o \
o/$(MODE)/libc/intrin/exit.greg.o \ o/$(MODE)/libc/intrin/exit.greg.o \
o/$(MODE)/libc/intrin/exit1.greg.o \ o/$(MODE)/libc/intrin/exit1.greg.o \

View file

@ -16,8 +16,18 @@
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/pthread.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
STATIC_YOINK("_init__mmi"); STATIC_YOINK("_init__mmi");
struct MemoryIntervals _mmi; struct MemoryIntervals _mmi;
static pthread_mutex_t __mmi_lock_obj;
void(__mmi_lock)(void) {
pthread_mutex_lock(&__mmi_lock_obj);
}
void(__mmi_unlock)(void) {
pthread_mutex_unlock(&__mmi_lock_obj);
}

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ #ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ #define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -23,9 +24,9 @@ typedef unsigned long *pthread_t;
typedef int pthread_once_t; typedef int pthread_once_t;
typedef struct { typedef struct {
_Atomic(int) owner;
_Atomic(int) waits;
int reent; int reent;
int owner;
int waits;
} pthread_mutex_t; } pthread_mutex_t;
typedef struct { typedef struct {

View file

@ -18,7 +18,8 @@
*/ */
#include "libc/bits/atomic.h" #include "libc/bits/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/lockcmpxchgp.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/sysv/consts/futex.h" #include "libc/sysv/consts/futex.h"
@ -26,25 +27,24 @@
/** /**
* Acquires mutex. * Acquires mutex.
*/ */
noasan noubsan int pthread_mutex_lock(pthread_mutex_t *mutex) { int pthread_mutex_lock(pthread_mutex_t *mutex) {
int me, owner; int me, owner;
unsigned tries; unsigned tries;
if (__threaded) { for (tries = 0, me = gettid();;) {
for (tries = 0, me = gettid();;) { owner = 0;
owner = 0; if (atomic_compare_exchange_weak(&mutex->owner, &owner, me) ||
if (_lockcmpxchgp(&mutex->owner, &owner, me) || owner == me) { owner == me) {
break; break;
}
atomic_fetch_add(&mutex->waits, +1);
if (!IsLinux() || futex((void *)&mutex->owner, FUTEX_WAIT, owner, 0, 0)) {
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
atomic_fetch_add(&mutex->waits, -1);
} }
atomic_fetch_add(&mutex->waits, +1);
if (!IsLinux() || futex((void *)&mutex->owner, FUTEX_WAIT, owner, 0, 0)) {
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
atomic_fetch_add(&mutex->waits, -1);
} }
++mutex->reent; ++mutex->reent;
return 0; return 0;

View file

@ -16,9 +16,9 @@
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/bits/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
@ -26,18 +26,15 @@
* Tries to acquire mutex. * Tries to acquire mutex.
*/ */
int pthread_mutex_trylock(pthread_mutex_t *mutex) { int pthread_mutex_trylock(pthread_mutex_t *mutex) {
int rc, me, owner = 0; int rc, me, owner;
if (__threaded) { me = gettid();
me = gettid(); owner = 0;
if (!_lockcmpxchgp(&mutex->owner, &owner, me) && owner == me) { if (!atomic_compare_exchange_strong(&mutex->owner, &owner, me) &&
rc = 0; owner == me) {
++mutex->reent;
} else {
rc = EBUSY;
}
} else {
rc = 0; rc = 0;
++mutex->reent; ++mutex->reent;
} else {
rc = EBUSY;
} }
return rc; return rc;
} }

View file

@ -20,6 +20,7 @@
#include "libc/bits/atomic.h" #include "libc/bits/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/sysv/consts/futex.h" #include "libc/sysv/consts/futex.h"
@ -27,19 +28,17 @@
/** /**
* Releases mutex. * Releases mutex.
*/ */
noasan noubsan int pthread_mutex_unlock(pthread_mutex_t *mutex) { int pthread_mutex_unlock(pthread_mutex_t *mutex) {
int owner; int owner;
bool shouldunlock; bool shouldunlock;
assert(mutex->reent > 0); assert(mutex->reent > 0);
shouldunlock = --mutex->reent <= 0; shouldunlock = --mutex->reent <= 0;
if (__threaded) { assert(mutex->owner == gettid());
assert(mutex->owner == gettid()); if (shouldunlock) {
if (shouldunlock) { atomic_store_explicit(&mutex->owner, 0, memory_order_relaxed);
atomic_store_explicit(&mutex->owner, 0, memory_order_relaxed); if (IsLinux() &&
if (IsLinux() && atomic_load_explicit(&mutex->waits, memory_order_acquire)) {
atomic_load_explicit(&mutex->waits, memory_order_acquire)) { futex((void *)&mutex->owner, FUTEX_WAKE, 1, 0, 0);
futex((void *)&mutex->owner, FUTEX_WAKE, 1, 0, 0);
}
} }
} }
return 0; return 0;

View file

@ -7,6 +7,7 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
forceinline pureconst bool IsValidStackFramePointer(struct StackFrame *x) { forceinline pureconst bool IsValidStackFramePointer(struct StackFrame *x) {
/* assumes __mmi_lock() is held */
return IsLegalPointer(x) && !((uintptr_t)x & 15) && return IsLegalPointer(x) && !((uintptr_t)x & 15) &&
(IsStaticStackFrame((uintptr_t)x >> 16) || (IsStaticStackFrame((uintptr_t)x >> 16) ||
IsSigAltStackFrame((uintptr_t)x >> 16) || IsSigAltStackFrame((uintptr_t)x >> 16) ||

View file

@ -53,6 +53,7 @@ static void ShowHint(const char *s) {
} }
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
bool ok;
ssize_t got; ssize_t got;
intptr_t addr; intptr_t addr;
size_t i, j, gi; size_t i, j, gi;
@ -99,7 +100,10 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) { for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
if (!IsValidStackFramePointer(frame)) { __mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
return -1; return -1;
} }
addr = frame->addr; addr = frame->addr;

View file

@ -27,6 +27,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -46,6 +47,7 @@
noinstrument noasan int PrintBacktraceUsingSymbols(int fd, noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
const struct StackFrame *bp, const struct StackFrame *bp,
struct SymbolTable *st) { struct SymbolTable *st) {
bool ok;
size_t gi; size_t gi;
intptr_t addr; intptr_t addr;
int i, symbol, addend; int i, symbol, addend;
@ -55,7 +57,10 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (i = 0, frame = bp; frame; frame = frame->next) { for (i = 0, frame = bp; frame; frame = frame->next) {
if (!IsValidStackFramePointer(frame)) { __mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
kprintf("%p corrupt frame pointer\n", frame); kprintf("%p corrupt frame pointer\n", frame);
break; break;
} }

27
libc/nexgen32e/gettls.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_GETTLS_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_GETTLS_H_
#include "libc/dce.h"
#include "libc/nexgen32e/threaded.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *__get_tls(void) libcesque nosideeffect;
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
static noasan inline char *__get_tls_inline(void) {
char *tib, *lin = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
if (IsWindows()) {
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
}
}
return tib;
}
#endif /* GNU x86-64 */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_GETTLS_H_ */

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ #ifndef COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ #define COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
#include "libc/dce.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -8,25 +7,9 @@ extern int __threaded;
extern bool __tls_enabled; extern bool __tls_enabled;
extern unsigned __tls_index; extern unsigned __tls_index;
char *__get_tls(void) libcesque nosideeffect;
void *__initialize_tls(char[64]); void *__initialize_tls(char[64]);
void __install_tls(char[64]); void __install_tls(char[64]);
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
static noasan inline char *__get_tls_inline(void) {
char *tib, *lin = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
if (IsWindows()) {
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
}
}
return tib;
}
#endif /* GNU x86-64 */
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ */ #endif /* COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ */

View file

@ -31,7 +31,6 @@
sys_clone_linux: sys_clone_linux:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable
push %rbx push %rbx
mov %rcx,%r10 mov %rcx,%r10
mov 16(%rbp),%rbx mov 16(%rbp),%rbx

View file

@ -1,6 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_ #ifndef COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_
#define COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_ #define COSMOPOLITAN_LIBC_RUNTIME_CXAATEXIT_H_
#include "libc/intrin/pthread.h" #include "libc/nexgen32e/threaded.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -17,13 +17,14 @@ struct CxaAtexitBlocks {
} * p, root; } * p, root;
}; };
extern pthread_mutex_t __cxa_lock_obj;
extern struct CxaAtexitBlocks __cxa_blocks; extern struct CxaAtexitBlocks __cxa_blocks;
void __cxa_lock(void);
void __cxa_unlock(void);
void __cxa_printexits(FILE *, void *); void __cxa_printexits(FILE *, void *);
#define __cxa_lock() pthread_mutex_lock(&__cxa_lock_obj) #define __cxa_lock() (__threaded ? __cxa_lock() : 0)
#define __cxa_unlock() pthread_mutex_unlock(&__cxa_lock_obj) #define __cxa_unlock() (__threaded ? __cxa_unlock() : 0)
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -20,7 +20,7 @@
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/cmpxchg.h" #include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchgp.h" #include "libc/intrin/lockcmpxchg.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/stackframe.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
@ -39,12 +39,11 @@
void ftrace_hook(void); void ftrace_hook(void);
_Alignas(64) int ftrace_lock;
static struct Ftrace { static struct Ftrace {
int skew; int skew;
int stackdigs; int stackdigs;
int64_t lastaddr; int64_t lastaddr;
volatile bool busy;
} g_ftrace; } g_ftrace;
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) { static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
@ -65,37 +64,14 @@ static privileged inline int GetNestingLevel(struct StackFrame *frame) {
} }
static privileged inline void ReleaseFtraceLock(void) { static privileged inline void ReleaseFtraceLock(void) {
int zero = 0; g_ftrace.busy = false;
__atomic_store(&ftrace_lock, &zero, __ATOMIC_RELAXED);
} }
static privileged inline bool AcquireFtraceLock(void) { static privileged inline bool AcquireFtraceLock(void) {
int me, owner;
unsigned tries;
if (!__threaded) { if (!__threaded) {
return _cmpxchg(&ftrace_lock, 0, -1); return _cmpxchg(&g_ftrace.busy, false, true);
} else { } else {
for (tries = 0, me = gettid();;) { return _lockcmpxchg(&g_ftrace.busy, false, true);
owner = 0;
if (_lockcmpxchgp(&ftrace_lock, &owner, me)) {
return true;
}
if (owner == -1) {
// avoid things getting weird after first clone() call transition
return false;
}
if (owner == me) {
// we ignore re-entry into ftrace. while the code and build config
// is written to make re-entry highly unlikely, it's impossible to
// guarantee. there's also the possibility of asynchronous signals
return false;
}
if (++tries & 7) {
__builtin_ia32_pause();
} else {
sched_yield();
}
}
} }
} }

View file

@ -3,8 +3,8 @@
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/midpoint.h" #include "libc/bits/midpoint.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/pthread.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/nt/version.h" #include "libc/nt/version.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/sysv/consts/ss.h" #include "libc/sysv/consts/ss.h"
@ -31,9 +31,6 @@ COSMOPOLITAN_C_START_
#define _kMem(NORMAL, WIN7) \ #define _kMem(NORMAL, WIN7) \
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7) (!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
#define __mmi_lock() pthread_mutex_lock(&_mmi.lock)
#define __mmi_unlock() pthread_mutex_unlock(&_mmi.lock)
struct MemoryInterval { struct MemoryInterval {
int x; int x;
int y; int y;
@ -50,11 +47,12 @@ struct MemoryIntervals {
size_t i, n; size_t i, n;
struct MemoryInterval *p; struct MemoryInterval *p;
struct MemoryInterval s[OPEN_MAX]; struct MemoryInterval s[OPEN_MAX];
pthread_mutex_t lock;
}; };
extern hidden struct MemoryIntervals _mmi; extern hidden struct MemoryIntervals _mmi;
void __mmi_lock(void) hidden;
void __mmi_unlock(void) hidden;
bool IsMemtracked(int, int) hidden; bool IsMemtracked(int, int) hidden;
void PrintSystemMappings(int) hidden; void PrintSystemMappings(int) hidden;
const char *DescribeFrame(int) hidden; const char *DescribeFrame(int) hidden;
@ -69,6 +67,9 @@ void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
int UntrackMemoryIntervals(void *, size_t) hidden; int UntrackMemoryIntervals(void *, size_t) hidden;
size_t GetMemtrackSize(struct MemoryIntervals *); size_t GetMemtrackSize(struct MemoryIntervals *);
#define __mmi_lock() (__threaded ? __mmi_lock() : 0)
#define __mmi_unlock() (__threaded ? __mmi_unlock() : 0)
#define IsLegalPointer(p) \ #define IsLegalPointer(p) \
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff) (-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)

View file

@ -11,13 +11,17 @@ struct StdioFlushHandles {
}; };
struct StdioFlush { struct StdioFlush {
pthread_mutex_t lock;
struct StdioFlushHandles handles; struct StdioFlushHandles handles;
FILE *handles_initmem[8]; FILE *handles_initmem[8];
}; };
hidden extern struct StdioFlush __fflush; hidden extern struct StdioFlush __fflush;
void __fflush_lock(void);
void __fflush_unlock(void);
#define __fflush_lock() (__threaded ? __fflush_lock() : 0)
#define __fflush_unlock() (__threaded ? __fflush_unlock() : 0)
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_ */ #endif /* COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_ */

View file

@ -31,6 +31,16 @@
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
static pthread_mutex_t __fflush_lock_obj;
void(__fflush_lock)(void) {
pthread_mutex_lock(&__fflush_lock_obj);
}
void(__fflush_unlock)(void) {
pthread_mutex_unlock(&__fflush_lock_obj);
}
/** /**
* Blocks until data from stream buffer is written out. * Blocks until data from stream buffer is written out.
* *
@ -41,7 +51,7 @@ int fflush_unlocked(FILE *f) {
int rc = 0; int rc = 0;
size_t i; size_t i;
if (!f) { if (!f) {
pthread_mutex_lock(&__fflush.lock); __fflush_lock();
for (i = __fflush.handles.i; i; --i) { for (i = __fflush.handles.i; i; --i) {
if ((f = __fflush.handles.p[i - 1])) { if ((f = __fflush.handles.p[i - 1])) {
if (fflush(f) == -1) { if (fflush(f) == -1) {
@ -49,7 +59,7 @@ int fflush_unlocked(FILE *f) {
} }
} }
} }
pthread_mutex_unlock(&__fflush.lock); __fflush_unlock();
} else if (f->fd != -1) { } else if (f->fd != -1) {
if (__fflush_impl(f) == -1) { if (__fflush_impl(f) == -1) {
rc = -1; rc = -1;
@ -64,7 +74,7 @@ textstartup int __fflush_register(FILE *f) {
int rc; int rc;
size_t i; size_t i;
struct StdioFlush *sf; struct StdioFlush *sf;
pthread_mutex_lock(&__fflush.lock); __fflush_lock();
sf = &__fflush; sf = &__fflush;
if (!sf->handles.p) { if (!sf->handles.p) {
sf->handles.p = sf->handles_initmem; sf->handles.p = sf->handles_initmem;
@ -74,19 +84,19 @@ textstartup int __fflush_register(FILE *f) {
for (i = sf->handles.i; i; --i) { for (i = sf->handles.i; i; --i) {
if (!sf->handles.p[i - 1]) { if (!sf->handles.p[i - 1]) {
sf->handles.p[i - 1] = f; sf->handles.p[i - 1] = f;
pthread_mutex_unlock(&__fflush.lock); __fflush_unlock();
return 0; return 0;
} }
} }
rc = append(&sf->handles, &f); rc = append(&sf->handles, &f);
pthread_mutex_unlock(&__fflush.lock); __fflush_unlock();
return rc; return rc;
} }
void __fflush_unregister(FILE *f) { void __fflush_unregister(FILE *f) {
size_t i; size_t i;
struct StdioFlush *sf; struct StdioFlush *sf;
pthread_mutex_lock(&__fflush.lock); __fflush_lock();
sf = &__fflush; sf = &__fflush;
sf = pushpop(sf); sf = pushpop(sf);
for (i = sf->handles.i; i; --i) { for (i = sf->handles.i; i; --i) {
@ -95,5 +105,5 @@ void __fflush_unregister(FILE *f) {
break; break;
} }
} }
pthread_mutex_unlock(&__fflush.lock); __fflush_unlock();
} }

View file

@ -16,26 +16,25 @@
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/assert.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
/** /**
* Reads UTF-8 content from stream into UTF-32 buffer. * Reads UTF-8 content from stream into UTF-32 buffer.
*
* This function is similar to getline() except it'll truncate lines
* exceeding size. The line ending marker is included and may be removed
* using _chomp().
*
* @param s is is nul-terminated string that's non-null
* @param size is byte length of `s`
* @param f is file stream object pointer
* @see fgetws()
* @threadsafe
*/ */
wchar_t *fgetws_unlocked(wchar_t *s, int size, FILE *f) { wchar_t *fgetws(wchar_t *s, int size, FILE *f) {
wint_t c; wchar_t *rc;
wchar_t *p = s; flockfile(f);
if (size > 0) { rc = fgetws_unlocked(s, size, f);
while (--size > 0) { funlockfile(f);
if ((c = fgetwc_unlocked(f)) == -1) { return rc;
if (ferror_unlocked(f) == EINTR) continue;
break;
}
*p++ = c;
if (c == '\n') break;
}
*p = '\0';
}
return (intptr_t)p > (intptr_t)s ? s : NULL;
} }

View file

@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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/assert.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
* Reads UTF-8 content from stream into UTF-32 buffer.
*
* This function is similar to getline() except it'll truncate lines
* exceeding size. The line ending marker is included and may be removed
* using _chomp().
*
* @param s is is nul-terminated string that's non-null
* @param size is byte length of `s`
* @param f is file stream object pointer
* @see fgetws()
*/
wchar_t *fgetws_unlocked(wchar_t *s, int size, FILE *f) {
wint_t c;
wchar_t *p = s;
if (size > 0) {
while (--size > 0) {
if ((c = fgetwc_unlocked(f)) == -1) {
if (ferror_unlocked(f) == EINTR) continue;
break;
}
*p++ = c;
if (c == '\n') break;
}
*p = '\0';
}
return (intptr_t)p > (intptr_t)s ? s : NULL;
}

View file

@ -21,6 +21,6 @@
/** /**
* Acquires reentrant lock on stdio object, blocking if needed. * Acquires reentrant lock on stdio object, blocking if needed.
*/ */
void flockfile(FILE *f) { void(flockfile)(FILE *f) {
pthread_mutex_lock(&f->lock); pthread_mutex_lock(&f->lock);
} }

View file

@ -29,7 +29,7 @@
void _flushlbf(void) { void _flushlbf(void) {
int i; int i;
FILE *f; FILE *f;
pthread_mutex_lock(&__fflush.lock); __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])) {
flockfile(f); flockfile(f);
@ -39,5 +39,5 @@ void _flushlbf(void) {
funlockfile(f); funlockfile(f);
} }
} }
pthread_mutex_unlock(&__fflush.lock); __fflush_unlock();
} }

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/** /**
* Writes string to stream. * Writes string to stream.
@ -29,11 +28,12 @@
* @param s is a NUL-terminated string that's non-NULL * @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream * @param f is an open stream
* @return bytes written, or -1 w/ errno * @return bytes written, or -1 w/ errno
* @threadsafe
*/ */
int fputs_unlocked(const char *s, FILE *f) { int fputs(const char *s, FILE *f) {
size_t n, r; int rc;
n = strlen(s); flockfile(f);
r = fwrite_unlocked(s, 1, n, f); rc = fputs_unlocked(s, f);
if (!r && n) return -1; funlockfile(f);
return r; return rc;
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,24 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
// Writes string to stream. /**
// * Writes string to stream.
// Writing stops at the NUL-terminator, which isn't included in output. *
// This function blocks until the full string is written, unless an * Writing stops at the NUL-terminator, which isn't included in output.
// unrecoverable error happens. * This function blocks until the full string is written, unless an
// * unrecoverable error happens.
// @param rdi is nul-terminated string that's non-null *
// @param rsi is file object stream pointer * @param s is a NUL-terminated string that's non-NULL
// @return strlen(rdi) on success or -1 w/ errno * @param f is an open stream
// @see fputs_unlocked() * @return bytes written, or -1 w/ errno
// @threadsafe */
fputs: mov %rsi,%r11 int fputs_unlocked(const char *s, FILE *f) {
ezlea fputs_unlocked,ax size_t n, r;
jmp stdio_unlock n = strlen(s);
.endfn fputs,globl r = fwrite_unlocked(s, 1, n, f);
if (!r && n) return -1;
return r;
}

View file

@ -17,24 +17,19 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/tpenc.h"
/** /**
* Writes wide character to stream. * Writes wide character to stream.
* *
* @return wc if written or -1 w/ errno * @param wc has wide character
* @param f is file object stream pointer
* @return wide character if written or -1 w/ errno
* @threadsafe
*/ */
wint_t fputwc_unlocked(wchar_t wc, FILE *f) { wint_t fputwc(wchar_t wc, FILE *f) {
uint64_t w; wint_t rc;
if (wc != -1) { flockfile(f);
w = tpenc(wc); rc = fputwc_unlocked(wc, f);
do { funlockfile(f);
if (fputc_unlocked(w, f) == -1) { return rc;
return -1;
}
} while ((w >>= 8));
return wc;
} else {
return -1;
}
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,18 +16,27 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
#include "libc/str/tpenc.h"
// Writes data to stream. /**
// * Writes wide character to stream.
// @param rdi has pointer to data to write *
// @param rsi stride specifies the size of individual items * @param wc has wide character
// @param rdx count is the number of strides to write * @param f is file object stream pointer
// @param rcx has file object stream pointer * @return wide character if written or -1 w/ errno
// @return count on success, [0,count) on EOF, 0 on error or count==0 */
// @see fwrite_unlocked() wint_t fputwc_unlocked(wchar_t wc, FILE *f) {
// @threadsafe uint64_t w;
fwrite: mov %rcx,%r11 if (wc != -1) {
ezlea fwrite_unlocked,ax w = tpenc(wc);
jmp stdio_unlock do {
.endfn fwrite,globl if (fputc_unlocked(w, f) == -1) {
return -1;
}
} while ((w >>= 8));
return wc;
} else {
return -1;
}
}

View file

@ -16,7 +16,6 @@
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/errno.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
/** /**
@ -29,20 +28,12 @@
* @param s is a NUL-terminated string that's non-NULL * @param s is a NUL-terminated string that's non-NULL
* @param f is an open stream * @param f is an open stream
* @return strlen(s) or -1 w/ errno on error * @return strlen(s) or -1 w/ errno on error
* @threadsafe
*/ */
int fputws_unlocked(const wchar_t *s, FILE *f) { int fputws(const wchar_t *s, FILE *f) {
int res = 0; int rc;
while (*s) { flockfile(f);
if (fputwc_unlocked(*s++, f) == -1) { rc = fputws_unlocked(s, f);
if (ferror_unlocked(f) == EINTR) { funlockfile(f);
continue; return rc;
}
if (feof_unlocked(f)) {
errno = f->state = EPIPE;
}
return -1;
}
++res;
}
return ++res;
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,33 @@
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/macros.internal.h" #include "libc/errno.h"
#include "libc/stdio/stdio.h"
// Writes wide character string to stream. /**
// * Writes wide character string to stream.
// Writing stops at the NUL-terminator, which isn't included in output. *
// This function blocks until the full string is written, unless an * Writing stops at the NUL-terminator, which isn't included in output.
// unrecoverable error happens. * This function blocks until the full string is written, unless an
// * unrecoverable error happens.
// @param rdi is nul-terminated string that's non-null *
// @param rsi is file object stream pointer * @param s is a NUL-terminated string that's non-NULL
// @return strlen(rdi) on success or -1 w/ errno * @param f is an open stream
// @see fputws_unlocked() * @return strlen(s) or -1 w/ errno on error
// @threadsafe */
fputws: mov %rsi,%r11 int fputws_unlocked(const wchar_t *s, FILE *f) {
ezlea fputws_unlocked,ax int res = 0;
jmp stdio_unlock while (*s) {
.endfn fputws,globl if (fputwc_unlocked(*s++, f) == -1) {
if (ferror_unlocked(f) == EINTR) {
continue;
}
if (feof_unlocked(f)) {
errno = f->state = EPIPE;
}
return -1;
}
++res;
}
return ++res;
}

View file

@ -16,19 +16,7 @@
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/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/** /**
* Reads data from stream. * Reads data from stream.
@ -36,64 +24,12 @@
* @param stride specifies the size of individual items * @param stride specifies the size of individual items
* @param count is the number of strides to fetch * @param count is the number of strides to fetch
* @return count on success, [0,count) on eof, or 0 on error or count==0 * @return count on success, [0,count) on eof, or 0 on error or count==0
* @threadsafe
*/ */
size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) { size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
char *p; size_t rc;
ssize_t rc; flockfile(f);
size_t n, m; rc = fread_unlocked(buf, stride, count, f);
struct iovec iov[2]; funlockfile(f);
if ((f->iomode & O_ACCMODE) == O_WRONLY) { return rc;
f->state = errno = EBADF;
return 0;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return 0;
}
p = buf;
n = stride * count;
m = f->end - f->beg;
if (MIN(n, m)) memcpy(p, f->buf + f->beg, MIN(n, m));
if (n < m) {
f->beg += n;
return count;
}
if (n == m) {
f->beg = f->end = 0;
return count;
}
if (f->fd == -1) {
f->beg = 0;
f->end = 0;
f->state = -1;
return m / stride;
}
iov[0].iov_base = p + m;
iov[0].iov_len = n - m;
if (f->bufmode != _IONBF && n < f->size) {
iov[1].iov_base = f->buf;
if (f->size > PUSHBACK) {
iov[1].iov_len = f->size - PUSHBACK;
} else {
iov[1].iov_len = f->size;
}
} else {
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
}
if ((rc = readv(f->fd, iov, 2)) == -1) {
f->state = errno;
return 0;
}
n = rc;
f->beg = 0;
f->end = 0;
if (n > iov[0].iov_len) {
f->end += n - iov[0].iov_len;
return count;
} else {
n = (m + n) / stride;
if (n < count) f->state = -1;
return n;
}
} }

104
libc/stdio/fread_unlocked.c Normal file
View file

@ -0,0 +1,104 @@
/*-*- 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/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Reads data from stream.
*
* @param stride specifies the size of individual items
* @param count is the number of strides to fetch
* @return count on success, [0,count) on eof, or 0 on error or count==0
*/
size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
char *p;
ssize_t rc;
size_t n, m;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
f->state = errno = EBADF;
return 0;
}
if (f->beg > f->end) {
f->state = errno = EINVAL;
return 0;
}
if (__builtin_mul_overflow(stride, count, &n)) {
f->state = errno = EOVERFLOW;
return 0;
}
p = buf;
m = f->end - f->beg;
if (MIN(n, m)) {
memcpy(p, f->buf + f->beg, MIN(n, m));
}
if (n < m) {
f->beg += n;
return count;
}
if (n == m) {
f->beg = f->end = 0;
return count;
}
if (f->fd == -1) {
f->beg = 0;
f->end = 0;
f->state = -1;
return m / stride;
}
iov[0].iov_base = p + m;
iov[0].iov_len = n - m;
if (f->bufmode != _IONBF && n < f->size) {
iov[1].iov_base = f->buf;
if (f->size > PUSHBACK) {
iov[1].iov_len = f->size - PUSHBACK;
} else {
iov[1].iov_len = f->size;
}
} else {
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
}
if ((rc = readv(f->fd, iov, 2)) == -1) {
f->state = errno;
return 0;
}
n = rc;
f->beg = 0;
f->end = 0;
if (n > iov[0].iov_len) {
f->end += n - iov[0].iov_len;
return count;
} else {
n = (m + n) / stride;
if (n < count) f->state = -1;
return n;
}
}

View file

@ -16,11 +16,7 @@
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/errno.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/** /**
* Repositions open file stream. * Repositions open file stream.
@ -34,46 +30,12 @@
* @param offset is the byte delta * @param offset is the byte delta
* @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
* @threadsafe
*/ */
int fseeko_unlocked(FILE *f, int64_t offset, int whence) { int fseeko(FILE *f, int64_t offset, int whence) {
int res; int rc;
ssize_t rc; flockfile(f);
int64_t pos; rc = fseeko_unlocked(f, offset, whence);
if (f->fd != -1) { funlockfile(f);
if (__fflush_impl(f) == -1) return -1; return rc;
if (whence == SEEK_CUR && f->beg < f->end) {
offset -= f->end - f->beg;
}
if (lseek(f->fd, offset, whence) != -1) {
f->beg = 0;
f->end = 0;
res = 0;
} else {
f->state = errno == ESPIPE ? EBADF : errno;
res = -1;
}
} else {
switch (whence) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = f->beg + offset;
break;
case SEEK_END:
pos = f->end + offset;
break;
default:
pos = -1;
break;
}
if (0 <= pos && pos <= f->end) {
f->beg = pos;
res = 0;
} else {
f->state = errno = EINVAL;
res = -1;
}
}
return res;
} }

View file

@ -0,0 +1,79 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 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/errno.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.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 f is a non-null stream handle
* @param offset is the byte delta
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
* @returns 0 on success or -1 on error
*/
int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
int res;
ssize_t rc;
int64_t pos;
if (f->fd != -1) {
if (__fflush_impl(f) == -1) return -1;
if (whence == SEEK_CUR && f->beg < f->end) {
offset -= f->end - f->beg;
}
if (lseek(f->fd, offset, whence) != -1) {
f->beg = 0;
f->end = 0;
res = 0;
} else {
f->state = errno == ESPIPE ? EBADF : errno;
res = -1;
}
} else {
switch (whence) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = f->beg + offset;
break;
case SEEK_END:
pos = f->end + offset;
break;
default:
pos = -1;
break;
}
if (0 <= pos && pos <= f->end) {
f->beg = pos;
res = 0;
} else {
f->state = errno = EINVAL;
res = -1;
}
}
return res;
}

View file

@ -23,7 +23,7 @@
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
static int64_t ftello_unlocked(FILE *f) { static inline int64_t ftello_unlocked(FILE *f) {
int64_t pos; int64_t pos;
uint32_t skew; uint32_t skew;
if (f->fd != -1) { if (f->fd != -1) {
@ -45,6 +45,7 @@ static int64_t ftello_unlocked(FILE *f) {
* *
* @param stream is a non-null stream handle * @param stream is a non-null stream handle
* @returns current byte offset from beginning, or -1 w/ errno * @returns current byte offset from beginning, or -1 w/ errno
* @threadsafe
*/ */
int64_t ftello(FILE *f) { int64_t ftello(FILE *f) {
int64_t rc; int64_t rc;

View file

@ -23,6 +23,6 @@
* *
* @return 0 on success, or non-zero if another thread owns the lock * @return 0 on success, or non-zero if another thread owns the lock
*/ */
int ftrylockfile(FILE *f) { int(ftrylockfile)(FILE *f) {
return pthread_mutex_trylock(&f->lock); return pthread_mutex_trylock(&f->lock);
} }

View file

@ -21,6 +21,6 @@
/** /**
* Releases lock on stdio object. * Releases lock on stdio object.
*/ */
void funlockfile(FILE *f) { void(funlockfile)(FILE *f) {
pthread_mutex_unlock(&f->lock); pthread_mutex_unlock(&f->lock);
} }

View file

@ -16,18 +16,7 @@
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/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
/** /**
* Writes data to stream. * Writes data to stream.
@ -35,54 +24,12 @@
* @param stride specifies the size of individual items * @param stride specifies the size of individual items
* @param count is the number of strides to write * @param count is the number of strides to write
* @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
* @threadsafe
*/ */
size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) { size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
ldiv_t d; size_t rc;
ssize_t rc; flockfile(f);
size_t n, m; rc = fwrite_unlocked(data, stride, count, f);
const char *p; funlockfile(f);
struct iovec iov[2]; return rc;
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
f->state = errno = EBADF;
return 0;
}
n = stride * count;
m = f->size - f->beg;
if (n <= m && f->bufmode != _IONBF) {
memcpy(f->buf + f->beg, data, n);
f->beg += n;
if (f->fd != -1 && f->bufmode == _IOLBF &&
(p = memrchr(f->buf, '\n', f->beg))) {
n = p + 1 - f->buf;
if ((rc = write(f->fd, f->buf, n)) == -1) {
if (errno == EINTR || errno == EAGAIN) return count;
f->state = errno;
return 0;
}
n = rc;
memmove(f->buf, f->buf + n, f->beg - n);
f->beg -= n;
}
return count;
}
if (f->fd == -1) {
n = MIN(n, m);
d = ldiv(n, stride);
n -= d.rem;
memcpy(f->buf + f->beg, data, n);
f->beg += n;
f->state = -1;
return d.quot;
}
iov[0].iov_base = f->buf;
iov[0].iov_len = f->beg;
iov[1].iov_base = data;
iov[1].iov_len = n;
n += f->beg;
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
f->state = errno;
return 0;
}
f->beg = 0;
return count;
} }

View file

@ -0,0 +1,113 @@
/*-*- 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/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
/**
* Writes data to stream.
*
* @param stride specifies the size of individual items
* @param count is the number of strides to write
* @return count on success, [0,count) on EOF, 0 on error or count==0
*/
size_t fwrite_unlocked(const void *data, size_t stride, size_t count, FILE *f) {
ldiv_t d;
ssize_t rc;
size_t n, m;
const char *p;
struct iovec iov[2];
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
f->state = errno = EBADF;
return 0;
}
if (__builtin_mul_overflow(stride, count, &n)) {
f->state = errno = EOVERFLOW;
return 0;
}
m = f->size - f->beg;
if (n <= m && f->bufmode != _IONBF) {
// this isn't a fully buffered stream, and
// there's enough room in the buffer for the request
memcpy(f->buf + f->beg, data, n);
f->beg += n;
if (f->fd != -1 && f->bufmode == _IOLBF &&
(p = memrchr(f->buf, '\n', f->beg))) {
// write out as many lines as possible
n = p + 1 - f->buf;
if ((rc = write(f->fd, f->buf, n)) == -1) {
// the write() system call failed
if (errno == EINTR || errno == EAGAIN) {
return count;
} else {
f->state = errno;
return 0;
}
}
// copy backwards last line fragment or uncompleted data
n = rc;
if (f->beg - n) {
memmove(f->buf, f->buf + n, f->beg - n);
}
f->beg -= n;
}
return count;
}
// what's happening is either
// (1) a fully buffered stream, or
// (2) no room in buffer to hold full request
if (f->fd == -1) {
// this is an in-memory stream
// store as much of request as we can hold
n = MIN(n, m);
d = ldiv(n, stride);
n -= d.rem;
if (n) {
memcpy(f->buf + f->beg, data, n);
f->beg += n;
}
// trigger eof condition
f->state = EOF;
return d.quot;
}
// perform a fragmented write
// (1) we avoid needless copies in fully buffered mode
// (2) we avoid need for malloc() when it's out of room
iov[0].iov_base = f->buf;
iov[0].iov_len = f->beg;
iov[1].iov_base = data;
iov[1].iov_len = n;
n += f->beg;
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
f->state = errno;
return 0;
}
f->beg = 0;
return count;
}

View file

@ -21,7 +21,8 @@
/** /**
* Reads byte from stream. * Reads byte from stream.
* @return byte in range 0..255, or -1 w/ errno * @return byte in range 0..255, or -1 w/ errno
* @threadsafe
*/ */
int(getc_unlocked)(FILE *f) { int(getc)(FILE *f) {
return fgetc_unlocked(f); return getc(f);
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,12 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
// Reads character from stdin. /**
// * Reads byte from stream.
// @return byte in range 0..255, or -1 w/ errno * @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked() */
// @threadsafe int(getc_unlocked)(FILE *f) {
getchar: return fgetc_unlocked(f);
mov stdin(%rip),%rdi }
mov %rdi,%r11
ezlea fgetc_unlocked,ax
jmp stdio_unlock
.endfn getchar,globl

View file

@ -21,7 +21,8 @@
/** /**
* Reads byte from stdin. * Reads byte from stdin.
* @return byte in range 0..255, or -1 w/ errno * @return byte in range 0..255, or -1 w/ errno
* @htreadsafe
*/ */
int getchar_unlocked(void) { int getchar(void) {
return fgetc_unlocked(stdin); return fgetc(stdin);
} }

View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 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"
/**
* Reads byte from stdin.
* @return byte in range 0..255, or -1 w/ errno
*/
int getchar_unlocked(void) {
return fgetc_unlocked(stdin);
}

View file

@ -21,7 +21,8 @@
/** /**
* Reads UTF-8 character from stream. * Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error * @return wide character or -1 on EOF or error
* @threadsafe
*/ */
wint_t(getwc_unlocked)(FILE *f) { wint_t(getwc)(FILE *f) {
return fgetwc_unlocked(f); return fgetwc(f);
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,12 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
// Reads UTF-8 character from stdin. /**
// * Reads UTF-8 character from stream.
// @return wide character or -1 on EOF or error * @return wide character or -1 on EOF or error
// @see fgetwc_unlocked() */
// @threadsafe wint_t(getwc_unlocked)(FILE *f) {
getwchar: return fgetwc_unlocked(f);
mov stdin(%rip),%rdi }
mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getwchar,globl

View file

@ -21,7 +21,8 @@
/** /**
* Reads UTF-8 character from stream. * Reads UTF-8 character from stream.
* @return wide character or -1 on EOF or error * @return wide character or -1 on EOF or error
* @threadsafe
*/ */
wint_t getwchar_unlocked(void) { wint_t getwchar(void) {
return fgetwc_unlocked(stdin); return fgetwc(stdin);
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,15 +16,12 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
// Reads character from stream. /**
// * Reads UTF-8 character from stream.
// @param rdi has file stream object pointer * @return wide character or -1 on EOF or error
// @return byte in range 0..255, or -1 w/ errno */
// @see fgetc_unlocked() wint_t getwchar_unlocked(void) {
// @threadsafe return fgetwc_unlocked(stdin);
getc: mov %rdi,%r11 }
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getc,globl

View file

@ -23,7 +23,8 @@
* *
* @param c is byte to buffer or write, which is masked * @param c is byte to buffer or write, which is masked
* @return c as unsigned char if written or -1 w/ errno * @return c as unsigned char if written or -1 w/ errno
* @threadsafe
*/ */
int(putc_unlocked)(int c, FILE *f) { int(putc)(int c, FILE *f) {
return fputc_unlocked(c, f); return fputc(c, f);
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,15 +16,14 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
// Reads UTF-8 character from stream. /**
// * Writes byte to stream.
// @param rdi has file stream object pointer *
// @return wide character or -1 on EOF or error * @param c is byte to buffer or write, which is masked
// @see fgetwc_unlocked() * @return c as unsigned char if written or -1 w/ errno
// @threadsafe */
getwc: mov %rdi,%r11 int(putc_unlocked)(int c, FILE *f) {
ezlea fgetwc_unlocked,ax return fputc_unlocked(c, f);
jmp stdio_unlock }
.endfn getwc,globl

View file

@ -22,7 +22,8 @@
* Writes byte to stdout. * Writes byte to stdout.
* *
* @return c (as unsigned char) if written or -1 w/ errno * @return c (as unsigned char) if written or -1 w/ errno
* @threadsafe
*/ */
int putchar_unlocked(int c) { int putchar(int c) {
return fputc_unlocked(c, stdout); return fputc(c, stdout);
} }

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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"
/**
* Writes byte to stdout.
*
* @return c (as unsigned char) if written or -1 w/ errno
*/
int putchar_unlocked(int c) {
return fputc_unlocked(c, stdout);
}

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
static int PutsImpl(const char *s, FILE *f) { static inline int PutsImpl(const char *s, FILE *f) {
size_t n, r; size_t n, r;
if ((n = strlen(s))) { if ((n = strlen(s))) {
r = fwrite_unlocked(s, 1, n, f); r = fwrite_unlocked(s, 1, n, f);

View file

@ -22,7 +22,8 @@
* Writes wide character to stream. * Writes wide character to stream.
* *
* @return wc if written or -1 w/ errno * @return wc if written or -1 w/ errno
* @threadsafe
*/ */
wint_t(putwc_unlocked)(wchar_t wc, FILE *f) { wint_t(putwc)(wchar_t wc, FILE *f) {
return fputwc_unlocked(wc, f); return fputwc(wc, f);
} }

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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"
/**
* Writes wide character to stream.
*
* @return wc if written or -1 w/ errno
*/
wint_t(putwc_unlocked)(wchar_t wc, FILE *f) {
return fputwc_unlocked(wc, f);
}

View file

@ -21,7 +21,8 @@
/** /**
* Writes wide character to stdout. * Writes wide character to stdout.
* @return wc if written or -1 w/ errno * @return wc if written or -1 w/ errno
* @threadsafe
*/ */
wint_t putwchar_unlocked(wchar_t wc) { wint_t putwchar(wchar_t wc) {
return fputwc_unlocked(wc, stdout); return fputwc(wc, stdout);
} }

View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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"
/**
* Writes wide character to stdout.
* @return wc if written or -1 w/ errno
*/
wint_t putwchar_unlocked(wchar_t wc) {
return fputwc_unlocked(wc, stdout);
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_ #define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
#include "libc/fmt/pflink.h" #include "libc/fmt/pflink.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/symbolic.h" #include "libc/runtime/symbolic.h"
#define FILENAME_MAX PATH_MAX #define FILENAME_MAX PATH_MAX
@ -157,20 +158,24 @@ int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
int vfprintf_unlocked(FILE *, const char *, va_list) int vfprintf_unlocked(FILE *, const char *, va_list)
paramsnonnull() dontthrow nocallback; 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 cosmopolitan § standard i/o » optimizations
*/ */
#define flockfile(f) (__threaded ? flockfile(f) : 0)
#define funlockfile(f) (__threaded ? funlockfile(f) : 0)
#define ftrylockfile(f) (__threaded ? ftrylockfile(f) : 0)
#define getc(f) fgetc(f) #define getc(f) fgetc(f)
#define getwc(f) fgetwc(f) #define getwc(f) fgetwc(f)
#define putc(c, f) fputc(c, f) #define putc(c, f) fputc(c, f)
#define putwc(c, f) fputwc(c, f) #define putwc(c, f) fputwc(c, f)
#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)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* clang-format off */ /* clang-format off */
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__) #define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)

View file

@ -17,20 +17,15 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/** /**
* Pushes byte back to stream. * Pushes byte back to stream.
* @threadsafe
*/ */
int ungetc_unlocked(int c, FILE *f) { int ungetc(int c, FILE *f) {
if (c == -1) return -1; int rc;
if (f->beg) { flockfile(f);
f->buf[--f->beg] = c; rc = ungetc_unlocked(c, f);
} else if (f->end < f->size) { funlockfile(f);
memmove(f->buf + 1, f->buf, f->end++); return rc;
f->buf[0] = c;
} else {
return -1;
}
return c & 255;
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,16 +16,21 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
// Writes wide character to stream. /**
// * Pushes byte back to stream.
// @param rdi has wide character */
// @param rsi has file object stream pointer int ungetc_unlocked(int c, FILE *f) {
// @return rax is wide character if written or -1 w/ errno if (c == -1) return -1;
// @see fputwc_unlocked() if (f->beg) {
// @threadsafe f->buf[--f->beg] = c;
fputwc: mov %rsi,%r11 } else if (f->end < f->size) {
ezlea fputwc_unlocked,ax memmove(f->buf + 1, f->buf, f->end++);
jmp stdio_unlock f->buf[0] = c;
.endfn fputwc,globl } else {
return -1;
}
return c & 255;
}

View file

@ -17,31 +17,15 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
/** /**
* Pushes wide character back to stream. * Pushes wide character back to stream.
* @threadsafe
*/ */
wint_t ungetwc_unlocked(wint_t c, FILE *f) { wint_t ungetwc(wint_t c, FILE *f) {
char b[6]; wint_t rc;
unsigned n; flockfile(f);
uint64_t w; rc = ungetwc_unlocked(c, f);
if (c == -1) return -1; funlockfile(f);
n = 0; return rc;
w = tpenc(c);
do {
b[n++] = w;
} while ((w >>= 8));
if (f->beg >= n) {
f->beg -= n;
memcpy(f->buf + f->beg, b, n);
} else if (f->beg + f->end + n <= f->size) {
memmove(f->buf + f->beg + n, f->buf + f->beg, f->end - f->beg);
memcpy(f->buf + f->beg, b, n);
f->end += n;
} else {
return -1;
}
return c;
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,20 +16,32 @@
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/macros.internal.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
// Reads UTF-8 content from stream into UTF-32 buffer. /**
// * Pushes wide character back to stream.
// This function is similar to getline() except it'll truncate lines */
// exceeding size. The line ending marker is included and may be removed wint_t ungetwc_unlocked(wint_t c, FILE *f) {
// using _chomp(). char b[6];
// unsigned n;
// @param rdi is nul-terminated string that's non-null uint64_t w;
// @param rsi is size of rdi buffer if (c == -1) return -1;
// @param rsi is file stream object pointer n = 0;
// @see fgetws_unlocked() w = tpenc(c);
// @threadsafe do {
fgetws: mov %rdx,%r11 b[n++] = w;
ezlea fgetws_unlocked,ax } while ((w >>= 8));
jmp stdio_unlock if (f->beg >= n) {
.endfn fgetws,globl f->beg -= n;
memcpy(f->buf + f->beg, b, n);
} else if (f->beg + f->end + n <= f->size) {
memmove(f->buf + f->beg + n, f->buf + f->beg, f->end - f->beg);
memcpy(f->buf + f->beg, b, n);
f->end += n;
} else {
return -1;
}
return c;
}

View file

@ -1,33 +0,0 @@
/*-*- 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"
// Reads data from stream.
//
// @param rdi has pointer to data to read
// @param rsi stride specifies the size of individual items
// @param rdx count is the number of strides to read
// @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
.endfn fread,globl

View file

@ -1,37 +0,0 @@
/*-*- 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

@ -1,31 +0,0 @@
/*-*- 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"
// Writes character to stream.
//
// @param rdi c is byte to buffer or write, which is masked
// @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
.endfn putc,globl

View file

@ -1,32 +0,0 @@
/*-*- 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"
// Writes character to stdout.
//
// @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
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn putchar,globl

View file

@ -1,31 +0,0 @@
/*-*- 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"
// Writes wide character to stream.
//
// @param rdi has wide character
// @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
.endfn putwc,globl

View file

@ -1,32 +0,0 @@
/*-*- 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"
// Writes wide character to stdout.
//
// @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
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn putwchar,globl

View file

@ -1,72 +0,0 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Wrapper for applying locking to stdio functions.
//
// This function is intended to be called by thunks.
//
// @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 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 %rax
push %rdi
push %rsi
push %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 %r11
push %rsi # align stack
call *%rax
pop %rsi
pop %r11
// releases mutex
push %rax
push %rdx
mov %r11,%rdi
call funlockfile
pop %rdx
pop %rax
pop %rbp
ret
.endfn stdio_unlock,globl

View file

@ -1,31 +0,0 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @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
.endfn ungetc,globl

View file

@ -1,32 +0,0 @@
/*-*- 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 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @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
jmp stdio_unlock
.endfn ungetwc,globl

View file

@ -69,8 +69,10 @@ noasan static inline const unsigned char *memchr_sse(const unsigned char *s,
*/ */
void *memchr(const void *s, int c, size_t n) { void *memchr(const void *s, int c, size_t n) {
const void *r; const void *r;
if (X86_HAVE(SSE)) { if (!IsTiny() && X86_HAVE(SSE)) {
if (IsAsan()) __asan_verify(s, n); if (IsAsan()) {
__asan_verify(s, n);
}
r = memchr_sse(s, c, n); r = memchr_sse(s, c, n);
} else { } else {
r = memchr_pure(s, c, n); r = memchr_pure(s, c, n);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nexgen32e/gettls.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
/** /**

View file

@ -16,7 +16,7 @@
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/nexgen32e/threaded.h" #include "libc/nexgen32e/gettls.h"
/** /**
* Returns address of thread information block. * Returns address of thread information block.

View file

@ -16,6 +16,7 @@
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/nexgen32e/gettls.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"

View file

@ -7,6 +7,7 @@
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/gc.h" #include "libc/runtime/gc.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
@ -45,15 +46,18 @@ STATIC_YOINK("usr/share/zoneinfo/UTC");
static pthread_mutex_t locallock; static pthread_mutex_t locallock;
static int lock(void) { static int localtime_lock(void) {
pthread_mutex_lock(&locallock); pthread_mutex_lock(&locallock);
return 0; return 0;
} }
static void unlock(void) { static void localtime_unlock(void) {
pthread_mutex_unlock(&locallock); pthread_mutex_unlock(&locallock);
} }
#define localtime_lock() (__threaded ? localtime_lock() : 0)
#define localtime_unlock() (__threaded ? localtime_unlock() : 0)
#ifndef TZ_ABBR_MAX_LEN #ifndef TZ_ABBR_MAX_LEN
#define TZ_ABBR_MAX_LEN 16 #define TZ_ABBR_MAX_LEN 16
#endif /* !defined TZ_ABBR_MAX_LEN */ #endif /* !defined TZ_ABBR_MAX_LEN */
@ -1407,10 +1411,10 @@ localtime_tzset_unlocked(void)
void void
tzset(void) tzset(void)
{ {
if (lock() != 0) if (localtime_lock() != 0)
return; return;
localtime_tzset_unlocked(); localtime_tzset_unlocked();
unlock(); localtime_unlock();
} }
static void static void
@ -1422,7 +1426,7 @@ static void
localtime_gmtcheck(void) localtime_gmtcheck(void)
{ {
static bool gmt_is_set; static bool gmt_is_set;
if (lock() != 0) if (localtime_lock() != 0)
return; return;
if (! gmt_is_set) { if (! gmt_is_set) {
gmtptr = malloc(sizeof *gmtptr); gmtptr = malloc(sizeof *gmtptr);
@ -1431,7 +1435,7 @@ localtime_gmtcheck(void)
gmtload(gmtptr); gmtload(gmtptr);
gmt_is_set = true; gmt_is_set = true;
} }
unlock(); localtime_unlock();
} }
/* /*
@ -1535,7 +1539,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
static struct tm * static struct tm *
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
{ {
int err = lock(); int err = localtime_lock();
if (err) { if (err) {
errno = err; errno = err;
return NULL; return NULL;
@ -1543,7 +1547,7 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
if (setname || !lcl_is_set) if (setname || !lcl_is_set)
localtime_tzset_unlocked(); localtime_tzset_unlocked();
tmp = localsub(lclptr, timep, setname, tmp); tmp = localsub(lclptr, timep, setname, tmp);
unlock(); localtime_unlock();
return tmp; return tmp;
} }
@ -2150,14 +2154,14 @@ time_t
mktime(struct tm *tmp) mktime(struct tm *tmp)
{ {
time_t t; time_t t;
int err = lock(); int err = localtime_lock();
if (err) { if (err) {
errno = err; errno = err;
return -1; return -1;
} }
localtime_tzset_unlocked(); localtime_tzset_unlocked();
t = mktime_tzname(lclptr, tmp, true); t = mktime_tzname(lclptr, tmp, true);
unlock(); localtime_unlock();
return t; return t;
} }

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nexgen32e/gettls.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"

View file

@ -23,6 +23,7 @@
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/gettls.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"

View file

@ -101,7 +101,7 @@ static dontinline int spin_acquire_lock(int *sl) {
#define MLOCK_T int #define MLOCK_T int
#define TRY_LOCK(sl) !CAS_LOCK(sl) #define TRY_LOCK(sl) !CAS_LOCK(sl)
#define RELEASE_LOCK(sl) if (__threaded) CLEAR_LOCK(sl) #define RELEASE_LOCK(sl) (__threaded && (CLEAR_LOCK(sl), 0))
#define ACQUIRE_LOCK(sl) (__threaded && CAS_LOCK(sl) ? spin_acquire_lock(sl) : 0) #define ACQUIRE_LOCK(sl) (__threaded && CAS_LOCK(sl) ? spin_acquire_lock(sl) : 0)
#define INITIAL_LOCK(sl) (*sl = 0) #define INITIAL_LOCK(sl) (*sl = 0)
#define DESTROY_LOCK(sl) (0) #define DESTROY_LOCK(sl) (0)

View file

@ -131,7 +131,7 @@ struct state {
* buffer, using shift right, and new bytes are appended to the top of the * buffer, using shift right, and new bytes are appended to the top of the
* bit buffer, using shift left. * bit buffer, using shift left.
*/ */
static int bits(struct state *s, int need) { static noinstrument int bits(struct state *s, int need) {
long val; /* bit accumulator (can use up to 20 bits) */ long val; /* bit accumulator (can use up to 20 bits) */
/* load at least need bits into val */ /* load at least need bits into val */