Make improvements to locking

This change makes pthread_mutex_lock() as fast as _spinlock() by
default. Thread instability issues on NetBSD have been resolved.
Improvements made to gdtoa thread code. Crash reporting will now
synchronize between threads in a slightly better way.
This commit is contained in:
Justine Tunney 2022-06-19 01:13:03 -07:00
parent 25041b8026
commit d5312b60f7
60 changed files with 890 additions and 629 deletions

View file

@ -36,9 +36,7 @@ EXAMPLES_COMS = \
EXAMPLES_BINS = \
$(EXAMPLES_COMS) \
$(EXAMPLES_COMS:%=%.dbg) \
o/$(MODE)/examples/life-nomod.com \
o/$(MODE)/examples/life-classic.com
$(EXAMPLES_COMS:%=%.dbg)
EXAMPLES_DIRECTDEPS = \
DSP_CORE \
@ -166,34 +164,6 @@ o/$(MODE)/usr/share/dict/words: \
@$(MKDIR) $(@D)
@o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@
################################################################################
# binaries for execve_test.com
o/$(MODE)/examples/life-nomod.com.zip.o: o/$(MODE)/examples/life-nomod.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/life-classic.com.zip.o: o/$(MODE)/examples/life-classic.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/pylife/pylife.com.zip.o: o/$(MODE)/examples/pylife/pylife.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/examples/life-classic.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/life.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/examples/life-nomod.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/life.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
################################################################################
.PHONY: o/$(MODE)/examples

View file

@ -16,9 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/str/str.h"
#include "libc/time/time.h"
/**

View file

@ -25,9 +25,11 @@ unsigned __sighandflags[NSIG];
static pthread_mutex_t __sig_lock_obj;
void(__sig_lock)(void) {
__sig_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__sig_lock_obj);
}
void(__sig_unlock)(void) {
__sig_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__sig_lock_obj);
}

View file

@ -18,34 +18,44 @@
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/log/log.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
/**
* Handles failure of assert() macro.
*/
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
int rc;
static bool noreentry;
int me, owner;
static int sync;
--__strace;
--__ftrace;
kprintf("%s:%d: assert(%s) failed\n", file, line, expr);
if (_lockcmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
owner = 0;
me = gettid();
kprintf("%s:%d: assert(%s) failed (tid %d)\n", file, line, expr, me);
if (_lockcmpxchgp(&sync, &owner, me)) {
__restore_tty();
if (weaken(ShowBacktrace)) {
weaken(ShowBacktrace)(2, __builtin_frame_address(0));
} else if (weaken(PrintBacktraceUsingSymbols) && weaken(GetSymbolTable)) {
weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
weaken(GetSymbolTable)());
} else {
kprintf("can't backtrace b/c `__die` not linked\n");
kprintf("can't backtrace b/c `ShowCrashReports` not linked\n");
}
rc = 23;
__restorewintty();
_Exit(23);
} else if (owner == me) {
kprintf("assert failed while failing\n");
__restorewintty();
_Exit(24);
} else {
rc = 24;
_Exit1(25);
}
__restorewintty();
_Exit(rc);
}

View file

@ -31,7 +31,6 @@
* @noreturn
*/
privileged wontreturn void _Exit1(int rc) {
jmp_buf *jb;
struct WinThread *wt;
STRACE("_Exit1(%d)", rc);
if (!IsWindows() && !IsMetal()) {

View file

@ -30,10 +30,12 @@ struct Fds g_fds;
static pthread_mutex_t __fds_lock_obj;
void(__fds_lock)(void) {
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__fds_lock_obj);
}
void(__fds_unlock)(void) {
__fds_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__fds_lock_obj);
}

View file

@ -22,7 +22,7 @@
STATIC_YOINK("_init__mmi");
struct MemoryIntervals _mmi;
static pthread_mutex_t __mmi_lock_obj;
pthread_mutex_t __mmi_lock_obj; // recursive :'(
void(__mmi_lock)(void) {
pthread_mutex_lock(&__mmi_lock_obj);

View file

@ -16,9 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pthread.h"
#include "libc/macros.internal.h"
.init.start 200,_init__mmi
movb $OPEN_MAX,_mmi+8
movl $_mmi+24,_mmi+16
movb $PTHREAD_MUTEX_RECURSIVE,__mmi_lock_obj(%rip)
.init.end 200,_init__mmi

View file

@ -1,19 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#define COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_
#include "libc/bits/atomic.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/kprintf.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/dce.h"
#define PTHREAD_ONCE_INIT 0
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_RECURSIVE 0
#define PTHREAD_MUTEX_NORMAL 1
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_RECURSIVE 1
#define PTHREAD_MUTEX_ERRORCHECK 2
#define PTHREAD_MUTEX_STALLED 0
#define PTHREAD_MUTEX_ROBUST 1
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* clang-format off */
#define PTHREAD_MUTEX_INITIALIZER {PTHREAD_MUTEX_DEFAULT}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
@ -66,8 +68,8 @@ typedef struct {
} __u;
} pthread_rwlock_t;
wontreturn void pthread_exit(void *);
pureconst pthread_t pthread_self(void);
void pthread_exit(void *) wontreturn;
pthread_t pthread_self(void) pureconst;
int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *);
int pthread_yield(void);
@ -104,6 +106,30 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
#define pthread_mutexattr_init(pAttr) ((pAttr)->attr = PTHREAD_MUTEX_DEFAULT, 0)
#define pthread_mutexattr_destroy(pAttr) ((pAttr)->attr = 0)
#define pthread_mutexattr_gettype(pAttr, pType) (*(pType) = (pAttr)->attr, 0)
#define pthread_mutexattr_settype(pAttr, type) ((pAttr)->attr = type, 0)
#ifdef __GNUC__
#define pthread_mutex_lock(mutex) \
(((mutex)->attr == PTHREAD_MUTEX_NORMAL && \
!atomic_load_explicit(&(mutex)->lock, memory_order_relaxed) && \
!atomic_exchange(&(mutex)->lock, 1)) \
? 0 \
: pthread_mutex_lock(mutex))
#define pthread_mutex_unlock(mutex) \
((mutex)->attr == PTHREAD_MUTEX_NORMAL \
? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \
(IsLinux() && \
atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \
_pthread_mutex_wake(mutex)), \
0) \
: pthread_mutex_unlock(mutex))
#endif
int _pthread_mutex_wake(pthread_mutex_t *) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_PTHREAD_H_ */

View file

