From 41b3e8b9893a8561af7e85ca98444bc284b4013d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 19 Jan 2020 22:39:22 -0500 Subject: libthread: use consistent stack calculation code in makecontext Also reduce duplication: makecontext is per-arch not per-os-arch. May fix #353. --- src/libthread/386-ucontext.c | 22 ++++++++++++++ src/libthread/COPYRIGHT | 6 ++-- src/libthread/Darwin-x86_64-swapcontext.c | 38 ------------------------ src/libthread/Linux-arm-swapcontext.c | 24 --------------- src/libthread/Linux-sparc64-swapcontext.c | 49 ------------------------------- src/libthread/NetBSD.c | 25 ---------------- src/libthread/OpenBSD-386.c | 22 -------------- src/libthread/OpenBSD-power.c | 24 --------------- src/libthread/OpenBSD-x86_64.c | 30 ------------------- src/libthread/arm-ucontext.c | 24 +++++++++++++++ src/libthread/mkfile | 4 +-- src/libthread/power-ucontext.c | 26 ++++++++++++++++ src/libthread/sparc64-ucontext.c | 49 +++++++++++++++++++++++++++++++ src/libthread/sysofiles.sh | 29 +++++++++++++----- src/libthread/threadimpl.h | 3 ++ src/libthread/x86_64-ucontext.c | 28 ++++++++++++++++++ 16 files changed, 178 insertions(+), 225 deletions(-) create mode 100644 src/libthread/386-ucontext.c delete mode 100644 src/libthread/Darwin-x86_64-swapcontext.c delete mode 100644 src/libthread/Linux-arm-swapcontext.c delete mode 100644 src/libthread/Linux-sparc64-swapcontext.c delete mode 100644 src/libthread/OpenBSD-386.c delete mode 100644 src/libthread/OpenBSD-power.c delete mode 100644 src/libthread/OpenBSD-x86_64.c create mode 100644 src/libthread/arm-ucontext.c create mode 100644 src/libthread/power-ucontext.c create mode 100644 src/libthread/sparc64-ucontext.c create mode 100644 src/libthread/x86_64-ucontext.c (limited to 'src/libthread') diff --git a/src/libthread/386-ucontext.c b/src/libthread/386-ucontext.c new file mode 100644 index 00000000..3afa9513 --- /dev/null +++ b/src/libthread/386-ucontext.c @@ -0,0 +1,22 @@ +#include "threadimpl.h" + +void +makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) +{ + int *sp; + + sp = USPALIGN(ucp, 4); + sp -= argc; + memmove(sp, &argc+1, argc*sizeof(int)); + *--sp = 0; /* return address */ + ucp->uc_mcontext.mc_eip = (long)func; + ucp->uc_mcontext.mc_esp = (int)sp; +} + +int +swapcontext(ucontext_t *oucp, ucontext_t *ucp) +{ + if(getcontext(oucp) == 0) + setcontext(ucp); + return 0; +} diff --git a/src/libthread/COPYRIGHT b/src/libthread/COPYRIGHT index f4ee354e..d0820965 100644 --- a/src/libthread/COPYRIGHT +++ b/src/libthread/COPYRIGHT @@ -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. diff --git a/src/libthread/Darwin-x86_64-swapcontext.c b/src/libthread/Darwin-x86_64-swapcontext.c deleted file mode 100644 index c29ddb5e..00000000 --- a/src/libthread/Darwin-x86_64-swapcontext.c +++ /dev/null @@ -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; -} diff --git a/src/libthread/Linux-arm-swapcontext.c b/src/libthread/Linux-arm-swapcontext.c deleted file mode 100644 index fc0dfdda..00000000 --- a/src/libthread/Linux-arm-swapcontext.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "threadimpl.h" - -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 && iuc_mcontext.arm_r0)[i] = va_arg(arg, uint); - va_end(arg); - uc->uc_mcontext.arm_sp = (uint)sp; - uc->uc_mcontext.arm_lr = (uint)fn; -} - -int -swapcontext(ucontext_t *oucp, const ucontext_t *ucp) -{ - if(getcontext(oucp) == 0) - setcontext(ucp); - return 0; -} diff --git a/src/libthread/Linux-sparc64-swapcontext.c b/src/libthread/Linux-sparc64-swapcontext.c deleted file mode 100644 index e4800c19..00000000 --- a/src/libthread/Linux-sparc64-swapcontext.c +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Jakub Jelinek . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -#define UC_M_PC 40 -#define UC_M_NPC 48 - -extern int __getcontext (ucontext_t *ucp); -extern int __setcontext (const ucontext_t *ucp, int restoremask); - -int -swapcontext (ucontext_t *oucp, const ucontext_t *ucp) -{ - extern void __swapcontext_ret (void); - /* Save the current machine context to oucp. */ - __getcontext (oucp); - /* Modify oucp to skip the __setcontext call on reactivation. */ - *(long*)((char*)oucp+UC_M_PC) = (long)__swapcontext_ret; - *(long*)((char*)oucp+UC_M_NPC) = (long)__swapcontext_ret + 4; - /* Restore the machine context in ucp. */ - __setcontext (ucp, 1); - return 0; -} - -asm (" \n\ - .text \n\ - .type __swapcontext_ret, #function \n\ -__swapcontext_ret: \n\ - return %i7 + 8 \n\ - clr %o0 \n\ - .size __swapcontext_ret, .-__swapcontext_ret \n\ - "); diff --git a/src/libthread/NetBSD.c b/src/libthread/NetBSD.c index 31577e87..2b14146b 100644 --- a/src/libthread/NetBSD.c +++ b/src/libthread/NetBSD.c @@ -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 && iuc_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 diff --git a/src/libthread/OpenBSD-386.c b/src/libthread/OpenBSD-386.c deleted file mode 100644 index 89bfedcd..00000000 --- a/src/libthread/OpenBSD-386.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "threadimpl.h" - -void -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 -= argc; - memmove(sp, &argc+1, argc*sizeof(int)); - *--sp = 0; /* return address */ - ucp->uc_mcontext.mc_eip = (long)func; - ucp->uc_mcontext.mc_esp = (int)sp; -} - -int -swapcontext(ucontext_t *oucp, ucontext_t *ucp) -{ - if(getcontext(oucp) == 0) - setcontext(ucp); - return 0; -} diff --git a/src/libthread/OpenBSD-power.c b/src/libthread/OpenBSD-power.c deleted file mode 100644 index eab711f2..00000000 --- a/src/libthread/OpenBSD-power.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "threadimpl.h" - -void -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); - ucp->mc.pc = (long)func; - ucp->mc.sp = (long)sp; - va_start(arg, argc); - ucp->mc.r3 = va_arg(arg, long); - va_end(arg); -} - -int -swapcontext(ucontext_t *oucp, ucontext_t *ucp) -{ - if(getcontext(oucp) == 0) - setcontext(ucp); - return 0; -} diff --git a/src/libthread/OpenBSD-x86_64.c b/src/libthread/OpenBSD-x86_64.c deleted file mode 100644 index 27931456..00000000 --- a/src/libthread/OpenBSD-x86_64.c +++ /dev/null @@ -1,30 +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); - *--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; -} diff --git a/src/libthread/arm-ucontext.c b/src/libthread/arm-ucontext.c new file mode 100644 index 00000000..512ca973 --- /dev/null +++ b/src/libthread/arm-ucontext.c @@ -0,0 +1,24 @@ +#include "threadimpl.h" + +void +makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) +{ + int i, *sp; + va_list arg; + + sp = USPALIGN(uc, 4); + va_start(arg, argc); + for(i=0; i<4 && iuc_mcontext.arm_r0)[i] = va_arg(arg, uint); + va_end(arg); + uc->uc_mcontext.arm_sp = (uint)sp; + uc->uc_mcontext.arm_lr = (uint)fn; +} + +int +swapcontext(ucontext_t *oucp, const ucontext_t *ucp) +{ + if(getcontext(oucp) == 0) + setcontext(ucp); + return 0; +} diff --git a/src/libthread/mkfile b/src/libthread/mkfile index a083fd01..45b78039 100644 --- a/src/libthread/mkfile +++ b/src/libthread/mkfile @@ -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 diff --git a/src/libthread/power-ucontext.c b/src/libthread/power-ucontext.c new file mode 100644 index 00000000..32a8e931 --- /dev/null +++ b/src/libthread/power-ucontext.c @@ -0,0 +1,26 @@ +#include "threadimpl.h" + +void +makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) +{ + ulong *sp, *tos; + va_list arg; + + 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); +} + +int +swapcontext(ucontext_t *oucp, ucontext_t *ucp) +{ + if(getcontext(oucp) == 0) + setcontext(ucp); + return 0; +} diff --git a/src/libthread/sparc64-ucontext.c b/src/libthread/sparc64-ucontext.c new file mode 100644 index 00000000..e4800c19 --- /dev/null +++ b/src/libthread/sparc64-ucontext.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#define UC_M_PC 40 +#define UC_M_NPC 48 + +extern int __getcontext (ucontext_t *ucp); +extern int __setcontext (const ucontext_t *ucp, int restoremask); + +int +swapcontext (ucontext_t *oucp, const ucontext_t *ucp) +{ + extern void __swapcontext_ret (void); + /* Save the current machine context to oucp. */ + __getcontext (oucp); + /* Modify oucp to skip the __setcontext call on reactivation. */ + *(long*)((char*)oucp+UC_M_PC) = (long)__swapcontext_ret; + *(long*)((char*)oucp+UC_M_NPC) = (long)__swapcontext_ret + 4; + /* Restore the machine context in ucp. */ + __setcontext (ucp, 1); + return 0; +} + +asm (" \n\ + .text \n\ + .type __swapcontext_ret, #function \n\ +__swapcontext_ret: \n\ + return %i7 + 8 \n\ + clr %o0 \n\ + .size __swapcontext_ret, .-__swapcontext_ret \n\ + "); diff --git a/src/libthread/sysofiles.sh b/src/libthread/sysofiles.sh index 9a7301a8..8a65d0f6 100644 --- a/src/libthread/sysofiles.sh +++ b/src/libthread/sysofiles.sh @@ -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 diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h index 5b6d74cc..cceb1b8e 100644 --- a/src/libthread/threadimpl.h +++ b/src/libthread/threadimpl.h @@ -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)) diff --git a/src/libthread/x86_64-ucontext.c b/src/libthread/x86_64-ucontext.c new file mode 100644 index 00000000..5d1aaefc --- /dev/null +++ b/src/libthread/x86_64-ucontext.c @@ -0,0 +1,28 @@ +#include "threadimpl.h" + +void +makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) +{ + uintptr *sp; + va_list arg; + + 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); + va_end(arg); + + sp = USPALIGN(uc, 16); + *--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; +} -- cgit v1.2.3