mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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:
parent
4ddfc47d6e
commit
8cdec62f5b
87 changed files with 955 additions and 899 deletions
|
@ -1607,6 +1607,9 @@ ape_pad_text:
|
|||
.type ape_pad_privileged,@object
|
||||
.hidden ape_pad_privileged
|
||||
ape_pad_privileged:
|
||||
#if !IsTiny()
|
||||
.align 4096
|
||||
#endif
|
||||
.previous
|
||||
|
||||
.section .ape.pad.rodata,"a",@progbits
|
||||
|
|
Binary file not shown.
|
@ -37,7 +37,8 @@ EXAMPLES_COMS = \
|
|||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
$(EXAMPLES_COMS:%=%.dbg) \
|
||||
o/$(MODE)/examples/life-nomod.com
|
||||
o/$(MODE)/examples/life-nomod.com \
|
||||
o/$(MODE)/examples/life-classic.com
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
|
|
|
@ -61,7 +61,6 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
size_t i;
|
||||
uint32_t dwExitCode;
|
||||
char progbuf[PATH_MAX];
|
||||
struct MemoryIntervals *mm;
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtProcessInformation procinfo;
|
||||
|
||||
|
|
|
@ -16,8 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
|
||||
unsigned __sighandrvas[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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef 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)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -8,14 +8,17 @@ hidden extern int __vforked;
|
|||
hidden extern bool __time_critical;
|
||||
hidden extern unsigned __sighandrvas[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;
|
||||
|
||||
#define __fds_lock() pthread_mutex_lock(&__fds_lock_obj)
|
||||
#define __fds_unlock() pthread_mutex_unlock(&__fds_lock_obj)
|
||||
#define __sig_lock() pthread_mutex_lock(&__sig_lock_obj)
|
||||
#define __sig_unlock() pthread_mutex_unlock(&__sig_lock_obj)
|
||||
void __fds_lock(void);
|
||||
void __fds_unlock(void);
|
||||
void __sig_lock(void);
|
||||
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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -858,25 +858,25 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
|
|||
void *__asan_morgue_add(void *p) {
|
||||
int i;
|
||||
void *r;
|
||||
pthread_mutex_lock(&__asan_lock);
|
||||
if (__threaded) pthread_mutex_lock(&__asan_lock);
|
||||
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
|
||||
r = __asan_morgue.p[i];
|
||||
__asan_morgue.p[i] = p;
|
||||
pthread_mutex_unlock(&__asan_lock);
|
||||
if (__threaded) pthread_mutex_unlock(&__asan_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __asan_morgue_flush(void) {
|
||||
int i;
|
||||
void *p;
|
||||
pthread_mutex_lock(&__asan_lock);
|
||||
if (__threaded) pthread_mutex_lock(&__asan_lock);
|
||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||
if (__asan_morgue.p[i] && weaken(dlfree)) {
|
||||
weaken(dlfree)(__asan_morgue.p[i]);
|
||||
}
|
||||
__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) {
|
||||
|
|
|
@ -16,6 +16,15 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.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);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,15 @@
|
|||
STATIC_YOINK("_init_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) {
|
||||
struct Fds *fds;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
|
|
@ -72,6 +72,21 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
|
|||
-fno-sanitize=all \
|
||||
-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/exit.greg.o \
|
||||
o/$(MODE)/libc/intrin/exit1.greg.o \
|
||||
|
|
|
@ -16,8 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
STATIC_YOINK("_init__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);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -23,9 +24,9 @@ typedef unsigned long *pthread_t;
|
|||
typedef int pthread_once_t;
|
||||
|
||||
typedef struct {
|
||||
_Atomic(int) owner;
|
||||
_Atomic(int) waits;
|
||||
int reent;
|
||||
int owner;
|
||||
int waits;
|
||||
} pthread_mutex_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/atomic.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/nexgen32e/threaded.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
|
@ -26,25 +27,24 @@
|
|||
/**
|
||||
* Acquires mutex.
|
||||
*/
|
||||
noasan noubsan int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int me, owner;
|
||||
unsigned tries;
|
||||
if (__threaded) {
|
||||
for (tries = 0, me = gettid();;) {
|
||||
owner = 0;
|
||||
if (_lockcmpxchgp(&mutex->owner, &owner, me) || owner == me) {
|
||||
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);
|
||||
for (tries = 0, me = gettid();;) {
|
||||
owner = 0;
|
||||
if (atomic_compare_exchange_weak(&mutex->owner, &owner, me) ||
|
||||
owner == me) {
|
||||
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);
|
||||
}
|
||||
++mutex->reent;
|
||||
return 0;
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/lockcmpxchgp.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
|
||||
|
@ -26,18 +26,15 @@
|
|||
* Tries to acquire mutex.
|
||||
*/
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
|
||||
int rc, me, owner = 0;
|
||||
if (__threaded) {
|
||||
me = gettid();
|
||||
if (!_lockcmpxchgp(&mutex->owner, &owner, me) && owner == me) {
|
||||
rc = 0;
|
||||
++mutex->reent;
|
||||
} else {
|
||||
rc = EBUSY;
|
||||
}
|
||||
} else {
|
||||
int rc, me, owner;
|
||||
me = gettid();
|
||||
owner = 0;
|
||||
if (!atomic_compare_exchange_strong(&mutex->owner, &owner, me) &&
|
||||
owner == me) {
|
||||
rc = 0;
|
||||
++mutex->reent;
|
||||
} else {
|
||||
rc = EBUSY;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
|
@ -27,19 +28,17 @@
|
|||
/**
|
||||
* Releases mutex.
|
||||
*/
|
||||
noasan noubsan int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
int owner;
|
||||
bool shouldunlock;
|
||||
assert(mutex->reent > 0);
|
||||
shouldunlock = --mutex->reent <= 0;
|
||||
if (__threaded) {
|
||||
assert(mutex->owner == gettid());
|
||||
if (shouldunlock) {
|
||||
atomic_store_explicit(&mutex->owner, 0, memory_order_relaxed);
|
||||
if (IsLinux() &&
|
||||
atomic_load_explicit(&mutex->waits, memory_order_acquire)) {
|
||||
futex((void *)&mutex->owner, FUTEX_WAKE, 1, 0, 0);
|
||||
}
|
||||
assert(mutex->owner == gettid());
|
||||
if (shouldunlock) {
|
||||
atomic_store_explicit(&mutex->owner, 0, memory_order_relaxed);
|
||||
if (IsLinux() &&
|
||||
atomic_load_explicit(&mutex->waits, memory_order_acquire)) {
|
||||
futex((void *)&mutex->owner, FUTEX_WAKE, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline pureconst bool IsValidStackFramePointer(struct StackFrame *x) {
|
||||
/* assumes __mmi_lock() is held */
|
||||
return IsLegalPointer(x) && !((uintptr_t)x & 15) &&
|
||||
(IsStaticStackFrame((uintptr_t)x >> 16) ||
|
||||
IsSigAltStackFrame((uintptr_t)x >> 16) ||
|
||||
|
|
|
@ -53,6 +53,7 @@ static void ShowHint(const char *s) {
|
|||
}
|
||||
|
||||
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
||||
bool ok;
|
||||
ssize_t got;
|
||||
intptr_t addr;
|
||||
size_t i, j, gi;
|
||||
|
@ -99,7 +100,10 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
garbage = weaken(__garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
for (frame = bp; frame && i < kBacktraceMaxFrames - 1; frame = frame->next) {
|
||||
if (!IsValidStackFramePointer(frame)) {
|
||||
__mmi_lock();
|
||||
ok = IsValidStackFramePointer(frame);
|
||||
__mmi_unlock();
|
||||
if (!ok) {
|
||||
return -1;
|
||||
}
|
||||
addr = frame->addr;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/gc.internal.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -46,6 +47,7 @@
|
|||
noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
||||
const struct StackFrame *bp,
|
||||
struct SymbolTable *st) {
|
||||
bool ok;
|
||||
size_t gi;
|
||||
intptr_t addr;
|
||||
int i, symbol, addend;
|
||||
|
@ -55,7 +57,10 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
|||
garbage = weaken(__garbage);
|
||||
gi = garbage ? garbage->i : 0;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
|
27
libc/nexgen32e/gettls.h
Normal file
27
libc/nexgen32e/gettls.h
Normal 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_ */
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
|
||||
#define COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_
|
||||
#include "libc/dce.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -8,25 +7,9 @@ extern int __threaded;
|
|||
extern bool __tls_enabled;
|
||||
extern unsigned __tls_index;
|
||||
|
||||
char *__get_tls(void) libcesque nosideeffect;
|
||||
void *__initialize_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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ */
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
sys_clone_linux:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
push %rbx
|
||||
mov %rcx,%r10
|
||||
mov 16(%rbp),%rbx
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef 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"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -17,13 +17,14 @@ struct CxaAtexitBlocks {
|
|||
} * p, root;
|
||||
};
|
||||
|
||||
extern pthread_mutex_t __cxa_lock_obj;
|
||||
extern struct CxaAtexitBlocks __cxa_blocks;
|
||||
|
||||
void __cxa_lock(void);
|
||||
void __cxa_unlock(void);
|
||||
void __cxa_printexits(FILE *, void *);
|
||||
|
||||
#define __cxa_lock() pthread_mutex_lock(&__cxa_lock_obj)
|
||||
#define __cxa_unlock() pthread_mutex_unlock(&__cxa_lock_obj)
|
||||
#define __cxa_lock() (__threaded ? __cxa_lock() : 0)
|
||||
#define __cxa_unlock() (__threaded ? __cxa_unlock() : 0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/lockcmpxchgp.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
|
@ -39,12 +39,11 @@
|
|||
|
||||
void ftrace_hook(void);
|
||||
|
||||
_Alignas(64) int ftrace_lock;
|
||||
|
||||
static struct Ftrace {
|
||||
int skew;
|
||||
int stackdigs;
|
||||
int64_t lastaddr;
|
||||
volatile bool busy;
|
||||
} g_ftrace;
|
||||
|
||||
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) {
|
||||
int zero = 0;
|
||||
__atomic_store(&ftrace_lock, &zero, __ATOMIC_RELAXED);
|
||||
g_ftrace.busy = false;
|
||||
}
|
||||
|
||||
static privileged inline bool AcquireFtraceLock(void) {
|
||||
int me, owner;
|
||||
unsigned tries;
|
||||
if (!__threaded) {
|
||||
return _cmpxchg(&ftrace_lock, 0, -1);
|
||||
return _cmpxchg(&g_ftrace.busy, false, true);
|
||||
} else {
|
||||
for (tries = 0, me = gettid();;) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
return _lockcmpxchg(&g_ftrace.busy, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#include "libc/assert.h"
|
||||
#include "libc/bits/midpoint.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/sysv/consts/ss.h"
|
||||
|
@ -31,9 +31,6 @@ COSMOPOLITAN_C_START_
|
|||
#define _kMem(NORMAL, WIN7) \
|
||||
(!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7)
|
||||
|
||||
#define __mmi_lock() pthread_mutex_lock(&_mmi.lock)
|
||||
#define __mmi_unlock() pthread_mutex_unlock(&_mmi.lock)
|
||||
|
||||
struct MemoryInterval {
|
||||
int x;
|
||||
int y;
|
||||
|
@ -50,11 +47,12 @@ struct MemoryIntervals {
|
|||
size_t i, n;
|
||||
struct MemoryInterval *p;
|
||||
struct MemoryInterval s[OPEN_MAX];
|
||||
pthread_mutex_t lock;
|
||||
};
|
||||
|
||||
extern hidden struct MemoryIntervals _mmi;
|
||||
|
||||
void __mmi_lock(void) hidden;
|
||||
void __mmi_unlock(void) hidden;
|
||||
bool IsMemtracked(int, int) hidden;
|
||||
void PrintSystemMappings(int) hidden;
|
||||
const char *DescribeFrame(int) hidden;
|
||||
|
@ -69,6 +67,9 @@ void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
|
|||
int UntrackMemoryIntervals(void *, size_t) hidden;
|
||||
size_t GetMemtrackSize(struct MemoryIntervals *);
|
||||
|
||||
#define __mmi_lock() (__threaded ? __mmi_lock() : 0)
|
||||
#define __mmi_unlock() (__threaded ? __mmi_unlock() : 0)
|
||||
|
||||
#define IsLegalPointer(p) \
|
||||
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
|
||||
|
||||
|
|
|
@ -11,13 +11,17 @@ struct StdioFlushHandles {
|
|||
};
|
||||
|
||||
struct StdioFlush {
|
||||
pthread_mutex_t lock;
|
||||
struct StdioFlushHandles handles;
|
||||
FILE *handles_initmem[8];
|
||||
};
|
||||
|
||||
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_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STDIO_FFLUSH_H_ */
|
||||
|
|
|
@ -31,6 +31,16 @@
|
|||
#include "libc/stdio/stdio.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.
|
||||
*
|
||||
|
@ -41,7 +51,7 @@ int fflush_unlocked(FILE *f) {
|
|||
int rc = 0;
|
||||
size_t i;
|
||||
if (!f) {
|
||||
pthread_mutex_lock(&__fflush.lock);
|
||||
__fflush_lock();
|
||||
for (i = __fflush.handles.i; i; --i) {
|
||||
if ((f = __fflush.handles.p[i - 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) {
|
||||
if (__fflush_impl(f) == -1) {
|
||||
rc = -1;
|
||||
|
@ -64,7 +74,7 @@ textstartup int __fflush_register(FILE *f) {
|
|||
int rc;
|
||||
size_t i;
|
||||
struct StdioFlush *sf;
|
||||
pthread_mutex_lock(&__fflush.lock);
|
||||
__fflush_lock();
|
||||
sf = &__fflush;
|
||||
if (!sf->handles.p) {
|
||||
sf->handles.p = sf->handles_initmem;
|
||||
|
@ -74,19 +84,19 @@ textstartup int __fflush_register(FILE *f) {
|
|||
for (i = sf->handles.i; i; --i) {
|
||||
if (!sf->handles.p[i - 1]) {
|
||||
sf->handles.p[i - 1] = f;
|
||||
pthread_mutex_unlock(&__fflush.lock);
|
||||
__fflush_unlock();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rc = append(&sf->handles, &f);
|
||||
pthread_mutex_unlock(&__fflush.lock);
|
||||
__fflush_unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void __fflush_unregister(FILE *f) {
|
||||
size_t i;
|
||||
struct StdioFlush *sf;
|
||||
pthread_mutex_lock(&__fflush.lock);
|
||||
__fflush_lock();
|
||||
sf = &__fflush;
|
||||
sf = pushpop(sf);
|
||||
for (i = sf->handles.i; i; --i) {
|
||||
|
@ -95,5 +105,5 @@ void __fflush_unregister(FILE *f) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&__fflush.lock);
|
||||
__fflush_unlock();
|
||||
}
|
||||
|
|
|
@ -16,26 +16,25 @@
|
|||
│ 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()
|
||||
* @threadsafe
|
||||
*/
|
||||
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;
|
||||
wchar_t *fgetws(wchar_t *s, int size, FILE *f) {
|
||||
wchar_t *rc;
|
||||
flockfile(f);
|
||||
rc = fgetws_unlocked(s, size, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
50
libc/stdio/fgetws_unlocked.c
Normal file
50
libc/stdio/fgetws_unlocked.c
Normal 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;
|
||||
}
|
|
@ -21,6 +21,6 @@
|
|||
/**
|
||||
* Acquires reentrant lock on stdio object, blocking if needed.
|
||||
*/
|
||||
void flockfile(FILE *f) {
|
||||
void(flockfile)(FILE *f) {
|
||||
pthread_mutex_lock(&f->lock);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
void _flushlbf(void) {
|
||||
int i;
|
||||
FILE *f;
|
||||
pthread_mutex_lock(&__fflush.lock);
|
||||
__fflush_lock();
|
||||
for (i = 0; i < __fflush.handles.i; ++i) {
|
||||
if ((f = __fflush.handles.p[i])) {
|
||||
flockfile(f);
|
||||
|
@ -39,5 +39,5 @@ void _flushlbf(void) {
|
|||
funlockfile(f);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&__fflush.lock);
|
||||
__fflush_unlock();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Writes string to stream.
|
||||
|
@ -29,11 +28,12 @@
|
|||
* @param s is a NUL-terminated string that's non-NULL
|
||||
* @param f is an open stream
|
||||
* @return bytes written, or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int fputs_unlocked(const char *s, FILE *f) {
|
||||
size_t n, r;
|
||||
n = strlen(s);
|
||||
r = fwrite_unlocked(s, 1, n, f);
|
||||
if (!r && n) return -1;
|
||||
return r;
|
||||
int fputs(const char *s, FILE *f) {
|
||||
int rc;
|
||||
flockfile(f);
|
||||
rc = fputs_unlocked(s, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,20 +16,24 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
// 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
|
||||
// unrecoverable error happens.
|
||||
//
|
||||
// @param rdi is nul-terminated string that's non-null
|
||||
// @param rsi is file object stream pointer
|
||||
// @return strlen(rdi) on success or -1 w/ errno
|
||||
// @see fputs_unlocked()
|
||||
// @threadsafe
|
||||
fputs: mov %rsi,%r11
|
||||
ezlea fputs_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn fputs,globl
|
||||
/**
|
||||
* 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
|
||||
* unrecoverable error happens.
|
||||
*
|
||||
* @param s is a NUL-terminated string that's non-NULL
|
||||
* @param f is an open stream
|
||||
* @return bytes written, or -1 w/ errno
|
||||
*/
|
||||
int fputs_unlocked(const char *s, FILE *f) {
|
||||
size_t n, r;
|
||||
n = strlen(s);
|
||||
r = fwrite_unlocked(s, 1, n, f);
|
||||
if (!r && n) return -1;
|
||||
return r;
|
||||
}
|
|
@ -17,24 +17,19 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
uint64_t w;
|
||||
if (wc != -1) {
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
if (fputc_unlocked(w, f) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return wc;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
wint_t fputwc(wchar_t wc, FILE *f) {
|
||||
wint_t rc;
|
||||
flockfile(f);
|
||||
rc = fputwc_unlocked(wc, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,18 +16,27 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
// Writes data to stream.
|
||||
//
|
||||
// @param rdi has pointer to data to write
|
||||
// @param rsi stride specifies the size of individual items
|
||||
// @param rdx count is the number of strides to write
|
||||
// @param rcx has file object stream pointer
|
||||
// @return count on success, [0,count) on EOF, 0 on error or count==0
|
||||
// @see fwrite_unlocked()
|
||||
// @threadsafe
|
||||
fwrite: mov %rcx,%r11
|
||||
ezlea fwrite_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn fwrite,globl
|
||||
/**
|
||||
* Writes wide character to stream.
|
||||
*
|
||||
* @param wc has wide character
|
||||
* @param f is file object stream pointer
|
||||
* @return wide character if written or -1 w/ errno
|
||||
*/
|
||||
wint_t fputwc_unlocked(wchar_t wc, FILE *f) {
|
||||
uint64_t w;
|
||||
if (wc != -1) {
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
if (fputc_unlocked(w, f) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return wc;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
|
@ -29,20 +28,12 @@
|
|||
* @param s is a NUL-terminated string that's non-NULL
|
||||
* @param f is an open stream
|
||||
* @return strlen(s) or -1 w/ errno on error
|
||||
* @threadsafe
|
||||
*/
|
||||
int fputws_unlocked(const wchar_t *s, FILE *f) {
|
||||
int res = 0;
|
||||
while (*s) {
|
||||
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;
|
||||
int fputws(const wchar_t *s, FILE *f) {
|
||||
int rc;
|
||||
flockfile(f);
|
||||
rc = fputws_unlocked(s, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,20 +16,33 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
// 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
|
||||
// unrecoverable error happens.
|
||||
//
|
||||
// @param rdi is nul-terminated string that's non-null
|
||||
// @param rsi is file object stream pointer
|
||||
// @return strlen(rdi) on success or -1 w/ errno
|
||||
// @see fputws_unlocked()
|
||||
// @threadsafe
|
||||
fputws: mov %rsi,%r11
|
||||
ezlea fputws_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn fputws,globl
|
||||
/**
|
||||
* 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
|
||||
* unrecoverable error happens.
|
||||
*
|
||||
* @param s is a NUL-terminated string that's non-NULL
|
||||
* @param f is an open stream
|
||||
* @return strlen(s) or -1 w/ errno on error
|
||||
*/
|
||||
int fputws_unlocked(const wchar_t *s, FILE *f) {
|
||||
int res = 0;
|
||||
while (*s) {
|
||||
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;
|
||||
}
|
|
@ -16,19 +16,7 @@
|
|||
│ 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.
|
||||
|
@ -36,64 +24,12 @@
|
|||
* @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
|
||||
* @threadsafe
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
|
||||
size_t rc;
|
||||
flockfile(f);
|
||||
rc = fread_unlocked(buf, stride, count, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
104
libc/stdio/fread_unlocked.c
Normal file
104
libc/stdio/fread_unlocked.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -16,11 +16,7 @@
|
|||
│ 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.
|
||||
|
@ -34,46 +30,12 @@
|
|||
* @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
|
||||
* @threadsafe
|
||||
*/
|
||||
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;
|
||||
int fseeko(FILE *f, int64_t offset, int whence) {
|
||||
int rc;
|
||||
flockfile(f);
|
||||
rc = fseeko_unlocked(f, offset, whence);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
79
libc/stdio/fseeko_unlocked.c
Normal file
79
libc/stdio/fseeko_unlocked.c
Normal 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;
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
#include "libc/stdio/stdio.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;
|
||||
uint32_t skew;
|
||||
if (f->fd != -1) {
|
||||
|
@ -45,6 +45,7 @@ static int64_t ftello_unlocked(FILE *f) {
|
|||
*
|
||||
* @param stream is a non-null stream handle
|
||||
* @returns current byte offset from beginning, or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int64_t ftello(FILE *f) {
|
||||
int64_t rc;
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
*
|
||||
* @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);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
/**
|
||||
* Releases lock on stdio object.
|
||||
*/
|
||||
void funlockfile(FILE *f) {
|
||||
void(funlockfile)(FILE *f) {
|
||||
pthread_mutex_unlock(&f->lock);
|
||||
}
|
||||
|
|
|
@ -16,18 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ 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/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Writes data to stream.
|
||||
|
@ -35,54 +24,12 @@
|
|||
* @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
|
||||
* @threadsafe
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
||||
size_t rc;
|
||||
flockfile(f);
|
||||
rc = fwrite_unlocked(data, stride, count, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
113
libc/stdio/fwrite_unlocked.c
Normal file
113
libc/stdio/fwrite_unlocked.c
Normal 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;
|
||||
}
|
|
@ -21,7 +21,8 @@
|
|||
/**
|
||||
* Reads byte from stream.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int(getc_unlocked)(FILE *f) {
|
||||
return fgetc_unlocked(f);
|
||||
int(getc)(FILE *f) {
|
||||
return getc(f);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,16 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
// Reads character from stdin.
|
||||
//
|
||||
// @return byte in range 0..255, or -1 w/ errno
|
||||
// @see fgetc_unlocked()
|
||||
// @threadsafe
|
||||
getchar:
|
||||
mov stdin(%rip),%rdi
|
||||
mov %rdi,%r11
|
||||
ezlea fgetc_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn getchar,globl
|
||||
/**
|
||||
* Reads byte from stream.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
*/
|
||||
int(getc_unlocked)(FILE *f) {
|
||||
return fgetc_unlocked(f);
|
||||
}
|
|
@ -21,7 +21,8 @@
|
|||
/**
|
||||
* Reads byte from stdin.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
* @htreadsafe
|
||||
*/
|
||||
int getchar_unlocked(void) {
|
||||
return fgetc_unlocked(stdin);
|
||||
int getchar(void) {
|
||||
return fgetc(stdin);
|
||||
}
|
||||
|
|
27
libc/stdio/getchar_unlocked.c
Normal file
27
libc/stdio/getchar_unlocked.c
Normal 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);
|
||||
}
|
|
@ -21,7 +21,8 @@
|
|||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
* @threadsafe
|
||||
*/
|
||||
wint_t(getwc_unlocked)(FILE *f) {
|
||||
return fgetwc_unlocked(f);
|
||||
wint_t(getwc)(FILE *f) {
|
||||
return fgetwc(f);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,16 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
// Reads UTF-8 character from stdin.
|
||||
//
|
||||
// @return wide character or -1 on EOF or error
|
||||
// @see fgetwc_unlocked()
|
||||
// @threadsafe
|
||||
getwchar:
|
||||
mov stdin(%rip),%rdi
|
||||
mov %rdi,%r11
|
||||
ezlea fgetwc_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn getwchar,globl
|
||||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
*/
|
||||
wint_t(getwc_unlocked)(FILE *f) {
|
||||
return fgetwc_unlocked(f);
|
||||
}
|
|
@ -21,7 +21,8 @@
|
|||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
* @threadsafe
|
||||
*/
|
||||
wint_t getwchar_unlocked(void) {
|
||||
return fgetwc_unlocked(stdin);
|
||||
wint_t getwchar(void) {
|
||||
return fgetwc(stdin);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,15 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
// Reads character from stream.
|
||||
//
|
||||
// @param rdi has file stream object pointer
|
||||
// @return byte in range 0..255, or -1 w/ errno
|
||||
// @see fgetc_unlocked()
|
||||
// @threadsafe
|
||||
getc: mov %rdi,%r11
|
||||
ezlea fgetwc_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn getc,globl
|
||||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
*/
|
||||
wint_t getwchar_unlocked(void) {
|
||||
return fgetwc_unlocked(stdin);
|
||||
}
|
|
@ -23,7 +23,8 @@
|
|||
*
|
||||
* @param c is byte to buffer or write, which is masked
|
||||
* @return c as unsigned char if written or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int(putc_unlocked)(int c, FILE *f) {
|
||||
return fputc_unlocked(c, f);
|
||||
int(putc)(int c, FILE *f) {
|
||||
return fputc(c, f);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,15 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
// Reads UTF-8 character from stream.
|
||||
//
|
||||
// @param rdi has file stream object pointer
|
||||
// @return wide character or -1 on EOF or error
|
||||
// @see fgetwc_unlocked()
|
||||
// @threadsafe
|
||||
getwc: mov %rdi,%r11
|
||||
ezlea fgetwc_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn getwc,globl
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
*
|
||||
* @param c is byte to buffer or write, which is masked
|
||||
* @return c as unsigned char if written or -1 w/ errno
|
||||
*/
|
||||
int(putc_unlocked)(int c, FILE *f) {
|
||||
return fputc_unlocked(c, f);
|
||||
}
|
|
@ -22,7 +22,8 @@
|
|||
* Writes byte to stdout.
|
||||
*
|
||||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int putchar_unlocked(int c) {
|
||||
return fputc_unlocked(c, stdout);
|
||||
int putchar(int c) {
|
||||
return fputc(c, stdout);
|
||||
}
|
||||
|
|
28
libc/stdio/putchar_unlocked.c
Normal file
28
libc/stdio/putchar_unlocked.c
Normal 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);
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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;
|
||||
if ((n = strlen(s))) {
|
||||
r = fwrite_unlocked(s, 1, n, f);
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
* Writes wide character to stream.
|
||||
*
|
||||
* @return wc if written or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
wint_t(putwc_unlocked)(wchar_t wc, FILE *f) {
|
||||
return fputwc_unlocked(wc, f);
|
||||
wint_t(putwc)(wchar_t wc, FILE *f) {
|
||||
return fputwc(wc, f);
|
||||
}
|
||||
|
|
28
libc/stdio/putwc_unlocked.c
Normal file
28
libc/stdio/putwc_unlocked.c
Normal 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);
|
||||
}
|
|
@ -21,7 +21,8 @@
|
|||
/**
|
||||
* Writes wide character to stdout.
|
||||
* @return wc if written or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
wint_t putwchar_unlocked(wchar_t wc) {
|
||||
return fputwc_unlocked(wc, stdout);
|
||||
wint_t putwchar(wchar_t wc) {
|
||||
return fputwc(wc, stdout);
|
||||
}
|
||||
|
|
27
libc/stdio/putwchar_unlocked.c
Normal file
27
libc/stdio/putwchar_unlocked.c
Normal 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);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#define COSMOPOLITAN_LIBC_STDIO_STDIO_H_
|
||||
#include "libc/fmt/pflink.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/symbolic.h"
|
||||
|
||||
#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)
|
||||
paramsnonnull() dontthrow nocallback;
|
||||
|
||||
#define getc_unlocked(f) fgetc_unlocked(f)
|
||||
#define getwc_unlocked(f) fgetwc_unlocked(f)
|
||||
#define putc_unlocked(c, f) fputc_unlocked(c, f)
|
||||
#define putwc_unlocked(c, f) fputwc_unlocked(c, f)
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define 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 getwc(f) fgetwc(f)
|
||||
#define putc(c, f) fputc(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__)
|
||||
/* clang-format off */
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
|
|
|
@ -17,20 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Pushes byte back to stream.
|
||||
* @threadsafe
|
||||
*/
|
||||
int ungetc_unlocked(int c, FILE *f) {
|
||||
if (c == -1) return -1;
|
||||
if (f->beg) {
|
||||
f->buf[--f->beg] = c;
|
||||
} else if (f->end < f->size) {
|
||||
memmove(f->buf + 1, f->buf, f->end++);
|
||||
f->buf[0] = c;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return c & 255;
|
||||
int ungetc(int c, FILE *f) {
|
||||
int rc;
|
||||
flockfile(f);
|
||||
rc = ungetc_unlocked(c, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,16 +16,21 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
// Writes wide character to stream.
|
||||
//
|
||||
// @param rdi has wide character
|
||||
// @param rsi has file object stream pointer
|
||||
// @return rax is wide character if written or -1 w/ errno
|
||||
// @see fputwc_unlocked()
|
||||
// @threadsafe
|
||||
fputwc: mov %rsi,%r11
|
||||
ezlea fputwc_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn fputwc,globl
|
||||
/**
|
||||
* Pushes byte back to stream.
|
||||
*/
|
||||
int ungetc_unlocked(int c, FILE *f) {
|
||||
if (c == -1) return -1;
|
||||
if (f->beg) {
|
||||
f->buf[--f->beg] = c;
|
||||
} else if (f->end < f->size) {
|
||||
memmove(f->buf + 1, f->buf, f->end++);
|
||||
f->buf[0] = c;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return c & 255;
|
||||
}
|
|
@ -17,31 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
/**
|
||||
* Pushes wide character back to stream.
|
||||
* @threadsafe
|
||||
*/
|
||||
wint_t ungetwc_unlocked(wint_t c, FILE *f) {
|
||||
char b[6];
|
||||
unsigned n;
|
||||
uint64_t w;
|
||||
if (c == -1) return -1;
|
||||
n = 0;
|
||||
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;
|
||||
wint_t ungetwc(wint_t c, FILE *f) {
|
||||
wint_t rc;
|
||||
flockfile(f);
|
||||
rc = ungetwc_unlocked(c, f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- 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│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,20 +16,32 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ 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.
|
||||
//
|
||||
// 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 rdi is nul-terminated string that's non-null
|
||||
// @param rsi is size of rdi buffer
|
||||
// @param rsi is file stream object pointer
|
||||
// @see fgetws_unlocked()
|
||||
// @threadsafe
|
||||
fgetws: mov %rdx,%r11
|
||||
ezlea fgetws_unlocked,ax
|
||||
jmp stdio_unlock
|
||||
.endfn fgetws,globl
|
||||
/**
|
||||
* Pushes wide character back to stream.
|
||||
*/
|
||||
wint_t ungetwc_unlocked(wint_t c, FILE *f) {
|
||||
char b[6];
|
||||
unsigned n;
|
||||
uint64_t w;
|
||||
if (c == -1) return -1;
|
||||
n = 0;
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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) {
|
||||
const void *r;
|
||||
if (X86_HAVE(SSE)) {
|
||||
if (IsAsan()) __asan_verify(s, n);
|
||||
if (!IsTiny() && X86_HAVE(SSE)) {
|
||||
if (IsAsan()) {
|
||||
__asan_verify(s, n);
|
||||
}
|
||||
r = memchr_sse(s, c, n);
|
||||
} else {
|
||||
r = memchr_pure(s, c, n);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
|
||||
/**
|
||||
* Returns address of thread information block.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -45,15 +46,18 @@ STATIC_YOINK("usr/share/zoneinfo/UTC");
|
|||
|
||||
static pthread_mutex_t locallock;
|
||||
|
||||
static int lock(void) {
|
||||
static int localtime_lock(void) {
|
||||
pthread_mutex_lock(&locallock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unlock(void) {
|
||||
static void localtime_unlock(void) {
|
||||
pthread_mutex_unlock(&locallock);
|
||||
}
|
||||
|
||||
#define localtime_lock() (__threaded ? localtime_lock() : 0)
|
||||
#define localtime_unlock() (__threaded ? localtime_unlock() : 0)
|
||||
|
||||
#ifndef TZ_ABBR_MAX_LEN
|
||||
#define TZ_ABBR_MAX_LEN 16
|
||||
#endif /* !defined TZ_ABBR_MAX_LEN */
|
||||
|
@ -1407,10 +1411,10 @@ localtime_tzset_unlocked(void)
|
|||
void
|
||||
tzset(void)
|
||||
{
|
||||
if (lock() != 0)
|
||||
if (localtime_lock() != 0)
|
||||
return;
|
||||
localtime_tzset_unlocked();
|
||||
unlock();
|
||||
localtime_unlock();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1422,7 +1426,7 @@ static void
|
|||
localtime_gmtcheck(void)
|
||||
{
|
||||
static bool gmt_is_set;
|
||||
if (lock() != 0)
|
||||
if (localtime_lock() != 0)
|
||||
return;
|
||||
if (! gmt_is_set) {
|
||||
gmtptr = malloc(sizeof *gmtptr);
|
||||
|
@ -1431,7 +1435,7 @@ localtime_gmtcheck(void)
|
|||
gmtload(gmtptr);
|
||||
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 *
|
||||
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
|
||||
{
|
||||
int err = lock();
|
||||
int err = localtime_lock();
|
||||
if (err) {
|
||||
errno = err;
|
||||
return NULL;
|
||||
|
@ -1543,7 +1547,7 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
|
|||
if (setname || !lcl_is_set)
|
||||
localtime_tzset_unlocked();
|
||||
tmp = localsub(lclptr, timep, setname, tmp);
|
||||
unlock();
|
||||
localtime_unlock();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -2150,14 +2154,14 @@ time_t
|
|||
mktime(struct tm *tmp)
|
||||
{
|
||||
time_t t;
|
||||
int err = lock();
|
||||
int err = localtime_lock();
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
localtime_tzset_unlocked();
|
||||
t = mktime_tzname(lclptr, tmp, true);
|
||||
unlock();
|
||||
localtime_unlock();
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
2
third_party/dlmalloc/locks.inc
vendored
2
third_party/dlmalloc/locks.inc
vendored
|
@ -101,7 +101,7 @@ static dontinline int spin_acquire_lock(int *sl) {
|
|||
|
||||
#define MLOCK_T int
|
||||
#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 INITIAL_LOCK(sl) (*sl = 0)
|
||||
#define DESTROY_LOCK(sl) (0)
|
||||
|
|
2
third_party/zlib/puff.c
vendored
2
third_party/zlib/puff.c
vendored
|
@ -131,7 +131,7 @@ struct state {
|
|||
* buffer, using shift right, and new bytes are appended to the top of the
|
||||
* 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) */
|
||||
|
||||
/* load at least need bits into val */
|
||||
|
|
Loading…
Reference in a new issue