@ -21,41 +21,68 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h"
#include "libc/linux/futex.h"
#include "libc/nexgen32e/threaded.h"
static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int tries) {
volatile int i;
if (tries < 7) {
for (i = 0; i != 1 << tries; i++) {
}
tries++;
} else if (IsLinux()) {
atomic_fetch_add(&mutex->waits, 1);
LinuxFutexWait(&mutex->lock, 1, 0);
atomic_fetch_sub(&mutex->waits, 1);
} else {
sched_yield();
}
return tries;
}
/**
* Locks mutex.
*
* _spinlock() l: 181,570c 58,646ns
* mutex normal l: 297,965c 96,241ns
* mutex recursive l: 1,112,166c 359,223ns
* mutex errorcheck l: 1,449,723c 468,252ns
*
* @return 0 on success, or error number on failure
*/
int pthread_mutex_lock(pthread_mutex_t *mutex) {
volatile int i;
int(pthread_mutex_lock)(pthread_mutex_t *mutex) {
int me, owner, tries;
for (tries = 0, me = gettid();;) {
owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed);
if (!owner && atomic_compare_exchange_weak_explicit(
&mutex->lock, &owner, me, memory_order_acquire,
memory_order_relaxed)) {
break;
} else if (owner == me) {
if (mutex->attr != PTHREAD_MUTEX_ERRORCHECK) {
break;
} else {
return EDEADLK;
switch (mutex->attr) {
case PTHREAD_MUTEX_NORMAL:
for (tries = 0;;) {
if (!atomic_load_explicit(&mutex->lock, memory_order_relaxed) &&
!atomic_exchange_explicit(&mutex->lock, 1, memory_order_acquire)) {
break;
}
tries = pthread_mutex_lock_spin(mutex, tries);
}
}
if (tries < 7) {
for (i = 0; i != 1 << tries; i++) {
return 0;
case PTHREAD_MUTEX_RECURSIVE:
case PTHREAD_MUTEX_ERRORCHECK:
for (tries = 0, me = gettid();;) {
owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed);
if (!owner && atomic_compare_exchange_weak_explicit(
&mutex->lock, &owner, me, memory_order_acquire,
memory_order_relaxed)) {
break;
} else if (owner == me) {
if (mutex->attr != PTHREAD_MUTEX_ERRORCHECK) {
break;
} else {
return EDEADLK;
}
}
tries = pthread_mutex_lock_spin(mutex, tries);
}
tries++;
} else if (IsLinux()) {
atomic_fetch_add(&mutex->waits, 1);
LinuxFutexWait(&mutex->lock, owner, 0);
atomic_fetch_sub(&mutex->waits, 1);
} else {
sched_yield();
}
++mutex->reent;
return 0;
default:
return EINVAL;
}
++mutex->reent;
return 0;
}

View file

@ -18,28 +18,34 @@
*/
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/pthread.h"
#include "libc/linux/futex.h"
#include "libc/nexgen32e/threaded.h"
/**
* Releases mutex.
* @return 0 on success or error number on failure
* @raises EPERM if in error check mode and not owned by caller
*/
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
int owner;
if (mutex->attr == PTHREAD_MUTEX_ERRORCHECK && mutex->lock != gettid()) {
return EPERM;
int(pthread_mutex_unlock)(pthread_mutex_t *mutex) {
int me, owner;
switch (mutex->attr) {
case PTHREAD_MUTEX_ERRORCHECK:
me = gettid();
owner = atomic_load_explicit(&mutex->lock, memory_order_relaxed);
if (owner != me) return EPERM;
// fallthrough
case PTHREAD_MUTEX_RECURSIVE:
if (--mutex->reent) return 0;
// fallthrough
case PTHREAD_MUTEX_NORMAL:
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
if (IsLinux() &&
atomic_load_explicit(&mutex->waits, memory_order_relaxed)) {
_pthread_mutex_wake(mutex);
}
return 0;
default:
return EINVAL;
}
if (!--mutex->reent) {
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
if (IsLinux() &&
atomic_load_explicit(&mutex->waits, memory_order_acquire)) {
LinuxFutexWake(&mutex->lock, 1);
}
}
return 0;
}

View file

@ -0,0 +1,26 @@
/*-*- 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 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/bits/atomic.h"
#include "libc/dce.h"
#include "libc/intrin/pthread.h"
#include "libc/linux/futex.h"
int _pthread_mutex_wake(pthread_mutex_t *mutex) {
return LinuxFutexWake(&mutex->lock, 1);
}

View file

@ -17,13 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pthread.h"
#include "libc/str/str.h"
/**
* Destroys mutex attr.
* @return 0 on success, or error number on failure
*/
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) {
bzero(attr, sizeof(*attr));
int(pthread_mutexattr_destroy)(pthread_mutexattr_t *attr) {
attr->attr = 0;
return 0;
}

View file

@ -29,7 +29,7 @@
* - `PTHREAD_MUTEX_ERRORCHECK`
* @return 0 on success, or error on failure
*/
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) {
int(pthread_mutexattr_gettype)(const pthread_mutexattr_t *attr, int *type) {
*type = attr->attr;
return 0;
}

View file

@ -17,14 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pthread.h"
#include "libc/str/str.h"
/**
* Initializes mutex attr.
* @return 0 on success, or error number on failure
*/
int pthread_mutexattr_init(pthread_mutexattr_t *attr) {
bzero(attr, sizeof(*attr));
int(pthread_mutexattr_init)(pthread_mutexattr_t *attr) {
attr->attr = PTHREAD_MUTEX_DEFAULT;
return 0;
}

View file

@ -30,7 +30,7 @@
* @return 0 on success, or error on failure
* @raises EINVAL if `type` is invalid
*/
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) {
int(pthread_mutexattr_settype)(pthread_mutexattr_t *attr, int type) {
switch (type) {
case PTHREAD_MUTEX_NORMAL:
case PTHREAD_MUTEX_RECURSIVE:

View file

@ -1,5 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § spinlocks
@ -11,7 +13,7 @@
#define _spinlock(lock) _spinlock_cooperative(lock)
#endif
#define _spunlock(lock) __atomic_store_n(lock, 0, __ATOMIC_RELAXED)
#define _spunlock(lock) (__atomic_store_n(lock, 0, __ATOMIC_RELAXED), 0)
#define _seizelock(lock, value) \
({ \
@ -69,6 +71,8 @@
#define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST)
void _spinlock_yield(void);
int _spinlock_yield(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */

View file

@ -103,12 +103,6 @@ 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) {
__mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
return -1;
}
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {

View file

@ -57,13 +57,6 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (i = 0, frame = bp; frame; frame = frame->next) {
__mmi_lock();
ok = IsValidStackFramePointer(frame);
__mmi_unlock();
if (!ok) {
kprintf("%p corrupt frame pointer\n", frame);
break;
}
if (++i == LIMIT) {
kprintf("<truncated backtrace>\n");
break;

View file

@ -16,8 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
@ -32,18 +34,30 @@
*/
relegated wontreturn void __die(void) {
/* asan runtime depends on this function */
int rc;
static bool once;
if (_lockcmpxchg(&once, false, true)) {
int me, owner;
static int sync;
owner = 0;
me = gettid();
if (_lockcmpxchgp(&sync, &owner, me)) {
__restore_tty();
if (IsDebuggerPresent(false)) {
DebugBreak();
}
ShowBacktrace(2, NULL);
rc = 77;
if (weaken(ShowBacktrace)) {
weaken(ShowBacktrace)(2, __builtin_frame_address(0));
} else if (weaken(PrintBacktraceUsingSymbols) && weaken(GetSymbolTable)) {
weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
weaken(GetSymbolTable)());
} else {
kprintf("can't backtrace b/c `ShowCrashReports` not linked\n");
}
__restorewintty();
_Exit(77);
} else if (owner == me) {
kprintf("die failed while dying\n");
__restorewintty();
_Exit(78);
} else {
rc = 78;
_Exit1(79);
}
__restorewintty();
_Exit(rc);
}

View file

@ -26,6 +26,7 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/lockcmpxchgp.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
@ -262,15 +263,22 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
* simply print addresses which may be cross-referenced using objdump.
*
* This function never returns, except for traps w/ human supervision.
*
* @threadsafe
* @vforksafe
*/
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip;
int me, owner;
int gdbpid, err;
static bool noreentry, notpossible;
static int sync;
static bool notpossible;
STRACE("__oncrash rip %x", ctx->uc_mcontext.rip);
--__ftrace;
--__strace;
if (_lockcmpxchg(&noreentry, false, true)) {
owner = 0;
me = gettid();
if (_lockcmpxchgp(&sync, &owner, me)) {
if (!__vforked) {
rip = ctx ? ctx->uc_mcontext.rip : 0;
err = errno;
@ -292,20 +300,30 @@ relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
__restorewintty();
_Exit(128 + sig);
}
sync = 0;
} else {
sync = 0;
__minicrash(sig, si, ctx, "WHILE VFORKED");
}
} else if (sig == SIGTRAP) {
/* chances are IsDebuggerPresent() confused strace w/ gdb */
// chances are IsDebuggerPresent() confused strace w/ gdb
goto ItsATrap;
} else if (_lockcmpxchg(&notpossible, false, true)) {
__minicrash(sig, si, ctx, "WHILE CRASHING");
} else {
for (;;) {
asm("ud2");
} else if (owner == me) {
// we crashed while generating a crash report
if (_lockcmpxchg(&notpossible, false, true)) {
__minicrash(sig, si, ctx, "WHILE CRASHING");
} else {
// somehow __minicrash() crashed not possible
for (;;) {
asm("ud2");
}
}
} else {
// multiple threads have crashed
// kill current thread assuming process dies soon
// TODO(jart): It'd be nice to report on all threads.
_Exit1(8);
}
noreentry = false;
ItsATrap:
++__strace;
++__ftrace;

View file

@ -30,9 +30,12 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
STATIC_YOINK("__die"); /* for backtracing */
STATIC_YOINK("malloc_inspect_all"); /* for asan memory origin */
STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */
STATIC_YOINK("__die"); // for backtracing
STATIC_YOINK("ShowBacktrace"); // for backtracing
STATIC_YOINK("GetSymbolTable"); // for backtracing
STATIC_YOINK("PrintBacktraceUsingSymbols"); // for backtracing
STATIC_YOINK("malloc_inspect_all"); // for asan memory origin
STATIC_YOINK("__get_symbol_by_addr"); // for asan memory origin
extern const unsigned char __oncrash_thunks[8][11];
static struct sigaltstack g_oldsigaltstack;

View file

@ -355,16 +355,15 @@ static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg),
static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
void *arg, void *tls, size_t tlssz, int *ctid) {
// NetBSD has its own clone() and it works, but it's technically a
// second-class API, intended to help Linux folks migrate to this!
// We put it on the thread's stack, to avoid locking this function
// so its stack doesn't scope. The ucontext struct needs 784 bytes
// second-class API, intended to help Linux folks migrate to this.
bool failed;
int ax, *tid;
intptr_t dx, sp;
static bool once;
static int broken;
struct ucontext_netbsd ctx;
struct ucontext_netbsd *ctx;
static struct ucontext_netbsd netbsd_clone_template;
_Static_assert(sizeof(struct ucontext_netbsd) == 784, "fix assembly");
// memoize arbitrary valid processor state structure
if (!once) {
@ -382,35 +381,48 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
return -1;
}
sp = (intptr_t)(stk + stksz);
// allocate memory for child tid
sp -= sizeof(int);
sp = sp & -alignof(int);
tid = (int *)sp;
// align the stack
sp = sp & -16;
// simulate call to misalign stack and ensure backtrace looks good
sp -= 8;
*(intptr_t *)sp = (intptr_t)CloneNetbsd + 1;
// place the giant 784 byte ucontext structure in the red zone!
// it only has to live long enough for the thread to come alive
ctx = (struct ucontext_netbsd *)((sp - sizeof(struct ucontext_netbsd)) &
-alignof(struct ucontext_netbsd));
// pass parameters in process state
memcpy(&ctx, &netbsd_clone_template, sizeof(ctx));
ctx.uc_link = 0;
ctx.uc_mcontext.rbp = 0;
ctx.uc_mcontext.rsp = sp;
ctx.uc_mcontext.rip = (intptr_t)NetbsdThreadMain;
ctx.uc_mcontext.rdi = (intptr_t)arg;
ctx.uc_mcontext.rsi = (intptr_t)func;
ctx.uc_mcontext.rdx = (intptr_t)tid;
ctx.uc_mcontext.rcx = (intptr_t)(flags & CLONE_CHILD_SETTID ? ctid : tid);
ctx.uc_mcontext.r8 = (intptr_t)(flags & CLONE_CHILD_CLEARTID ? ctid : tid);
ctx.uc_flags |= _UC_STACK;
ctx.uc_stack.ss_sp = stk;
ctx.uc_stack.ss_size = stksz;
ctx.uc_stack.ss_flags = 0;
memcpy(ctx, &netbsd_clone_template, sizeof(*ctx));
ctx->uc_link = 0;
ctx->uc_mcontext.rbp = 0;
ctx->uc_mcontext.rsp = sp;
ctx->uc_mcontext.rip = (intptr_t)NetbsdThreadMain;
ctx->uc_mcontext.rdi = (intptr_t)arg;
ctx->uc_mcontext.rsi = (intptr_t)func;
ctx->uc_mcontext.rdx = (intptr_t)tid;
ctx->uc_mcontext.rcx = (intptr_t)(flags & CLONE_CHILD_SETTID ? ctid : tid);
ctx->uc_mcontext.r8 = (intptr_t)(flags & CLONE_CHILD_CLEARTID ? ctid : tid);
ctx->uc_flags |= _UC_STACK;
ctx->uc_stack.ss_sp = stk;
ctx->uc_stack.ss_size = stksz;
ctx->uc_stack.ss_flags = 0;
if (flags & CLONE_SETTLS) {
ctx.uc_flags |= _UC_TLSBASE;
ctx.uc_mcontext._mc_tlsbase = (intptr_t)tls;
ctx->uc_flags |= _UC_TLSBASE;
ctx->uc_mcontext._mc_tlsbase = (intptr_t)tls;
}
// perform the system call
asm volatile(CFLAG_ASM("syscall")
: CFLAG_CONSTRAINT(failed), "=a"(ax), "=d"(dx)
: "1"(__NR__lwp_create), "D"(&ctx), "S"(LWP_DETACHED), "2"(tid)
: "1"(__NR__lwp_create), "D"(ctx), "S"(LWP_DETACHED), "2"(tid)
: "rcx", "r11", "memory");
if (!failed) {
return *tid;

View file

@ -34,10 +34,12 @@
static pthread_mutex_t __fflush_lock_obj;
void(__fflush_lock)(void) {
__fflush_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_lock(&__fflush_lock_obj);
}
void(__fflush_unlock)(void) {
__fflush_lock_obj.attr = PTHREAD_MUTEX_RECURSIVE;
pthread_mutex_unlock(&__fflush_lock_obj);
}

View file

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

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/pthread.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"

View file

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

View file

@ -25,13 +25,13 @@
.init.start 400,_init_stderr
ezlea __stderr,ax
push $_IOLBF
pop (%rax) # f.fd
pop (%rax) # f.fd
push STDERR_FILENO
pop 12(%rax)
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
mov %edx,4(%rax) # f.iomode
ezlea __stderr_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stderr(%rip)
.init.end 400,_init_stderr,globl,hidden

View file

@ -25,9 +25,9 @@
.init.start 400,_init_stdin
ezlea __stdin,ax
mov O_RDONLY,%edx
mov %edx,4(%rax) # f.iomode
mov %edx,4(%rax) # f.iomode
ezlea __stdin_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stdin(%rip)
.init.end 400,_init_stdin,globl,hidden

View file

@ -16,19 +16,19 @@ COSMOPOLITAN_C_START_
*/
typedef struct FILE {
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln;
pthread_mutex_t lock;
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
bool noclose; /* 0x01 for fake dup() todo delete! */
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
uint32_t beg; /* 0x10 */
uint32_t end; /* 0x14 */
char *buf; /* 0x18 */
uint32_t size; /* 0x20 */
uint32_t nofree; /* 0x24 */
int pid; /* 0x28 */
char *getln; /* 0x30 */
pthread_mutex_t lock; /* 0x38 */
} FILE;
extern FILE *stdin;

View file

@ -25,11 +25,11 @@
.init.start 400,_init_stdout
ezlea __stdout,ax
push STDOUT_FILENO
pop 12(%rax) # f.fd
pop 0x0c(%rax) # f.fd
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
mov %edx,4(%rax) # f.iomode
ezlea __stdout_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
mov %rcx,0x18(%rax) # f.buf
movl $BUFSIZ,0x20(%rax) # f.size
mov %rax,stdout(%rip)
.init.end 400,_init_stdout,globl,hidden

View file

@ -56,7 +56,7 @@ void SetUp(void) {
ASSERT_SYS(0, 0, mkdir("tmp", 0755));
ASSERT_SYS(0, 0, mkdir("bin", 0755));
Extract("/zip/tiny64.elf", "bin/tiny64.elf", 0755);
Extract("/zip/pylife.com", "bin/pylife.com", 0755);
// Extract("/zip/pylife.com", "bin/pylife.com", 0755);
Extract("/zip/life-nomod.com", "bin/life-nomod.com", 0755);
Extract("/zip/life-classic.com", "bin/life-classic.com", 0755);
setenv("TMPDIR", "tmp", true);
@ -190,6 +190,7 @@ TEST(execve, vfork_apeClassic) {
}
////////////////////////////////////////////////////////////////////////////////
#if 0 // not worth depending on THIRD_PARTY_PYTHON for this test
TEST(execve, system_apeNoMod3mb) {
if (IsWindows()) return; // todo(jart): wut
@ -229,6 +230,7 @@ TEST(execve, vfork_apeNoMod3mb) {
}
}
#endif
////////////////////////////////////////////////////////////////////////////////
void SystemElf(void) {

22
test/libc/calls/life.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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 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.
*/
int main(int argc, char *argv[]) {
return 42;
}

View file

@ -3,74 +3,95 @@
PKGS += TEST_LIBC_CALLS
TEST_LIBC_CALLS_SRCS := \
TEST_LIBC_CALLS_SRCS := \
$(wildcard test/libc/calls/*.c)
TEST_LIBC_CALLS_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
TEST_LIBC_CALLS_OBJS = \
TEST_LIBC_CALLS_SRCS_TEST = \
$(filter %_test.c,$(TEST_LIBC_CALLS_SRCS))
TEST_LIBC_CALLS_OBJS = \
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.o)
TEST_LIBC_CALLS_COMS = \
$(TEST_LIBC_CALLS_SRCS:%.c=o/$(MODE)/%.com)
TEST_LIBC_CALLS_COMS = \
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com)
TEST_LIBC_CALLS_BINS = \
$(TEST_LIBC_CALLS_COMS) \
TEST_LIBC_CALLS_BINS = \
$(TEST_LIBC_CALLS_COMS) \
$(TEST_LIBC_CALLS_COMS:%=%.dbg)
TEST_LIBC_CALLS_TESTS = \
TEST_LIBC_CALLS_TESTS = \
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_LIBC_CALLS_CHECKS = \
TEST_LIBC_CALLS_CHECKS = \
$(TEST_LIBC_CALLS_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_LIBC_CALLS_DIRECTDEPS = \
DSP_CORE \
LIBC_CALLS \
LIBC_TINYMATH \
LIBC_SOCK \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RAND \
LIBC_STDIO \
LIBC_SYSV_CALLS \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TIME \
LIBC_TESTLIB \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
TEST_LIBC_CALLS_DIRECTDEPS = \
DSP_CORE \
LIBC_CALLS \
LIBC_TINYMATH \
LIBC_SOCK \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RAND \
LIBC_STDIO \
LIBC_SYSV_CALLS \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TIME \
LIBC_TESTLIB \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
THIRD_PARTY_XED
TEST_LIBC_CALLS_DEPS := \
TEST_LIBC_CALLS_DEPS := \
$(call uniq,$(foreach x,$(TEST_LIBC_CALLS_DIRECTDEPS),$($(x))))
o/$(MODE)/test/libc/calls/calls.pkg: \
$(TEST_LIBC_CALLS_OBJS) \
o/$(MODE)/test/libc/calls/calls.pkg: \
$(TEST_LIBC_CALLS_OBJS) \
$(foreach x,$(TEST_LIBC_CALLS_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/libc/calls/%.com.dbg: \
$(TEST_LIBC_CALLS_DEPS) \
o/$(MODE)/test/libc/calls/%.o \
o/$(MODE)/examples/life-nomod.com.zip.o \
o/$(MODE)/examples/life-classic.com.zip.o \
o/$(MODE)/examples/pylife/pylife.com.zip.o \
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
o/$(MODE)/test/libc/calls/%.com.dbg: \
$(TEST_LIBC_CALLS_DEPS) \
o/$(MODE)/test/libc/calls/%.o \
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o \
o/$(MODE)/test/libc/calls/life-classic.com.zip.o \
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o \
o/$(MODE)/third_party/python/Lib/test/tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt.zip.o \
o/$(MODE)/test/libc/calls/calls.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
o/$(MODE)/test/libc/calls/calls.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/test/libc/calls/tiny64.elf.zip.o: ZIPOBJ_FLAGS += -B
o/$(MODE)/test/libc/calls/life-nomod.com.zip.o: o/$(MODE)/test/libc/calls/life-nomod.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/test/libc/calls/life-classic.com.zip.o: o/$(MODE)/test/libc/calls/life-classic.com
@$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) -B $(OUTPUT_OPTION) $<
o/$(MODE)/test/libc/calls/life-classic.com.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/life.o \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/test/libc/calls/life-nomod.com.dbg: \
$(LIBC_RUNTIME) \
o/$(MODE)/test/libc/calls/life.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
.PHONY: o/$(MODE)/test/libc/calls
o/$(MODE)/test/libc/calls: \
$(TEST_LIBC_CALLS_BINS) \
o/$(MODE)/test/libc/calls: \
$(TEST_LIBC_CALLS_BINS) \
$(TEST_LIBC_CALLS_CHECKS)

View file

@ -91,6 +91,7 @@ TEST(memcmp, fuzz) {
int buncmp(const void *, const void *, size_t) asm("bcmp");
int funcmp(const void *, const void *, size_t) asm("memcmp");
#if 0
BENCH(bcmp, bench) {
volatile int v;
const char *volatile a;
@ -135,7 +136,9 @@ BENCH(bcmp, bench) {
memcpy(b, a, 128 * 1024);
EZBENCH_N("bcmp", 131072, v = buncmp(a, b, 131072));
}
#endif
#if 0
BENCH(memcmp, bench) {
volatile int v;
const char *volatile a;
@ -180,7 +183,9 @@ BENCH(memcmp, bench) {
memcpy(b, a, 128 * 1024);
EZBENCH_N("memcmp", 131072, v = funcmp(a, b, 131072));
}
#endif
#if 0
BENCH(timingsafe_memcmp, bench) {
volatile int v;
const char *volatile a;
@ -225,7 +230,9 @@ BENCH(timingsafe_memcmp, bench) {
memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_memcmp", 131072, v = timingsafe_memcmp(a, b, 131072));
}
#endif
#if 0
BENCH(timingsafe_bcmp, bench) {
volatile int v;
const char *volatile a;
@ -270,7 +277,9 @@ BENCH(timingsafe_bcmp, bench) {
memcpy(b, a, 128 * 1024);
EZBENCH_N("timingsafe_bcmp", 131072, v = timingsafe_bcmp(a, b, 131072));
}
#endif
#if 0
BENCH(memcasecmp, bench) {
volatile int v;
const char *volatile a;
@ -315,7 +324,9 @@ BENCH(memcasecmp, bench) {
memcpy(b, a, 128 * 1024);
EZBENCH_N("memcasecmp", 131072, v = memcasecmp(a, b, 131072));
}
#endif
#if 0
BENCH(timingsafe_memcmp, demonstration) {
int bcmp_(const void *, const void *, size_t) asm("bcmp");
int memcmp_(const void *, const void *, size_t) asm("memcmp");
@ -339,3 +350,4 @@ BENCH(timingsafe_memcmp, demonstration) {
a[0] = b[0];
EZBENCH_N("timingsafe_memcmp eq", 256, timingsafe_memcmp(a, b, 256));
}
#endif

View file

@ -51,6 +51,7 @@ TEST(pthread_mutex_lock, normal) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(0, pthread_mutex_init(&lock, 0));
ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
@ -65,6 +66,7 @@ TEST(pthread_mutex_lock, recursive) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
@ -72,7 +74,6 @@ TEST(pthread_mutex_lock, recursive) {
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
}
TEST(pthread_mutex_lock, errorcheck) {
@ -81,13 +82,13 @@ TEST(pthread_mutex_lock, errorcheck) {
ASSERT_EQ(0, pthread_mutexattr_init(&attr));
ASSERT_EQ(0, pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
ASSERT_EQ(0, pthread_mutex_init(&lock, &attr));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_lock(&lock));
ASSERT_EQ(EDEADLK, pthread_mutex_lock(&lock));
ASSERT_EQ(0, pthread_mutex_unlock(&lock));
ASSERT_EQ(EPERM, pthread_mutex_unlock(&lock));
ASSERT_EQ(0, pthread_mutex_destroy(&lock));
ASSERT_EQ(0, pthread_mutexattr_destroy(&attr));
}
int count;
@ -107,6 +108,11 @@ int MutexWorker(void *p) {
TEST(pthread_mutex_lock, contention) {
int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0;
for (i = 0; i < THREADS; ++i) {
clone(MutexWorker,
@ -125,6 +131,63 @@ TEST(pthread_mutex_lock, contention) {
for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize());
}
pthread_mutex_destroy(&lock);
}
TEST(pthread_mutex_lock, rcontention) {
int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0;
for (i = 0; i < THREADS; ++i) {
clone(MutexWorker,
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
(int *)(tls[i] + 0x38));
}
for (i = 0; i < THREADS; ++i) {
_wait0((int *)(tls[i] + 0x38));
}
ASSERT_EQ(THREADS * ITERATIONS, count);
for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize());
}
pthread_mutex_destroy(&lock);
}
TEST(pthread_mutex_lock, econtention) {
int i;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
count = 0;
for (i = 0; i < THREADS; ++i) {
clone(MutexWorker,
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0)),
GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS,
0, 0, __initialize_tls(tls[i]), sizeof(tls[i]),
(int *)(tls[i] + 0x38));
}
for (i = 0; i < THREADS; ++i) {
_wait0((int *)(tls[i] + 0x38));
}
ASSERT_EQ(THREADS * ITERATIONS, count);
for (i = 0; i < THREADS; ++i) {
munmap(stack[i], GetStackSize());
}
pthread_mutex_destroy(&lock);
}
int SpinlockWorker(void *p) {
@ -165,14 +228,8 @@ TEST(_spinlock, contention) {
BENCH(pthread_mutex_lock, bench) {
char schar = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
EZBENCH2("pthread_mutex_lock", donothing,
(pthread_mutex_lock(&lock), pthread_mutex_unlock(&lock)));
EZBENCH2("__fds_lock", donothing, (__fds_lock(), __fds_unlock()));
EZBENCH2("_spinlock", donothing, (_spinlock(&schar), _spunlock(&schar)));
EZBENCH2("_spinlock_tiny", donothing,
(_spinlock_tiny(&schar), _spunlock(&schar)));
EZBENCH2("_spinlock_coop", donothing,
(_spinlock_cooperative(&schar), _spunlock(&schar)));
EZBENCH2("content mut", donothing, pthread_mutex_lock_contention());
EZBENCH2("content spin", donothing, _spinlock_contention());
EZBENCH2("_spinlock", donothing, _spinlock_contention());
EZBENCH2("normal", donothing, pthread_mutex_lock_contention());
EZBENCH2("recursive", donothing, pthread_mutex_lock_rcontention());
EZBENCH2("errorcheck", donothing, pthread_mutex_lock_econtention());
}

View file

@ -79,6 +79,7 @@ TEST(clone, testNullFunc_raisesEinval) {
int CloneTest1(void *arg) {
intptr_t rsp, top, bot;
CheckStackIsAligned();
PrintBacktraceUsingSymbols(2, __builtin_frame_address(0), GetSymbolTable());
rsp = (intptr_t)__builtin_frame_address(0);
bot = (intptr_t)stack;
top = bot + GetStackSize();

View file

@ -30,7 +30,7 @@
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#define THREADS 16
#define THREADS 32
#define DUB(i) (union Dub){i}.x
@ -61,10 +61,6 @@ int Worker(void *p) {
}
TEST(dtoa, test) {
if (IsNetbsd()) {
// TODO(jart): Why does this flake on NetBSD?!
return;
}
int i;
for (i = 0; i < THREADS; ++i) {
clone(Worker,

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/runtime/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
@ -63,11 +64,15 @@ TEST(fgetc, testUnbuffered) {
}
BENCH(fputc, bench) {
__enable_tls();
__enable_threads();
FILE *f;
ASSERT_NE(NULL, (f = fopen("/dev/null", "w")));
EZBENCH2("fputc", donothing, fputc('E', f));
flockfile(f);
flockfile(f);
EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f));
funlockfile(f);
funlockfile(f);
fclose(f);
}

View file

@ -35,31 +35,31 @@
void
freedtoa(char *s)
{
ThInfo *TI = 0;
Bigint *b = (Bigint *)((int *)s - 1);
b->maxwds = 1 << (b->k = *(int*)b);
__gdtoa_Bfree(b);
b->maxwds = 1 << (b->k = *(int *)b);
__gdtoa_Bfree(b, &TI);
}
char *
__gdtoa_rv_alloc(int i)
__gdtoa_rv_alloc(int i, ThInfo **PTI)
{
int j, k, *r;
j = sizeof(ULong);
for(k = 0;
(int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
j <<= 1)
k++;
r = (int*)__gdtoa_Balloc(k);
for (k = 0; (int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
j <<= 1)
k++;
r = (int *)__gdtoa_Balloc(k, PTI);
*r = k;
return (char *)(r+1);
return (char *)(r + 1);
}
char *
__gdtoa_nrv_alloc(char *s, char **rve, int n)
__gdtoa_nrv_alloc(char *s, char **rve, int n, ThInfo **PTI)
{
char *rv, *t;
t = rv = __gdtoa_rv_alloc(n);
while((*t = *s++) !=0)
t = rv = __gdtoa_rv_alloc(n, PTI);
while ((*t = *s++) != 0)
t++;
if (rve)
*rve = t;

View file

@ -103,6 +103,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
Sufficient space is allocated to the return value
to hold the suppressed trailing zeros.
*/
ThInfo *TI = 0;
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
spec_case, try_quick;
@ -128,12 +129,12 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
/* Infinity or NaN */
*decpt = 9999;
if (!word1(&d) && !(word0(&d) & 0xfffff))
return __gdtoa_nrv_alloc("Infinity", rve, 8);
return __gdtoa_nrv_alloc("NaN", rve, 3);
return __gdtoa_nrv_alloc("Infinity", rve, 8, &TI);
return __gdtoa_nrv_alloc("NaN", rve, 3, &TI);
}
if (!dval(&d)) {
*decpt = 1;
return __gdtoa_nrv_alloc("0", rve, 1);
return __gdtoa_nrv_alloc("0", rve, 1, &TI);
}
if (Rounding >= 2) {
if (*sign)
@ -142,7 +143,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (Rounding != 2)
Rounding = 0;
}
b = __gdtoa_d2b(dval(&d), &be, &bbits);
b = __gdtoa_d2b(dval(&d), &be, &bbits, &TI);
if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
dval(&d2) = dval(&d);
word0(&d2) &= Frac_mask1;
@ -245,7 +246,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (i <= 0)
i = 1;
}
s = s0 = __gdtoa_rv_alloc(i);
s = s0 = __gdtoa_rv_alloc(i, &TI);
if (mode > 1 && Rounding != 1)
leftright = 0;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@ -409,7 +410,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
i = denorm ? be + (Bias + (P-1) - 1 + 1) : 1 + P - bbits;
b2 += i;
s2 += i;
mhi = __gdtoa_i2b(1);
mhi = __gdtoa_i2b(1, &TI);
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
@ -420,20 +421,20 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mhi = __gdtoa_pow5mult(mhi, m5);
b1 = __gdtoa_mult(mhi, b);
__gdtoa_Bfree(b);
mhi = __gdtoa_pow5mult(mhi, m5, &TI);
b1 = __gdtoa_mult(mhi, b, &TI);
__gdtoa_Bfree(b, &TI);
b = b1;
}
if (( j = b5 - m5 )!=0)
b = __gdtoa_pow5mult(b, j);
b = __gdtoa_pow5mult(b, j, &TI);
}
else
b = __gdtoa_pow5mult(b, b5);
b = __gdtoa_pow5mult(b, b5, &TI);
}
S = __gdtoa_i2b(1);
S = __gdtoa_i2b(1, &TI);
if (s5 > 0)
S = __gdtoa_pow5mult(S, s5);
S = __gdtoa_pow5mult(S, s5, &TI);
/* Check for special case that d is a normalized power of 2. */
spec_case = 0;
@ -469,20 +470,20 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
s2 += i;
}
if (b2 > 0)
b = __gdtoa_lshift(b, b2);
b = __gdtoa_lshift(b, b2, &TI);
if (s2 > 0)
S = __gdtoa_lshift(S, s2);
S = __gdtoa_lshift(S, s2, &TI);
if (k_check) {
if (__gdtoa_cmp(b,S) < 0) {
k--;
b = __gdtoa_multadd(b, 10, 0); /* we botched the k estimate */
b = __gdtoa_multadd(b, 10, 0, &TI); /* we botched the k estimate */
if (leftright)
mhi = __gdtoa_multadd(mhi, 10, 0);
mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
ilim = ilim1;
}
}
if (ilim <= 0 && (mode == 3 || mode == 5)) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0)) <= 0) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0,&TI)) <= 0) {
/* no digits, fcvt style */
no_digits:
k = -1 - ndigits;
@ -495,15 +496,15 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
}
if (leftright) {
if (m2 > 0)
mhi = __gdtoa_lshift(mhi, m2);
mhi = __gdtoa_lshift(mhi, m2, &TI);
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
*/
mlo = mhi;
if (spec_case) {
mhi = __gdtoa_Balloc(mhi->k);
mhi = __gdtoa_Balloc(mhi->k, &TI);
Bcopy(mhi, mlo);
mhi = __gdtoa_lshift(mhi, Log2P);
mhi = __gdtoa_lshift(mhi, Log2P, &TI);
}
for(i = 1;;i++) {
dig = __gdtoa_quorem(b,S) + '0';
@ -511,9 +512,9 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
* that will round to d?
*/
j = __gdtoa_cmp(b, mlo);
delta = __gdtoa_diff(S, mhi);
delta = __gdtoa_diff(S, mhi, &TI);
j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(delta, &TI);
if (j1 == 0 && mode != 1 && !(word1(&d) & 1) && Rounding >= 1) {
if (dig == '9')
goto round_9_up;
@ -533,7 +534,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
case 2: goto keep_dig;
}
if (j1 > 0) {
b = __gdtoa_lshift(b, 1);
b = __gdtoa_lshift(b, 1, &TI);
j1 = __gdtoa_cmp(b, S);
if ((j1 > 0 || (j1 == 0 && dig & 1))
&& dig++ == '9')
@ -558,12 +559,12 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
*s++ = dig;
if (i == ilim)
break;
b = __gdtoa_multadd(b, 10, 0);
b = __gdtoa_multadd(b, 10, 0, &TI);
if (mlo == mhi)
mlo = mhi = __gdtoa_multadd(mhi, 10, 0);
mlo = mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
else {
mlo = __gdtoa_multadd(mlo, 10, 0);
mhi = __gdtoa_multadd(mhi, 10, 0);
mlo = __gdtoa_multadd(mlo, 10, 0, &TI);
mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
}
}
}
@ -575,7 +576,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
}
if (i >= ilim)
break;
b = __gdtoa_multadd(b, 10, 0);
b = __gdtoa_multadd(b, 10, 0, &TI);
}
}
@ -584,7 +585,7 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
case 0: goto trimzeros;
case 2: goto roundoff;
}
b = __gdtoa_lshift(b, 1);
b = __gdtoa_lshift(b, 1, &TI);
j = __gdtoa_cmp(b, S);
if (j > 0 || (j == 0 && dig & 1))
{
@ -603,17 +604,17 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
s++;
}
ret:
__gdtoa_Bfree(S);
__gdtoa_Bfree(S, &TI);
if (mhi) {
if (mlo && mlo != mhi)
__gdtoa_Bfree(mlo);
__gdtoa_Bfree(mhi);
__gdtoa_Bfree(mlo, &TI);
__gdtoa_Bfree(mhi, &TI);
}
retc:
while(s > s0 && s[-1] == '0')
--s;
ret1:
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, &TI);
*s = 0;
*decpt = k + 1;
if (rve)

