Perform some code maintenance

- Change IDT code so kprintf() isn't mandatory dependency
- Document current intentions around pthread_cancel()
- Make _npassert() an _unassert() in MODE=tiny
This commit is contained in:
Justine Tunney 2022-10-09 13:00:46 -07:00
parent 4a6fd3d910
commit 9b7c8db846
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
7 changed files with 85 additions and 49 deletions

View file

@ -2,7 +2,6 @@
#define COSMOPOLITAN_LIBC_ASSERT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#include "libc/intrin/kprintf.h"
extern bool __assert_disable;
void __assert_fail(const char *, const char *, int) hidden relegated;
@ -24,13 +23,16 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
} \
} while (0)
#define _npassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
kprintf("%s:%d: oh no!\n", __FILE__, __LINE__); \
notpossible; \
} \
#ifndef TINY
#define _npassert(x) \
do { \
if (__builtin_expect(!(x), 0)) { \
notpossible; \
} \
} while (0)
#else
#define _npassert(x) _unassert(x)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -34,14 +34,11 @@ static void _mapframe(void *p, int f) {
struct DirectMap dm;
prot = PROT_READ | PROT_WRITE;
flags = f | MAP_ANONYMOUS | MAP_FIXED;
if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr != p) {
notpossible;
}
_npassert((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr == p);
__mmi_lock();
if (TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
dm.maphandle, prot, flags, false, false, 0, G)) {
notpossible;
}
_npassert(!TrackMemoryInterval(&_mmi, (uintptr_t)p >> 16, (uintptr_t)p >> 16,
dm.maphandle, prot, flags, false, false, 0,
G));
__mmi_unlock();
}
@ -65,13 +62,11 @@ static void _mapframe(void *p, int f) {
*/
noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
char *q;
#ifndef NDEBUG
if ((uintptr_t)SHADOW(p) & (G - 1)) notpossible;
if ((uintptr_t)p + (G << kAsanScale) > h) notpossible;
#endif
_npassert(!((uintptr_t)SHADOW(p) & (G - 1)));
_npassert((uintptr_t)p + (G << kAsanScale) <= h);
for (q = e; q < ((char *)p + n); q += 8) {
if (!((uintptr_t)q & (G - 1))) {
if (q + G > (char *)h) notpossible;
_npassert(q + G <= (char *)h);
_mapframe(q, f);
if (IsAsan()) {
if (!((uintptr_t)SHADOW(q) & (G - 1))) {

View file

@ -52,7 +52,7 @@
.rept 30
push %rsi # preserve rsi
mov $i,%sil # rsi = exception number
1: jmp 1f # 🦘
1: jmp 1f # kangeroo
i = i - 1
.endr
__excep1_isr:
@ -71,7 +71,7 @@ __excep0_isr:
push %rdx # use to call kprintf
push %r8
push %r9
mov 48(%rsp),%rcx # edx:rcx = "caller" cs:rip
mov 48(%rsp),%rcx # edx:rcx = 'caller' cs:rip
mov 56(%rsp),%edx
mov 40(%rsp),%r8 # r8 = error code
mov %cr2,%r9 # r9 = cr2, in case it is useful
@ -91,10 +91,14 @@ __excep0_isr:
mov %eax,%ds
mov %eax,%es
ezlea .excep_msg,di # stack should be 16-byte aligned now
xor %eax,%eax # kprintf is variadic; remember to
xor %eax,%eax # kprintf is variadic, remember to
# pass no. of vector regs. used (= 0)
call kprintf # print error message
cli
.weak kprintf # weakly link kprintf() because this
ezlea kprintf,bx # module is a mandatory dependency
test %ebx,%ebx # and we want to keep life.com tiny
jz 8f
call *%rbx # print error message
8: cli
9: hlt
jmp 9b
/* TODO: link up with sigaction etc. */
@ -105,7 +109,7 @@ __excep0_isr:
isr_init:
testb IsMetal()
jz 9f
ezlea _tss+0x24,di # fill up TSS; we already loaded
ezlea _tss+0x24,di # fill up TSS, we already loaded
# task register in ape/ape.S
ezlea _isr_stk_1+ISR_STK_SZ,ax
and $-ISR_STK_ALIGN,%al # be paranoid & enforce correct

View file

@ -49,7 +49,7 @@
static void *MoveMemoryIntervals(struct MemoryInterval *d,
const struct MemoryInterval *s, int n) {
int i;
if (n < 0) unreachable;
_unassert(n >= 0);
if (d > s) {
for (i = n; i--;) {
d[i] = s[i];
@ -63,8 +63,8 @@ static void *MoveMemoryIntervals(struct MemoryInterval *d,
}
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
if (i < 0) unreachable;
if (i + n > mm->i) unreachable;
_unassert(i >= 0);
_unassert(i + n <= mm->i);
MoveMemoryIntervals(mm->p + i, mm->p + i + n, mm->i - (i + n));
mm->i -= n;
}
@ -108,9 +108,9 @@ static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
}
int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
if (i < 0) unreachable;
if (i > mm->i) unreachable;
if (mm->n < 0) unreachable;
_unassert(i >= 0);
_unassert(i <= mm->i);
_unassert(mm->n >= 0);
if (UNLIKELY(mm->i == mm->n) && !ExtendMemoryIntervals(mm)) return enomem();
MoveMemoryIntervals(mm->p + i + 1, mm->p + i, mm->i++ - i);
return 0;
@ -129,7 +129,7 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
void wf(struct MemoryIntervals *, int, int)) {
unsigned l, r;
ASSERT_MEMTRACK();
if (y < x) unreachable;
_unassert(y >= x);
if (!mm->i) return 0;
// binary search for the lefthand side
l = FindMemoryInterval(mm, x);
@ -139,8 +139,8 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
// binary search for the righthand side
r = FindMemoryInterval(mm, y);
if (r == mm->i || (r > l && y < mm->p[r].x)) --r;
if (r < l) unreachable;
if (x > mm->p[r].y) unreachable;
_unassert(r >= l);
_unassert(x <= mm->p[r].y);
// remove the middle of an existing map
//
@ -161,11 +161,11 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
// ----|mmmm|----------------- after
//
if (x > mm->p[l].x && x <= mm->p[l].y) {
if (y < mm->p[l].y) unreachable;
_unassert(y >= mm->p[l].y);
if (IsWindows()) return einval();
mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE;
mm->p[l].y = x - 1;
if (mm->p[l].x > mm->p[l].y) unreachable;
_unassert(mm->p[l].x <= mm->p[l].y);
++l;
}
@ -176,11 +176,11 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
// ---------------|mm|-------- after
//
if (y >= mm->p[r].x && y < mm->p[r].y) {
if (x > mm->p[r].x) unreachable;
_unassert(x <= mm->p[r].x);
if (IsWindows()) return einval();
mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE;
mm->p[r].x = y + 1;
if (mm->p[r].x > mm->p[r].y) unreachable;
_unassert(mm->p[r].x <= mm->p[r].y);
--r;
}
@ -198,7 +198,7 @@ int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
long offset, long size) {
unsigned i;
ASSERT_MEMTRACK();
if (y < x) unreachable;
_unassert(y >= x);
i = FindMemoryInterval(mm, x);
// try to extend the righthand side of the lefthand entry

View file

@ -16,9 +16,52 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
/**
* Cancels thread.
*
* This function currently isn't supported. In order to support this
* function we'd need to redesign the system call interface, and add
* bloat and complexity to every function that can return EINTR. You
* might want to consider using `nsync_note` instead, which provides
* much better cancellations because posix cancellations is a broken
* design. If you need to cancel i/o operations, try doing this:
*
* _Thread_local bool gotusr1;
* void OnUsr1(int sig) { gotusr1 = true; }
* struct sigaction sa = {.sa_handler = OnUsr1};
* sigaction(SIGUSR1, &sa, 0);
* tkill(pthread_getunique_np(thread), SIGUSR1);
*
* The above code should successfully cancel a thread's blocking io
* operations in most cases, e.g.
*
* void *MyThread(void *arg) {
* sigset_t ss;
* sigfillset(&ss);
* sigdelset(&ss, SIGUSR1);
* sigprocmask(SIG_SETMASK, &ss, 0);
* while (!gotusr1) {
* char buf[512];
* ssize_t rc = read(0, buf, sizeof(buf));
* if (rc == -1 && errno == EINTR) continue;
* write(1, buf, rc);
* }
* return 0;
* }
*
* This has the same correctness issue as glibc, but it's usually
* "good enough" if you only need cancellations to perform things
* like server shutdown and socket options like `SO_RCVTIMEO` can
* ensure it's even safer, since it can't possibly block forever.
*
* @see https://sourceware.org/bugzilla/show_bug.cgi?id=12683
*/
int pthread_cancel(pthread_t thread) {
return ESRCH;
kprintf("error: pthread_cancel() is unsupported, please read the "
"cosmopolitan libc documentation for further details\n");
_Exit(1);
}

View file

@ -222,11 +222,7 @@ static const uint32_t NSYNC_WAITER_TAG = 0x726d2ba9;
#define CONTAINER(t_, f_, p_) ((t_ *)(((char *)(p_)) - offsetof(t_, f_)))
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Return a pointer to the nsync_waiter_s containing nsync_dll_element_ *e. */
#define DLL_NSYNC_WAITER(e) \

View file

@ -30,11 +30,7 @@ Copyright 2016 Google, Inc.\\n\
https://github.com/google/nsync\"");
// clang-format off
#ifdef TINY
#define ASSERT(x) _unassert(x)
#else
#define ASSERT(x) _npassert(x)
#endif
/* Check that atomic operations on nsync_atomic_uint32_ can be applied to int. */
static const int assert_int_size = 1 /