libthread: use consistent stack calculation code in makecontext

Also reduce duplication: makecontext is per-arch not per-os-arch.

May fix #353.
This commit is contained in:
Russ Cox 2020-01-19 22:39:22 -05:00
parent ac8042dfa9
commit 41b3e8b989
11 changed files with 36 additions and 83 deletions

View file

@ -5,7 +5,7 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
{
int *sp;
sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4;
sp = USPALIGN(ucp, 4);
sp -= argc;
memmove(sp, &argc+1, argc*sizeof(int));
*--sp = 0; /* return address */

View file

@ -45,9 +45,9 @@ Contains parts of an earlier library that has:
===
The above notices do *NOT* apply to Linux-sparc64-context.S
or to Linux-sparc64-swapcontext.c. Those are functions from
The above notices do *NOT* apply to Linux-sparc64-context.S
or to sparc64-ucontext.c. Those are functions from
the GNU C library and are provided for systems that use the GNU C
library but somehow are missing those functions. They are
library but somehow are missing those functions. They are
distributed under the Lesser GPL; see COPYING.SPARC64-CONTEXT.

View file

@ -1,38 +0,0 @@
#include "threadimpl.h"
void
makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
{
uintptr *sp;
va_list arg;
//fprint(2, "makecontext %d\n", argc);
if(argc != 2)
sysfatal("libthread: makecontext misused");
va_start(arg, argc);
uc->mc.di = va_arg(arg, uint);
uc->mc.si = va_arg(arg, uint);
//fprint(2, "%ux %ux\n", uc->mc.di, uc->mc.si);
va_end(arg);
sp = (uintptr*)((char*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size);
/*
* Stack pointer at call instruction (before return address
* gets pushed) must be 16-byte aligned.
*/
if((uintptr)sp%4)
abort();
while((uintptr)sp%16 != 0)
sp--;
*--sp = 0; // fn's return address
*--sp = (uintptr)fn; // return address of setcontext
uc->mc.sp = (uintptr)sp;
}
int
swapcontext(ucontext_t *oucp, ucontext_t *ucp)
{
if(getcontext(oucp) == 0)
setcontext(ucp);
return 0;
}

View file

@ -435,28 +435,3 @@ _threadpexit(void)
{
_exit(0);
}
#ifdef __arm__
void
makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
{
int i, *sp;
va_list arg;
sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
va_start(arg, argc);
for(i=0; i<4 && i<argc; i++)
uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
va_end(arg);
uc->uc_mcontext.gregs[13] = (uint)sp;
uc->uc_mcontext.gregs[14] = (uint)fn;
}
int
swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
{
if(getcontext(oucp) == 0)
setcontext(ucp);
return 0;
}
#endif

View file

@ -6,7 +6,7 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
int i, *sp;
va_list arg;
sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
sp = USPALIGN(uc, 4);
va_start(arg, argc);
for(i=0; i<4 && i<argc; i++)
(&uc->uc_mcontext.arm_r0)[i] = va_arg(arg, uint);

View file

@ -37,8 +37,8 @@ OpenBSD-%-asm.$O: OpenBSD-%-asm.S
Linux-sparc64-context.$O: Linux-sparc64-context.S
$CC -m64 -mcpu=v9 $CFLAGS Linux-sparc64-context.S
Linux-sparc64-swapcontext.$O: Linux-sparc64-swapcontext.c
$CC -m64 -mcpu=v9 $CFLAGS Linux-sparc64-swapcontext.c
sparc64-ucontext.$O: sparc64-ucontext.c
$CC -m64 -mcpu=v9 $CFLAGS sparc64-ucontext.c
test:V: tprimes tspawn
primes 1 10007 >p1.txt

View file

@ -6,12 +6,14 @@ makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
ulong *sp, *tos;
va_list arg;
tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong);
sp = (ulong*)((ulong)(tos-16) & ~15);
if(argc != 2)
sysfatal("libthread: makecontext misused");
sp = USPALIGN(ucp, 16);
ucp->mc.pc = (long)func;
ucp->mc.sp = (long)sp;
va_start(arg, argc);
ucp->mc.r3 = va_arg(arg, long);
ucp->mc.r4 = va_arg(arg, long);
va_end(arg);
}

View file

@ -7,24 +7,37 @@ NetBSD)
echo ${SYSNAME}-${OBJTYPE}-asm.o $SYSNAME.o stkmalloc.o
;;
OpenBSD)
echo ${SYSNAME}-${OBJTYPE}-asm.o ${SYSNAME}-${OBJTYPE}.o pthread.o stkmmap.o
echo ${SYSNAME}-${OBJTYPE}-asm.o pthread.o stkmmap.o
;;
*)
echo pthread.o stkmalloc.o
esac
# Various libc don't supply swapcontext, makecontext, so we do.
case "$OBJTYPE-$SYSNAME" in
sparc64-Linux)
# Debian glibc doesn't supply swapcontext, makecontext
# so we supply our own copy from the latest glibc.
echo Linux-sparc64-context.o Linux-sparc64-swapcontext.o
386-OpenBSD)
echo 386-ucontext.o
;;
arm-Linux)
# ARM doesn't supply them either.
echo Linux-arm-context.o Linux-arm-swapcontext.o
echo arm-ucontext.o
echo Linux-arm-context.o # setcontext, getcontext
;;
arm-NetBSD)
echo arm-ucontext.o
;;
power-OpenBSD)
echo power-ucontext.o
;;
sparc64-Linux)
echo sparc64-ucontext.o
echo Linux-sparc64-swapcontext.o # setcontext, getcontext
;;
x86_64-Darwin)
echo Darwin-x86_64-asm.o Darwin-x86_64-swapcontext.o
echo x86_64-ucontext.o
echo Darwin-x86_64-asm.o # setcontext, getcontext
;;
x86_64-OpenBSD)
echo x86_64-ucontext.o
;;
esac

View file

@ -188,3 +188,6 @@ extern void _threadpexit(void);
extern void _threaddaemonize(void);
extern void *_threadstkalloc(int);
extern void _threadstkfree(void*, int);
#define USPALIGN(ucp, align) \
(void*)((((uintptr)(ucp)->uc_stack.ss_sp+(ucp)->uc_stack.ss_size)-(align))&~((align)-1))

View file

@ -6,16 +6,14 @@ makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
uintptr *sp;
va_list arg;
//fprint(2, "makecontext %d\n", argc);
if(argc != 2)
sysfatal("libthread: makecontext misused");
va_start(arg, argc);
uc->mc.di = va_arg(arg, uint);
uc->mc.si = va_arg(arg, uint);
//fprint(2, "%ux %ux\n", uc->mc.di, uc->mc.si);
va_end(arg);
sp = (uintptr*)((char*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size);
sp = USPALIGN(uc, 16);
*--sp = 0; // fn's return address
*--sp = (uintptr)fn; // return address of setcontext
uc->mc.sp = (uintptr)sp;