View file

@ -42,6 +42,7 @@ g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z;
U *dd, ddx[2];
ThInfo *TI = 0;
if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0;
dd = (U*)dd0;
@ -84,31 +85,31 @@ g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
dd = ddx;
L = dd->L;
}
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx);
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx, &TI);
if (dval(&dd[1]) == 0.)
goto no_y;
x = z;
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by);
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by, &TI);
if ( (i = ex - ey) !=0) {
if (i > 0) {
x = __gdtoa_lshift(x, i);
x = __gdtoa_lshift(x, i, &TI);
ex = ey;
}
else
y = __gdtoa_lshift(y, -i);
y = __gdtoa_lshift(y, -i, &TI);
}
if ((L[1] ^ L[2+1]) & 0x80000000L) {
z = __gdtoa_diff(x, y);
z = __gdtoa_diff(x, y, &TI);
if (L[1] & 0x80000000L)
z->sign = 1 - z->sign;
}
else {
z = __gdtoa_sum(x, y);
z = __gdtoa_sum(x, y, &TI);
if (L[1] & 0x80000000L)
z->sign = 1;
}
__gdtoa_Bfree(x);
__gdtoa_Bfree(y);
__gdtoa_Bfree(x, &TI);
__gdtoa_Bfree(y, &TI);
no_y:
bits = zx = z->x;
for(i = 0; !*zx; zx++)
@ -132,7 +133,7 @@ no_y:
mode = 2;
if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
__gdtoa_Bfree(z);
__gdtoa_Bfree(z, &TI);
return 0;
}
mode = 0;
@ -145,6 +146,6 @@ no_y:
i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize);
__gdtoa_Bfree(z);
__gdtoa_Bfree(z, &TI);
return b;
}

View file

@ -45,6 +45,7 @@ g_ddfmt_p(char *buf, double *dd0, int ndig, size_t bufsize, int nik)
int bx, by, decpt, ex, ey, i, j, mode;
Bigint *x, *y, *z;
U *dd, ddx[2];
ThInfo *TI = 0;
if (bufsize < 10 || bufsize < (size_t)(ndig + 8))
return 0;
dd = (U*)dd0;
@ -105,31 +106,31 @@ g_ddfmt_p(char *buf, double *dd0, int ndig, size_t bufsize, int nik)
dd = ddx;
L = dd->L;
}
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx);
z = __gdtoa_d2b(dval(&dd[0]), &ex, &bx, &TI);
if (dval(&dd[1]) == 0.)
goto no_y;
x = z;
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by);
y = __gdtoa_d2b(dval(&dd[1]), &ey, &by, &TI);
if ( (i = ex - ey) !=0) {
if (i > 0) {
x = __gdtoa_lshift(x, i);
x = __gdtoa_lshift(x, i, &TI);
ex = ey;
}
else
y = __gdtoa_lshift(y, -i);
y = __gdtoa_lshift(y, -i, &TI);
}
if ((L[1] ^ L[2+1]) & 0x80000000L) {
z = __gdtoa_diff(x, y);
z = __gdtoa_diff(x, y, &TI);
if (L[1] & 0x80000000L)
z->sign = 1 - z->sign;
}
else {
z = __gdtoa_sum(x, y);
z = __gdtoa_sum(x, y, &TI);
if (L[1] & 0x80000000L)
z->sign = 1;
}
__gdtoa_Bfree(x);
__gdtoa_Bfree(y);
__gdtoa_Bfree(x, &TI);
__gdtoa_Bfree(y, &TI);
no_y:
bits = zx = z->x;
for(i = 0; !*zx; zx++)
@ -153,7 +154,7 @@ no_y:
mode = 2;
if (ndig <= 0) {
if (bufsize < (size_t)(fpi.nbits * .301029995664) + 10) {
__gdtoa_Bfree(z);
__gdtoa_Bfree(z, &TI);
return 0;
}
mode = 0;
@ -166,6 +167,6 @@ no_y:
i = STRTOG_Normal;
s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
b = __gdtoa_g__fmt(buf, s, se, decpt, z->sign, bufsize);
__gdtoa_Bfree(z);
__gdtoa_Bfree(z, &TI);
return b;
}

View file

@ -33,7 +33,7 @@
/* clang-format off */
static Bigint *
bitstob(ULong *bits, int nbits, int *bbits)
bitstob(ULong *bits, int nbits, int *bbits, ThInfo **PTI)
{
int i, k;
Bigint *b;
@ -44,7 +44,7 @@ bitstob(ULong *bits, int nbits, int *bbits)
i <<= 1;
k++;
}
b = __gdtoa_Balloc(k);
b = __gdtoa_Balloc(k, PTI);
be = bits + ((nbits - 1) >> kshift);
x = x0 = b->x;
do {
@ -135,6 +135,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
to hold the suppressed trailing zeros.
*/
ThInfo *TI = 0;
int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
int rdir, s2, s5, spec_case, try_quick;
@ -153,14 +154,14 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
break;
case STRTOG_Infinite:
*decpt = -32768;
return __gdtoa_nrv_alloc("Infinity", rve, 8);
return __gdtoa_nrv_alloc("Infinity", rve, 8, &TI);
case STRTOG_NaN:
*decpt = -32768;
return __gdtoa_nrv_alloc("NaN", rve, 3);
return __gdtoa_nrv_alloc("NaN", rve, 3, &TI);
default:
return 0;
}
b = bitstob(bits, nbits = fpi->nbits, &bbits);
b = bitstob(bits, nbits = fpi->nbits, &bbits, &TI);
be0 = be;
if ( (i = __gdtoa_trailz(b)) !=0) {
__gdtoa_rshift(b, i);
@ -168,10 +169,10 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
bbits -= i;
}
if (!b->wds) {
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, &TI);
ret_zero:
*decpt = 1;
return __gdtoa_nrv_alloc("0", rve, 1);
return __gdtoa_nrv_alloc("0", rve, 1, &TI);
}
dval(&d) = __gdtoa_b2d(b, &i);
i = be + bbits - 1;
@ -285,7 +286,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
if (i <= 0)
i = 1;
}
s = s0 = __gdtoa_rv_alloc(i);
s = s0 = __gdtoa_rv_alloc(i, &TI);
if (mode <= 1)
rdir = 0;
else if ( (rdir = fpi->rounding - 1) !=0) {
@ -471,7 +472,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
}
b2 += i;
s2 += i;
mhi = __gdtoa_i2b(1);
mhi = __gdtoa_i2b(1, &TI);
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
@ -482,20 +483,20 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mhi = __gdtoa_pow5mult(mhi, m5);
b1 = __gdtoa_mult(mhi, b);
__gdtoa_Bfree(b);
mhi = __gdtoa_pow5mult(mhi, m5, &TI);
b1 = __gdtoa_mult(mhi, b, &TI);
__gdtoa_Bfree(b, &TI);
b = b1;
}
if ( (j = b5 - m5) !=0)
b = __gdtoa_pow5mult(b, j);
b = __gdtoa_pow5mult(b, j, &TI);
}
else
b = __gdtoa_pow5mult(b, b5);
b = __gdtoa_pow5mult(b, b5, &TI);
}
S = __gdtoa_i2b(1);
S = __gdtoa_i2b(1, &TI);
if (s5 > 0)
S = __gdtoa_pow5mult(S, s5);
S = __gdtoa_pow5mult(S, s5, &TI);
/* Check for special case that d is a normalized power of 2. */
spec_case = 0;
if (mode < 2) {
@ -516,20 +517,20 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
m2 += i;
if ((b2 += i) > 0)
b = __gdtoa_lshift(b, b2);
b = __gdtoa_lshift(b, b2, &TI);
if ((s2 += i) > 0)
S = __gdtoa_lshift(S, s2);
S = __gdtoa_lshift(S, s2, &TI);
if (k_check) {
if (__gdtoa_cmp(b,S) < 0) {
k--;
b = __gdtoa_multadd(b, 10, 0); /* we botched the k estimate */
b = __gdtoa_multadd(b, 10, 0, &TI); /* we botched the k estimate */
if (leftright)
mhi = __gdtoa_multadd(mhi, 10, 0);
mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
ilim = ilim1;
}
}
if (ilim <= 0 && mode > 2) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0)) <= 0) {
if (ilim < 0 || __gdtoa_cmp(b,S = __gdtoa_multadd(S,5,0,&TI)) <= 0) {
/* no digits, fcvt style */
no_digits:
k = -1 - ndigits;
@ -544,15 +545,15 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
}
if (leftright) {
if (m2 > 0)
mhi = __gdtoa_lshift(mhi, m2);
mhi = __gdtoa_lshift(mhi, m2, &TI);
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
*/
mlo = mhi;
if (spec_case) {
mhi = __gdtoa_Balloc(mhi->k);
mhi = __gdtoa_Balloc(mhi->k, &TI);
Bcopy(mhi, mlo);
mhi = __gdtoa_lshift(mhi, 1);
mhi = __gdtoa_lshift(mhi, 1, &TI);
}
for(i = 1;;i++) {
dig = __gdtoa_quorem(b,S) + '0';
@ -560,9 +561,9 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
* that will round to d?
*/
j = __gdtoa_cmp(b, mlo);
delta = __gdtoa_diff(S, mhi);
delta = __gdtoa_diff(S, mhi, &TI);
j1 = delta->sign ? 1 : __gdtoa_cmp(b, delta);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(delta, &TI);
if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
if (dig == '9')
goto round_9_up;
@ -585,11 +586,11 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
}
while (__gdtoa_cmp(S,mhi) > 0) {
*s++ = dig;
mhi1 = __gdtoa_multadd(mhi, 10, 0);
mhi1 = __gdtoa_multadd(mhi, 10, 0, &TI);
if (mlo == mhi)
mlo = mhi1;
mhi = mhi1;
b = __gdtoa_multadd(b, 10, 0);
b = __gdtoa_multadd(b, 10, 0, &TI);
dig = __gdtoa_quorem(b,S) + '0';
}
if (dig++ == '9')
@ -598,7 +599,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
goto accept;
}
if (j1 > 0) {
b = __gdtoa_lshift(b, 1);
b = __gdtoa_lshift(b, 1, &TI);
j1 = __gdtoa_cmp(b, S);
if ((j1 > 0 || (j1 == 0 && dig & 1)) && dig++ == '9')
goto round_9_up;
@ -624,12 +625,12 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
*s++ = dig;
if (i == ilim)
break;
b = __gdtoa_multadd(b, 10, 0);
b = __gdtoa_multadd(b, 10, 0, &TI);
if (mlo == mhi)
mlo = mhi = __gdtoa_multadd(mhi, 10, 0);
mlo = mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
else {
mlo = __gdtoa_multadd(mlo, 10, 0);
mhi = __gdtoa_multadd(mhi, 10, 0);
mlo = __gdtoa_multadd(mlo, 10, 0, &TI);
mhi = __gdtoa_multadd(mhi, 10, 0, &TI);
}
}
}
@ -638,7 +639,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
*s++ = dig = __gdtoa_quorem(b,S) + '0';
if (i >= ilim)
break;
b = __gdtoa_multadd(b, 10, 0);
b = __gdtoa_multadd(b, 10, 0, &TI);
}
/* Round off last digit */
if (rdir) {
@ -646,7 +647,7 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
goto chopzeros;
goto roundoff;
}
b = __gdtoa_lshift(b, 1);
b = __gdtoa_lshift(b, 1, &TI);
j = __gdtoa_cmp(b, S);
if (j > 0 || (j == 0 && dig & 1))
{
@ -666,16 +667,16 @@ gdtoa(const FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, in
inex = STRTOG_Inexlo;
}
ret:
__gdtoa_Bfree(S);
__gdtoa_Bfree(S, &TI);
if (mhi) {
if (mlo && mlo != mhi)
__gdtoa_Bfree(mlo);
__gdtoa_Bfree(mhi);
__gdtoa_Bfree(mlo, &TI);
__gdtoa_Bfree(mhi, &TI);
}
ret1:
while(s > s0 && s[-1] == '0')
--s;
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, &TI);
*s = 0;
*decpt = k + 1;
if (rve)

View file

@ -355,35 +355,37 @@ hidden extern const unsigned char __gdtoa_hexdig[];
hidden extern const char *const __gdtoa_InfName[6];
hidden extern const char *const __gdtoa_NanName[3];
Bigint *__gdtoa_Balloc(int);
Bigint *__gdtoa_d2b(double, int *, int *);
Bigint *__gdtoa_diff(Bigint *, Bigint *);
Bigint *__gdtoa_i2b(int);
Bigint *__gdtoa_increment(Bigint *);
Bigint *__gdtoa_lshift(Bigint *, int);
Bigint *__gdtoa_mult(Bigint *, Bigint *);
Bigint *__gdtoa_multadd(Bigint *, int, int);
Bigint *__gdtoa_s2b(const char *, int, int, ULong, int);
Bigint *__gdtoa_set_ones(Bigint *, int);
Bigint *__gdtoa_sum(Bigint *, Bigint *);
Bigint *__gdtoa_pow5mult(Bigint *, int);
Bigint *__gdtoa_Balloc(int, ThInfo **);
void __gdtoa_Bfree(Bigint *, ThInfo **);
Bigint *__gdtoa_d2b(double, int *, int *, ThInfo **);
Bigint *__gdtoa_diff(Bigint *, Bigint *, ThInfo **);
int __gdtoa_gethex(const char **, const FPI *, int *, Bigint **, int,
ThInfo **);
Bigint *__gdtoa_i2b(int, ThInfo **);
Bigint *__gdtoa_increment(Bigint *, ThInfo **);
Bigint *__gdtoa_lshift(Bigint *, int, ThInfo **);
Bigint *__gdtoa_mult(Bigint *, Bigint *, ThInfo **);
Bigint *__gdtoa_multadd(Bigint *, int, int, ThInfo **);
char *__gdtoa_nrv_alloc(char *, char **, int, ThInfo **);
char *__gdtoa_rv_alloc(int, ThInfo **);
Bigint *__gdtoa_pow5mult(Bigint *, int, ThInfo **);
Bigint *__gdtoa_s2b(const char *, int, int, ULong, int, ThInfo **);
Bigint *__gdtoa_set_ones(Bigint *, int, ThInfo **);
Bigint *__gdtoa_sum(Bigint *, Bigint *, ThInfo **);
ULong __gdtoa_any_on(Bigint *, int);
char *__gdtoa_add_nanbits(char *, size_t, ULong *, int);
char *__gdtoa_g__fmt(char *, char *, char *, int, ULong, size_t);
char *__gdtoa_nrv_alloc(char *, char **, int);
char *__gdtoa_rv_alloc(int);
double __gdtoa_b2d(Bigint *, int *);
double __gdtoa_ratio(Bigint *, Bigint *);
double __gdtoa_ulp(U *);
int __gdtoa_cmp(Bigint *, Bigint *);
int __gdtoa_gethex(const char **, const FPI *, Long *, Bigint **, int);
int __gdtoa_hexnan(const char **, const FPI *, ULong *);
int __gdtoa_match(const char **, char *);
int __gdtoa_quorem(Bigint *, Bigint *);
int __gdtoa_strtoIg(const char *, char **, const FPI *, Long *, Bigint **,
int *);
int __gdtoa_trailz(Bigint *);
void __gdtoa_Bfree(Bigint *);
void __gdtoa_ULtoQ(ULong *, ULong *, Long, int);
void __gdtoa_ULtod(ULong *, ULong *, Long, int);
void __gdtoa_ULtodd(ULong *, ULong *, Long, int);

View file

@ -35,7 +35,7 @@
int
__gdtoa_gethex(const char **sp, const FPI *fpi,
Long *exp, Bigint **bp, int sign)
Long *exp, Bigint **bp, int sign, ThInfo **PTI)
{
Bigint *b;
const unsigned char *decpt, *s0, *s, *s1;
@ -124,7 +124,7 @@ pcheck:
}
goto retz;
ret_tiny:
b = __gdtoa_Balloc(0);
b = __gdtoa_Balloc(0, PTI);
b->wds = 1;
b->x[0] = 1;
goto dret;
@ -146,7 +146,7 @@ pcheck:
if (nbits & kmask)
++n;
for(j = n, k = 0; j >>= 1; ++k);
*bp = b = __gdtoa_Balloc(k);
*bp = b = __gdtoa_Balloc(k, PTI);
b->wds = n;
for(j = 0; j < n0; ++j)
b->x[j] = ALL_ON;
@ -158,7 +158,7 @@ pcheck:
n = s1 - s0 - 1;
for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
k++;
b = __gdtoa_Balloc(k);
b = __gdtoa_Balloc(k, PTI);
x = b->x;
n = 0;
L = 0;
@ -195,13 +195,13 @@ pcheck:
}
else if (n < nbits) {
n = nbits - n;
b = __gdtoa_lshift(b, n);
b = __gdtoa_lshift(b, n, PTI);
e -= n;
x = b->x;
}
if (e > fpi->emax) {
ovfl:
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, PTI);
ovfl1:
errno = ERANGE;
switch (fpi->rounding) {
@ -243,7 +243,7 @@ pcheck:
| STRTOG_Underflow;
}
}
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, PTI);
retz:
errno = ERANGE;
return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
@ -277,7 +277,7 @@ pcheck:
}
if (up) {
k = b->wds;
b = __gdtoa_increment(b);
b = __gdtoa_increment(b, PTI);
x = b->x;
if (irv == STRTOG_Denormal) {
if (nbits == fpi->nbits - 1

View file

@ -20,6 +20,7 @@
#include "third_party/gdtoa/lock.h"
static pthread_mutex_t __gdtoa_lock_obj;
static pthread_mutex_t __gdtoa_lock1_obj;
int(__gdtoa_lock)(void) {
return pthread_mutex_lock(&__gdtoa_lock_obj);
@ -28,3 +29,11 @@ int(__gdtoa_lock)(void) {
int(__gdtoa_unlock)(void) {
return pthread_mutex_unlock(&__gdtoa_lock_obj);
}
int(__gdtoa_lock1)(void) {
return pthread_mutex_lock(&__gdtoa_lock1_obj);
}
int(__gdtoa_unlock1)(void) {
return pthread_mutex_unlock(&__gdtoa_lock1_obj);
}

View file

@ -7,13 +7,19 @@ COSMOPOLITAN_C_START_
int __gdtoa_lock(void);
int __gdtoa_unlock(void);
int __gdtoa_lock1(void);
int __gdtoa_unlock1(void);
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__STRICT_ANSI__)
#define __gdtoa_lock() _NOPL0("__threadcalls", __gdtoa_lock)
#define __gdtoa_unlock() _NOPL0("__threadcalls", __gdtoa_unlock)
#define __gdtoa_lock() _NOPL0("__threadcalls", __gdtoa_lock)
#define __gdtoa_unlock() _NOPL0("__threadcalls", __gdtoa_unlock)
#define __gdtoa_lock1() _NOPL0("__threadcalls", __gdtoa_lock1)
#define __gdtoa_unlock1() _NOPL0("__threadcalls", __gdtoa_unlock1)
#else
#define __gdtoa_lock() (__threaded ? __gdtoa_lock() : 0)
#define __gdtoa_unlock() (__threaded ? __gdtoa_unlock() : 0)
#define __gdtoa_lock() (__threaded ? __gdtoa_lock() : 0)
#define __gdtoa_unlock() (__threaded ? __gdtoa_unlock() : 0)
#define __gdtoa_lock1() (__threaded ? __gdtoa_lock1() : 0)
#define __gdtoa_unlock1() (__threaded ? __gdtoa_unlock1() : 0)
#endif
COSMOPOLITAN_C_END_

View file

@ -30,6 +30,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "third_party/gdtoa/gdtoa.internal.h"
@ -62,69 +63,80 @@ __attribute__((__constructor__)) static void
__gdtoa_Binit(void)
{
atexit(__gdtoa_Bclear);
TI0.P5s = __gdtoa_i2b(625);
TI0.P5s->next = 0;
}
static ThInfo *
__gdtoa_get_TI(void)
{
return &TI0;
}
Bigint *
__gdtoa_Balloc(int k)
__gdtoa_Balloc(int k, ThInfo **PTI)
{
int x;
Bigint *rv;
assert(k >= 0);
__gdtoa_lock();
if (k <= Kmax && (rv = TI0.Freelist[k]) != 0) {
TI0.Freelist[k] = rv->next;
unsigned int len;
ThInfo *TI;
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock();
if (k <= Kmax && (rv = TI->Freelist[k]) != 0) {
TI->Freelist[k] = rv->next;
} else {
x = 1 << k;
rv = malloc(sizeof(Bigint) + (x-1)*sizeof(ULong));
rv->k = k;
rv->maxwds = x;
}
rv->sign = 0;
rv->wds = 0;
__gdtoa_unlock();
if (TI == &TI0)
__gdtoa_unlock();
rv->sign = rv->wds = 0;
return rv;
}
void
__gdtoa_Bfree(Bigint *v)
__gdtoa_Bfree(Bigint *v, ThInfo **PTI)
{
ThInfo *TI;
if (v) {
if (v->k > Kmax) {
free(v);
} else {
assert(v->k >= 0);
__gdtoa_lock();
v->next = TI0.Freelist[v->k];
TI0.Freelist[v->k] = v;
__gdtoa_unlock();
if (v->k > Kmax)
free((void *)v);
else {
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock();
v->next = TI->Freelist[v->k];
TI->Freelist[v->k] = v;
if (TI == &TI0)
__gdtoa_unlock();
}
}
}
Bigint * /* multiply by m and add a */
__gdtoa_multadd(Bigint *b, int m, int a)
Bigint *
__gdtoa_multadd(Bigint *b, int m, int a, ThInfo **PTI)
{
int i, wds;
ULong *x;
ULLong carry, y;
uint64_t carry, y;
Bigint *b1;
wds = b->wds;
x = b->x;
i = 0;
carry = a;
do {
y = *x * (ULLong)m + carry;
y = *x * (uint64_t)m + carry;
carry = y >> 32;
*x++ = y & 0xffffffffUL;
}
while(++i < wds);
} while (++i < wds);
if (carry) {
if (wds >= b->maxwds) {
b1 = __gdtoa_Balloc(b->k+1);
Bcopy(b1, b);
__gdtoa_Bfree(b);
b1 = __gdtoa_Balloc(b->k + 1, PTI);
memcpy(&b1->sign, &b->sign, b->wds * sizeof(ULong) + 2 * sizeof(int));
__gdtoa_Bfree(b, PTI);
b = b1;
}
b->x[wds++] = carry;
@ -134,23 +146,23 @@ __gdtoa_multadd(Bigint *b, int m, int a)
}
Bigint *
__gdtoa_i2b(int i)
__gdtoa_i2b(int i, ThInfo **PTI)
{
Bigint *b;
b = __gdtoa_Balloc(1);
b = __gdtoa_Balloc(1, PTI);
b->x[0] = i;
b->wds = 1;
return b;
}
Bigint *
__gdtoa_mult(Bigint *a, Bigint *b)
__gdtoa_mult(Bigint *a, Bigint *b, ThInfo **PTI)
{
Bigint *c;
int k, wa, wb, wc;
ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
ULong y;
ULLong carry, z;
uint64_t carry, z;
if (a->wds < b->wds) {
c = a;
a = b;
@ -162,96 +174,115 @@ __gdtoa_mult(Bigint *a, Bigint *b)
wc = wa + wb;
if (wc > a->maxwds)
k++;
c = __gdtoa_Balloc(k);
for(x = c->x, xa = x + wc; x < xa; x++)
c = __gdtoa_Balloc(k, PTI);
for (x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
xae = xa + wa;
xb = b->x;
xbe = xb + wb;
xc0 = c->x;
for(; xb < xbe; xc0++) {
if ( (y = *xb++) !=0) {
for (; xb < xbe; xc0++) {
if ((y = *xb++) != 0) {
x = xa;
xc = xc0;
carry = 0;
do {
z = *x++ * (ULLong)y + *xc + carry;
z = *x++ * (uint64_t)y + *xc + carry;
carry = z >> 32;
*xc++ = z & 0xffffffffUL;
}
while(x < xae);
} while (x < xae);
*xc = carry;
}
}
for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc)
;
c->wds = wc;
return c;
}
Bigint *
__gdtoa_pow5mult(Bigint *b, int k)
__gdtoa_pow5mult(Bigint *b, int k, ThInfo **PTI)
{
int i;
Bigint *b1, *p5, *p51;
static const int p05[3] = { 5, 25, 125 };
if ((i = k & 3))
b = __gdtoa_multadd(b, p05[i-1], 0);
ThInfo *TI;
int i;
static int p05[3] = {5, 25, 125};
if ((i = k & 3) != 0)
b = __gdtoa_multadd(b, p05[i - 1], 0, PTI);
if (!(k >>= 2))
return b;
__gdtoa_lock();
p5 = TI0.P5s;
for(;;) {
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if ((p5 = TI->P5s) == 0) {
if (!(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock1();
if (!(p5 = TI->P5s)) {
p5 = TI->P5s = __gdtoa_i2b(625, PTI);
p5->next = 0;
}
if (TI == &TI0)
__gdtoa_unlock1();
}
for (;;) {
if (k & 1) {
b1 = __gdtoa_mult(b, p5);
__gdtoa_Bfree(b);
b1 = __gdtoa_mult(b, p5, PTI);
__gdtoa_Bfree(b, PTI);
b = b1;
}
if (!(k >>= 1))
break;
if ((p51 = p5->next) == 0) {
p51 = p5->next = __gdtoa_mult(p5,p5);
p51->next = 0;
if (!TI && !(TI = *PTI))
*PTI = TI = __gdtoa_get_TI();
if (TI == &TI0)
__gdtoa_lock1();
if (!(p51 = p5->next)) {
p51 = p5->next = __gdtoa_mult(p5, p5, PTI);
p51->next = 0;
}
if (TI == &TI0)
__gdtoa_unlock1();
}
p5 = p51;
}
__gdtoa_unlock();
return b;
}
Bigint *
__gdtoa_lshift(Bigint *b, int k)
__gdtoa_lshift(Bigint *b, int k, ThInfo **PTI)
{
int i, k1, n, n1;
Bigint *b1;
ULong *x, *x1, *xe, z;
n = k >> kshift;
n = k >> 5;
k1 = b->k;
n1 = n + b->wds + 1;
for(i = b->maxwds; n1 > i; i <<= 1)
for (i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = __gdtoa_Balloc(k1);
b1 = __gdtoa_Balloc(k1, PTI);
x1 = b1->x;
for(i = 0; i < n; i++)
for (i = 0; i < n; i++)
*x1++ = 0;
x = b->x;
xe = x + b->wds;
if (k &= kmask) {
if (k &= 31) {
k1 = 32 - k;
z = 0;
do {
*x1++ = *x << k | z;
z = *x++ >> k1;
}
while(x < xe);
if ((*x1 = z) !=0)
} while (x < xe);
if ((*x1 = z) != 0)
++n1;
}
else do
*x1++ = *x++;
while(x < xe);
} else
do
*x1++ = *x++;
while (x < xe);
b1->wds = n1 - 1;
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, PTI);
return b1;
}
@ -262,19 +293,13 @@ __gdtoa_cmp(Bigint *a, Bigint *b)
int i, j;
i = a->wds;
j = b->wds;
#ifdef DEBUG
if (i > 1 && !a->x[i-1])
Bug("__gdtoa_cmp called with a->x[a->wds-1] == 0");
if (j > 1 && !b->x[j-1])
Bug("__gdtoa_cmp called with b->x[b->wds-1] == 0");
#endif
if (i -= j)
return i;
xa0 = a->x;
xa = xa0 + j;
xb0 = b->x;
xb = xb0 + j;
for(;;) {
for (;;) {
if (*--xa != *--xb)
return *xa < *xb ? -1 : 1;
if (xa <= xa0)
@ -284,15 +309,15 @@ __gdtoa_cmp(Bigint *a, Bigint *b)
}
Bigint *
__gdtoa_diff(Bigint *a, Bigint *b)
__gdtoa_diff(Bigint *a, Bigint *b, ThInfo **PTI)
{
Bigint *c;
int i, wa, wb;
ULong *xa, *xae, *xb, *xbe, *xc;
ULLong borrow, y;
i = __gdtoa_cmp(a,b);
uint64_t borrow, y;
i = __gdtoa_cmp(a, b);
if (!i) {
c = __gdtoa_Balloc(0);
c = __gdtoa_Balloc(0, PTI);
c->wds = 1;
c->x[0] = 0;
return c;
@ -302,10 +327,9 @@ __gdtoa_diff(Bigint *a, Bigint *b)
a = b;
b = c;
i = 1;
}
else
} else
i = 0;
c = __gdtoa_Balloc(a->k);
c = __gdtoa_Balloc(a->k, PTI);
c->sign = i;
wa = a->wds;
xa = a->x;
@ -316,17 +340,16 @@ __gdtoa_diff(Bigint *a, Bigint *b)
xc = c->x;
borrow = 0;
do {
y = (ULLong)*xa++ - *xb++ - borrow;
y = (uint64_t)*xa++ - *xb++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = y & 0xffffffffUL;
}
while(xb < xbe);
while(xa < xae) {
} while (xb < xbe);
while (xa < xae) {
y = *xa++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = y & 0xffffffffUL;
}
while(!*--xc)
while (!*--xc)
wa--;
c->wds = wa;
return c;
@ -341,33 +364,29 @@ __gdtoa_b2d(Bigint *a, int *e)
xa0 = a->x;
xa = xa0 + a->wds;
y = *--xa;
#ifdef DEBUG
if (!y) Bug("zero y in __gdtoa_b2d");
#endif
k = hi0bits(y);
k = hi0bits((ULong)(y));
*e = 32 - k;
if (k < Ebits) {
word0(&d) = Exp_1 | y >> (Ebits - k);
if (k < 11) {
(&d)->L[1] = 0x3ff00000 | y >> (11 - k);
w = xa > xa0 ? *--xa : 0;
word1(&d) = y << ((32-Ebits) + k) | w >> (Ebits - k);
(&d)->L[0] = y << ((32 - 11) + k) | w >> (11 - k);
goto ret_d;
}
z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) {
word0(&d) = Exp_1 | y << k | z >> (32 - k);
if (k -= 11) {
(&d)->L[1] = 0x3ff00000 | y << k | z >> (32 - k);
y = xa > xa0 ? *--xa : 0;
word1(&d) = z << k | y >> (32 - k);
}
else {
word0(&d) = Exp_1 | y;
word1(&d) = z;
(&d)->L[0] = z << k | y >> (32 - k);
} else {
(&d)->L[1] = 0x3ff00000 | y;
(&d)->L[0] = z;
}
ret_d:
return dval(&d);
return (&d)->d;
}
Bigint *
__gdtoa_d2b(double dd, int *e, int *bits)
__gdtoa_d2b(double dd, int *e, int *bits, ThInfo **PTI)
{
Bigint *b;
U d;
@ -375,47 +394,37 @@ __gdtoa_d2b(double dd, int *e, int *bits)
int de, k;
ULong *x, y, z;
d.d = dd;
b = __gdtoa_Balloc(1);
b = __gdtoa_Balloc(1, PTI);
x = b->x;
z = word0(&d) & Frac_mask;
word0(&d) &= 0x7fffffff; /* clear sign bit, which we ignore */
if ( (de = (int)(word0(&d) >> Exp_shift)) !=0)
z |= Exp_msk1;
if ( (y = word1(&d)) !=0) {
if ( (k = lo0bits(&y)) !=0) {
z = (&d)->L[1] & 0xfffff;
(&d)->L[1] &= 0x7fffffff;
if ((de = (int)((&d)->L[1] >> 20)) != 0)
z |= 0x100000;
if ((y = (&d)->L[0]) != 0) {
if ((k = lo0bits(&y)) != 0) {
x[0] = y | z << (32 - k);
z >>= k;
}
else
} else
x[0] = y;
i = b->wds = (x[1] = z) !=0 ? 2 : 1;
}
else {
i = b->wds = (x[1] = z) != 0 ? 2 : 1;
} else {
k = lo0bits(&z);
x[0] = z;
i = b->wds = 1;
k += 32;
}
if (de) {
*e = de - Bias - (P-1) + k;
*bits = P - k;
}
else {
*e = de - Bias - (P-1) + 1 + k;
*bits = 32*i - hi0bits(x[i-1]);
*e = de - 1023 - (53 - 1) + k;
*bits = 53 - k;
} else {
*e = de - 1023 - (53 - 1) + 1 + k;
*bits = 32 * i - hi0bits((ULong)(x[i - 1]));
}
return b;
}
const double
__gdtoa_bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
const double
__gdtoa_tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
const double
__gdtoa_tens[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
};
const double __gdtoa_bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256};
const double __gdtoa_tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128, 1e-256};
const double __gdtoa_tens[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};

View file

@ -33,27 +33,27 @@
/* clang-format off */
Bigint *
__gdtoa_s2b(const char *s, int nd0, int nd, ULong y9, int dplen)
__gdtoa_s2b(const char *s, int nd0, int nd, ULong y9, int dplen, ThInfo **PTI)
{
Bigint *b;
int i, k;
Long x, y;
x = (nd + 8) / 9;
for(k = 0, y = 1; x > y; y <<= 1, k++) ;
b = __gdtoa_Balloc(k);
b = __gdtoa_Balloc(k, PTI);
b->x[0] = y9;
b->wds = 1;
i = 9;
if (9 < nd0) {
s += 9;
do b = __gdtoa_multadd(b, 10, *s++ - '0');
do b = __gdtoa_multadd(b, 10, *s++ - '0', PTI);
while(++i < nd0);
s += dplen;
}
else
s += dplen + 9;
for(; i < nd; i++)
b = __gdtoa_multadd(b, 10, *s++ - '0');
b = __gdtoa_multadd(b, 10, *s++ - '0', PTI);
return b;
}

View file

@ -39,14 +39,15 @@ strtoId(const char *s, char **sp, double *f0, double *f1)
Long exp[2];
Bigint *B[2];
int k, rv[2];
B[0] = __gdtoa_Balloc(1);
ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(1, &TI);
B[0]->wds = 2;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]);
__gdtoa_Bfree(B[0], &TI);
if (B[1]) {
__gdtoa_ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]);
__gdtoa_Bfree(B[1], &TI);
}
else {
((ULong*)f1)[0] = ((ULong*)f0)[0];

View file

@ -39,14 +39,15 @@ strtoIdd(const char *s, char **sp, double *f0, double *f1)
Long exp[2];
Bigint *B[2];
int k, rv[2];
B[0] = __gdtoa_Balloc(2);
ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(2, &TI);
B[0]->wds = 4;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]);
__gdtoa_Bfree(B[0], &TI);
if (B[1]) {
__gdtoa_ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]);
__gdtoa_Bfree(B[1], &TI);
}
else {
((ULong*)f1)[0] = ((ULong*)f0)[0];

View file

@ -39,14 +39,15 @@ strtoIf(const char *s, char **sp, float *f0, float *f1)
Long exp[2];
Bigint *B[2];
int k, rv[2];
B[0] = __gdtoa_Balloc(0);
ThInfo *TI = 0;
B[0] = __gdtoa_Balloc(0, &TI);
B[0]->wds = 1;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]);
__gdtoa_Bfree(B[0], &TI);
if (B[1]) {
__gdtoa_ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]);
__gdtoa_Bfree(B[1], &TI);
}
else
*(ULong*)f1 = *(ULong*)f0;

View file

@ -39,6 +39,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
int i, nb, nw, nw1, rv, rv1, swap;
unsigned int nb1, nb11;
Long e1;
ThInfo *TI = 0;
b = *B;
rv = strtodg(s00, se, fpi, exp, b->x);
if (!(rv & STRTOG_Inexact)) {
@ -47,7 +48,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
}
e1 = exp[0];
rv1 = rv ^ STRTOG_Inexact;
b1 = __gdtoa_Balloc(b->k);
b1 = __gdtoa_Balloc(b->k, &TI);
Bcopy(b1, b);
nb = fpi->nbits;
nb1 = nb & 31;
@ -56,7 +57,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
nw1 = nw - 1;
if (rv & STRTOG_Inexlo) {
swap = 0;
b1 = __gdtoa_increment(b1);
b1 = __gdtoa_increment(b1, &TI);
if ((rv & STRTOG_Retmask) == STRTOG_Zero) {
if (fpi->sudden_underflow) {
b1->x[0] = 0;
@ -85,7 +86,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
else {
swap = STRTOG_Neg;
if ((rv & STRTOG_Retmask) == STRTOG_Infinite) {
b1 = __gdtoa_set_ones(b1, nb);
b1 = __gdtoa_set_ones(b1, nb, &TI);
e1 = fpi->emax;
rv1 = STRTOG_Normal | STRTOG_Inexlo | (rv & STRTOG_Neg);
goto swapcheck;
@ -108,7 +109,7 @@ __gdtoa_strtoIg(const char *s00, char **se, const FPI *fpi, Long *exp, Bigint **
rv1 |= STRTOG_Underflow;
}
else {
b1 = __gdtoa_lshift(b1, 1);
b1 = __gdtoa_lshift(b1, 1, &TI);
b1->x[0] |= 1;
--e1;
}

View file

@ -39,15 +39,16 @@ strtoIx(const char *s, char **sp, void *a, void *b)
Long exp[2];
Bigint *B[2];
int k, rv[2];
ThInfo *TI = 0;
UShort *L = (UShort *)a, *M = (UShort *)b;
B[0] = __gdtoa_Balloc(1);
B[0] = __gdtoa_Balloc(1, &TI);
B[0]->wds = 2;
k = __gdtoa_strtoIg(s, sp, &fpi, exp, B, rv);
__gdtoa_ULtox(L, B[0]->x, exp[0], rv[0]);
__gdtoa_Bfree(B[0]);
__gdtoa_Bfree(B[0], &TI);
if (B[1]) {
__gdtoa_ULtox(M, B[1]->x, exp[1], rv[1]);
__gdtoa_Bfree(B[1]);
__gdtoa_Bfree(B[1], &TI);
}
else {
M[0] = L[0];

View file

@ -45,7 +45,7 @@ static const double tiny__gdtoa_tens[] = {
};
static double
s__gdtoa_ulp(U *x, int scale)
__gdtoa_sulp(U *x, int scale)
{
U u;
int i;
@ -61,6 +61,7 @@ s__gdtoa_ulp(U *x, int scale)
double
strtod(const char *s00, char **se)
{
ThInfo *TI = 0;
int scale;
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign,
e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
@ -107,7 +108,7 @@ break2:
{
FPI fpi1 = fpi;
fpi1.rounding = Rounding;
switch((i = __gdtoa_gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) {
switch((i = __gdtoa_gethex(&s, &fpi1, &exp, &bb, sign, &TI)) & STRTOG_Retmask) {
case STRTOG_NoNumber:
s = s00;
sign = 0;
@ -116,7 +117,7 @@ break2:
default:
if (bb) {
__gdtoa_copybits(bits, fpi.nbits, bb);
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bb, &TI);
}
__gdtoa_ULtod(((U*)&rv)->L, bits, exp, i);
}}
@ -328,11 +329,11 @@ dig_done:
}
range_err:
if (bd0) {
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bd);
__gdtoa_Bfree(bs);
__gdtoa_Bfree(bd0);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta, &TI);
}
errno = ERANGE;
goto ret;
@ -393,12 +394,12 @@ dig_done:
}
/* Now the hard part -- adjusting rv to the correct value.*/
/* Put digits into bd: true value = bd * 10^e */
bd0 = __gdtoa_s2b(s0, nd0, nd, y, dplen);
bd0 = __gdtoa_s2b(s0, nd0, nd, y, dplen, &TI);
for(;;) {
bd = __gdtoa_Balloc(bd0->k);
bd = __gdtoa_Balloc(bd0->k, &TI);
Bcopy(bd, bd0);
bb = __gdtoa_d2b(dval(&rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
bs = __gdtoa_i2b(1);
bb = __gdtoa_d2b(dval(&rv), &bbe, &bbbits, &TI); /* rv = bb * 2^bbe */
bs = __gdtoa_i2b(1, &TI);
if (e >= 0) {
bb2 = bb5 = 0;
bd2 = bd5 = e;
@ -439,20 +440,20 @@ dig_done:
bs2 -= i;
}
if (bb5 > 0) {
bs = __gdtoa_pow5mult(bs, bb5);
bb1 = __gdtoa_mult(bs, bb);
__gdtoa_Bfree(bb);
bs = __gdtoa_pow5mult(bs, bb5, &TI);
bb1 = __gdtoa_mult(bs, bb, &TI);
__gdtoa_Bfree(bb, &TI);
bb = bb1;
}
if (bb2 > 0)
bb = __gdtoa_lshift(bb, bb2);
bb = __gdtoa_lshift(bb, bb2, &TI);
if (bd5 > 0)
bd = __gdtoa_pow5mult(bd, bd5);
bd = __gdtoa_pow5mult(bd, bd5, &TI);
if (bd2 > 0)
bd = __gdtoa_lshift(bd, bd2);
bd = __gdtoa_lshift(bd, bd2, &TI);
if (bs2 > 0)
bs = __gdtoa_lshift(bs, bs2);
delta = __gdtoa_diff(bb, bd);
bs = __gdtoa_lshift(bs, bs2, &TI);
delta = __gdtoa_diff(bb, bd, &TI);
dsign = delta->sign;
delta->sign = 0;
i = __gdtoa_cmp(delta, bs);
@ -476,7 +477,7 @@ dig_done:
y = word0(&rv) & Exp_mask;
if (!scale || y > 2*P*Exp_msk1)
{
delta = __gdtoa_lshift(delta,Log2P);
delta = __gdtoa_lshift(delta,Log2P,&TI);
if (__gdtoa_cmp(delta, bs) <= 0)
dval(&adj) = -0.5;
}
@ -525,7 +526,7 @@ dig_done:
/* exact result */
break;
}
delta = __gdtoa_lshift(delta,Log2P);
delta = __gdtoa_lshift(delta,Log2P,&TI);
if (__gdtoa_cmp(delta, bs) > 0)
goto drop_down;
break;
@ -575,9 +576,9 @@ dig_done:
else if (!(word1(&rv) & Lsb))
break;
if (dsign)
dval(&rv) += s__gdtoa_ulp(&rv, scale);
dval(&rv) += __gdtoa_sulp(&rv, scale);
else {
dval(&rv) -= s__gdtoa_ulp(&rv, scale);
dval(&rv) -= __gdtoa_sulp(&rv, scale);
if (!dval(&rv))
goto undfl;
}
@ -661,16 +662,16 @@ dig_done:
break;
}
cont:
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bd);
__gdtoa_Bfree(bs);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(delta, &TI);
}
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bd);
__gdtoa_Bfree(bs);
__gdtoa_Bfree(bd0);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta, &TI);
if (scale) {
word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
word1(&rv0) = 0;

View file

@ -39,7 +39,7 @@ fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21,
47, 49, 52 };
Bigint *
__gdtoa_increment(Bigint *b)
__gdtoa_increment(Bigint *b, ThInfo **PTI)
{
ULong *x, *xe;
Bigint *b1;
@ -54,9 +54,9 @@ __gdtoa_increment(Bigint *b)
} while(x < xe);
{
if (b->wds >= b->maxwds) {
b1 = __gdtoa_Balloc(b->k+1);
b1 = __gdtoa_Balloc(b->k+1, PTI);
Bcopy(b1,b);
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, PTI);
b = b1;
}
b->x[b->wds++] = 1;
@ -95,14 +95,14 @@ all_on(Bigint *b, int n)
}
Bigint *
__gdtoa_set_ones(Bigint *b, int n)
__gdtoa_set_ones(Bigint *b, int n, ThInfo **PTI)
{
int k;
ULong *x, *xe;
k = (n + ((1 << kshift) - 1)) >> kshift;
if (b->k < k) {
__gdtoa_Bfree(b);
b = __gdtoa_Balloc(k);
__gdtoa_Bfree(b, PTI);
b = __gdtoa_Balloc(k, PTI);
}
k = n >> kshift;
if (n &= kmask)
@ -118,13 +118,13 @@ __gdtoa_set_ones(Bigint *b, int n)
}
static int
rvOK(U *d, const FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv)
rvOK(U *d, const FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv, ThInfo **PTI)
{
Bigint *b;
ULong carry, inex, lostbits;
int bdif, e, j, k, k1, nb, rv;
carry = rv = 0;
b = __gdtoa_d2b(dval(d), &e, &bdif);
b = __gdtoa_d2b(dval(d), &e, &bdif, PTI);
bdif -= nb = fpi->nbits;
e += bdif;
if (bdif <= 0) {
@ -166,7 +166,7 @@ trunc:
__gdtoa_rshift(b, bdif);
if (carry) {
inex = STRTOG_Inexhi;
b = __gdtoa_increment(b);
b = __gdtoa_increment(b, PTI);
if ( (j = nb & kmask) !=0)
j = ULbits - j;
if (hi0bits(b->x[b->wds - 1]) != j) {
@ -178,7 +178,7 @@ trunc:
}
}
else if (bdif < 0)
b = __gdtoa_lshift(b, -bdif);
b = __gdtoa_lshift(b, -bdif, PTI);
if (e < fpi->emin) {
k = fpi->emin - e;
e = fpi->emin;
@ -197,7 +197,7 @@ trunc:
__gdtoa_rshift(b, k);
*irv = STRTOG_Denormal;
if (carry) {
b = __gdtoa_increment(b);
b = __gdtoa_increment(b, PTI);
inex = STRTOG_Inexhi | STRTOG_Underflow;
}
else if (lostbits)
@ -215,7 +215,7 @@ trunc:
*irv |= inex;
rv = 1;
ret:
__gdtoa_Bfree(b);
__gdtoa_Bfree(b, PTI);
return rv;
}
@ -243,6 +243,7 @@ strtodg(const char *s00, char **se, const FPI *fpi, Long *exp, ULong *bits)
U adj, rv;
ULong *b, *be, y, z;
Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
ThInfo *TI = 0;
irv = STRTOG_Zero;
denorm = sign = nz0 = nz = 0;
dval(&rv) = 0.;
@ -276,7 +277,7 @@ break2:
switch(s[1]) {
case 'x':
case 'X':
irv = __gdtoa_gethex(&s, fpi, exp, &rvb, sign);
irv = __gdtoa_gethex(&s, fpi, exp, &rvb, sign, &TI);
if (irv == STRTOG_NoNumber) {
s = s00;
sign = 0;
@ -425,14 +426,14 @@ dig_done:
bd0 = 0;
if (nbits <= P && nd <= DBL_DIG) {
if (!e) {
if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv))
if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv, &TI))
goto ret;
}
else if (e > 0) {
if (e <= Ten_pmax) {
i = fivesbits[e] + mantbits(&rv) <= P;
/* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e]);
if (rvOK(&rv, fpi, exp, bits, i, rd, &irv))
if (rvOK(&rv, fpi, exp, bits, i, rd, &irv, &TI))
goto ret;
e1 -= e;
goto rv_notOK;
@ -446,14 +447,14 @@ dig_done:
e1 -= i;
dval(&rv) *= __gdtoa_tens[i];
/* rv = */ rounded_product(dval(&rv), __gdtoa_tens[e2]);
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv))
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv, &TI))
goto ret;
e1 -= e2;
}
}
else if (e >= -Ten_pmax) {
/* rv = */ rounded_quotient(dval(&rv), __gdtoa_tens[-e]);
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv))
if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv, &TI))
goto ret;
e1 -= e;
}
@ -505,7 +506,7 @@ rv_notOK:
dval(&rv) *= __gdtoa_tinytens[j];
}
}
rvb = __gdtoa_d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */
rvb = __gdtoa_d2b(dval(&rv), &rve, &rvbits, &TI); /* rv = rvb * 2^rve */
rve += e2;
if ((j = rvbits - nbits) > 0) {
__gdtoa_rshift(rvb, j);
@ -521,7 +522,7 @@ rv_notOK:
denorm = 1;
j = rve - emin;
if (j > 0) {
rvb = __gdtoa_lshift(rvb, j);
rvb = __gdtoa_lshift(rvb, j, &TI);
rvbits += j;
}
else if (j < 0) {
@ -557,15 +558,15 @@ rv_notOK:
}
/* Now the hard part -- adjusting rv to the correct value.*/
/* Put digits into bd: true value = bd * 10^e */
bd0 = __gdtoa_s2b(s0, nd0, nd, y, 1);
bd0 = __gdtoa_s2b(s0, nd0, nd, y, 1, &TI);
for(;;) {
bd = __gdtoa_Balloc(bd0->k);
bd = __gdtoa_Balloc(bd0->k, &TI);
Bcopy(bd, bd0);
bb = __gdtoa_Balloc(rvb->k);
bb = __gdtoa_Balloc(rvb->k, &TI);
Bcopy(bb, rvb);
bbbits = rvbits - bb0;
bbe = rve + bb0;
bs = __gdtoa_i2b(1);
bs = __gdtoa_i2b(1, &TI);
if (e >= 0) {
bb2 = bb5 = 0;
bd2 = bd5 = e;
@ -594,25 +595,25 @@ rv_notOK:
bs2 -= i;
}
if (bb5 > 0) {
bs = __gdtoa_pow5mult(bs, bb5);
bb1 = __gdtoa_mult(bs, bb);
__gdtoa_Bfree(bb);
bs = __gdtoa_pow5mult(bs, bb5, &TI);
bb1 = __gdtoa_mult(bs, bb, &TI);
__gdtoa_Bfree(bb, &TI);
bb = bb1;
}
bb2 -= bb0;
if (bb2 > 0)
bb = __gdtoa_lshift(bb, bb2);
bb = __gdtoa_lshift(bb, bb2, &TI);
else if (bb2 < 0)
__gdtoa_rshift(bb, -bb2);
if (bd5 > 0)
bd = __gdtoa_pow5mult(bd, bd5);
bd = __gdtoa_pow5mult(bd, bd5, &TI);
if (bd2 > 0)
bd = __gdtoa_lshift(bd, bd2);
bd = __gdtoa_lshift(bd, bd2, &TI);
if (bs2 > 0)
bs = __gdtoa_lshift(bs, bs2);
bs = __gdtoa_lshift(bs, bs2, &TI);
asub = 1;
inex = STRTOG_Inexhi;
delta = __gdtoa_diff(bb, bd);
delta = __gdtoa_diff(bb, bd, &TI);
if (delta->wds <= 1 && !delta->x[0])
break;
dsign = delta->sign;
@ -637,7 +638,7 @@ rv_notOK:
if (j > 1 && lo0bits(rvb->x + i) < j - 1)
goto adj1;
rve = rve1 - 1;
rvb = __gdtoa_set_ones(rvb, rvbits = nbits);
rvb = __gdtoa_set_ones(rvb, rvbits = nbits, &TI);
break;
}
irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi;
@ -652,7 +653,7 @@ rv_notOK:
: STRTOG_Normal | STRTOG_Inexhi;
if (dsign || bbbits > 1 || denorm || rve1 == emin)
break;
delta = __gdtoa_lshift(delta,1);
delta = __gdtoa_lshift(delta,1,&TI);
if (__gdtoa_cmp(delta, bs) > 0) {
irv = STRTOG_Normal | STRTOG_Inexlo;
goto drop_down;
@ -684,7 +685,7 @@ rv_notOK:
break;
}
rve -= nbits;
rvb = __gdtoa_set_ones(rvb, rvbits = nbits);
rvb = __gdtoa_set_ones(rvb, rvbits = nbits, &TI);
break;
}
else
@ -692,7 +693,7 @@ rv_notOK:
if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1))
break;
if (dsign) {
rvb = __gdtoa_increment(rvb);
rvb = __gdtoa_increment(rvb, &TI);
j = kmask & (ULbits - (rvbits & kmask));
if (hi0bits(rvb->x[rvb->wds - 1]) != j)
rvbits++;
@ -759,20 +760,20 @@ rv_notOK:
/* adj *= __gdtoa_ulp(dval(&rv)); */
/* if (asub) rv -= adj; else rv += adj; */
if (!denorm && rvbits < nbits) {
rvb = __gdtoa_lshift(rvb, j = nbits - rvbits);
rvb = __gdtoa_lshift(rvb, j = nbits - rvbits, &TI);
rve -= j;
rvbits = nbits;
}
ab = __gdtoa_d2b(dval(&adj), &abe, &abits);
ab = __gdtoa_d2b(dval(&adj), &abe, &abits, &TI);
if (abe < 0)
__gdtoa_rshift(ab, -abe);
else if (abe > 0)
ab = __gdtoa_lshift(ab, abe);
ab = __gdtoa_lshift(ab, abe, &TI);
rvb0 = rvb;
if (asub) {
/* rv -= adj; */
j = hi0bits(rvb->x[rvb->wds-1]);
rvb = __gdtoa_diff(rvb, ab);
rvb = __gdtoa_diff(rvb, ab, &TI);
k = rvb0->wds - 1;
if (denorm)
/* do nothing */;
@ -785,7 +786,7 @@ rv_notOK:
denorm = 1;
}
else {
rvb = __gdtoa_lshift(rvb, 1);
rvb = __gdtoa_lshift(rvb, 1, &TI);
--rve;
--rve1;
L = finished = 0;
@ -793,7 +794,7 @@ rv_notOK:
}
}
else {
rvb = __gdtoa_sum(rvb, ab);
rvb = __gdtoa_sum(rvb, ab, &TI);
k = rvb->wds - 1;
if (k >= rvb0->wds
|| hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) {
@ -809,8 +810,8 @@ rv_notOK:
}
}
}
__gdtoa_Bfree(ab);
__gdtoa_Bfree(rvb0);
__gdtoa_Bfree(ab, &TI);
__gdtoa_Bfree(rvb0, &TI);
if (finished)
break;
z = rve + rvbits;
@ -830,27 +831,27 @@ rv_notOK:
}
}
bb0 = denorm ? 0 : __gdtoa_trailz(rvb);
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bd);
__gdtoa_Bfree(bs);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(delta, &TI);
}
if (!denorm && (j = nbits - rvbits)) {
if (j > 0)
rvb = __gdtoa_lshift(rvb, j);
rvb = __gdtoa_lshift(rvb, j, &TI);
else
__gdtoa_rshift(rvb, -j);
rve -= j;
}
*exp = rve;
__gdtoa_Bfree(bb);
__gdtoa_Bfree(bd);
__gdtoa_Bfree(bs);
__gdtoa_Bfree(bd0);
__gdtoa_Bfree(delta);
__gdtoa_Bfree(bb, &TI);
__gdtoa_Bfree(bd, &TI);
__gdtoa_Bfree(bs, &TI);
__gdtoa_Bfree(bd0, &TI);
__gdtoa_Bfree(delta, &TI);
if (rve > fpi->emax) {
huge:
__gdtoa_Bfree(rvb);
__gdtoa_Bfree(rvb, &TI);
rvb = 0;
errno = ERANGE;
switch(fpi->rounding & 3) {
@ -904,7 +905,7 @@ ret:
irv |= STRTOG_Neg;
if (rvb) {
__gdtoa_copybits(bits, nbits, rvb);
__gdtoa_Bfree(rvb);
__gdtoa_Bfree(rvb, &TI);
}
return irv;
}

View file

@ -33,7 +33,7 @@
/* clang-format off */
Bigint *
__gdtoa_sum(Bigint *a, Bigint *b)
__gdtoa_sum(Bigint *a, Bigint *b, ThInfo **PTI)
{
Bigint *c;
ULong carry, *xc, *xa, *xb, *xe, y;
@ -41,7 +41,7 @@ __gdtoa_sum(Bigint *a, Bigint *b)
if (a->wds < b->wds) {
c = b; b = a; a = c;
}
c = __gdtoa_Balloc(a->k);
c = __gdtoa_Balloc(a->k, PTI);
c->wds = a->wds;
carry = 0;
xa = a->x;
@ -66,9 +66,9 @@ __gdtoa_sum(Bigint *a, Bigint *b)
}
if (carry) {
if (c->wds == c->maxwds) {
b = __gdtoa_Balloc(c->k + 1);
b = __gdtoa_Balloc(c->k + 1, PTI);
Bcopy(b, c);
__gdtoa_Bfree(c);
__gdtoa_Bfree(c, PTI);
c = b;
}
c->x[c->wds++] = 1;

View file

@ -224,6 +224,7 @@ THIRD_PARTY_LUA_LUA_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_LOG \
LIBC_STR \
LIBC_SYSV \
THIRD_PARTY_LINENOISE \