From: alegrand Date: Wed, 29 Jun 2005 00:57:46 +0000 (+0000) Subject: Trying to make context work on stupid architectures by stealing some nice code to... X-Git-Tag: v3.3~3890 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/1703451f01d269c5b1cc49286b406ad2f28a56b7 Trying to make context work on stupid architectures by stealing some nice code to GNU pth. I probably have broken the windows support on my way but that should not be hard to repair. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1465 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- diff --git a/acmacro/context.m4 b/acmacro/context.m4 index d0836c1e4e..152ed2d29c 100644 --- a/acmacro/context.m4 +++ b/acmacro/context.m4 @@ -1,18 +1,402 @@ dnl AC_CHECK_UCONTEXT: Check whether ucontext are working -dnl it uses AC_RUN and assume the worse while cross-compiling - -AC_DEFUN([AC_CHECK_UCONTEXT], - [ -AC_MSG_CHECKING([whether ucontext'es exist and are usable...]) -AC_RUN_IFELSE(AC_LANG_PROGRAM([#include ], - [ucontext_t uc; - if (getcontext (&uc) != 0) return -1; - ]), - AC_MSG_RESULT(yes) - ac_check_ucontext=yes, - AC_MSG_RESULT(no) - ac_check_ucontext=no, - AC_MSG_RESULT(assuming the worse in cross-compilation) - ac_check_ucontext=no) +dnl Most of the code is stolen from the GNU pth autoconf macros by +dnl Ralf S. Engelschall. As +dnl # ``"Reuse an expert's code" is the right +dnl # advice for most people. But it's a useless +dnl # advice for the experts writing the code +dnl # in the first place.' +dnl # -- Dan J. Bernstein +dnl +dnl OK, you're definitely the expert on this point... :) + +dnl ## +dnl ## Display Configuration Headers +dnl ## +dnl ## configure.ac: +dnl ## AC_MSG_PART() +dnl ## + +m4_define(AC_MSG_PART,[dnl +if test ".$enable_subdir" != .yes; then + AC_MSG_RESULT() + AC_MSG_RESULT(${TB}$1:${TN}) +fi +])dnl + +dnl ## +dnl ## Display a message under --verbose +dnl ## +dnl ## configure.ac: +dnl ## AC_MSG_VERBOSE() +dnl ## + +m4_define(AC_MSG_VERBOSE,[dnl +if test ".$verbose" = .yes; then + AC_MSG_RESULT([ $1]) +fi +]) + +dnl ## +dnl ## Do not display message for a command +dnl ## +dnl ## configure.ac: +dnl ## AC_MSG_SILENT(...) +dnl ## + +m4_define(AC_FD_TMP, 9) +m4_define(AC_MSG_SILENT,[dnl +exec AC_FD_TMP>&AC_FD_MSG AC_FD_MSG>/dev/null +$1 +exec AC_FD_MSG>&AC_FD_TMP AC_FD_TMP>&- +]) + +dnl ## +dnl ## Check for direction of stack growth +dnl ## +dnl ## configure.ac: +dnl ## AC_CHECK_STACKGROWTH() +dnl ## acconfig.h: +dnl ## #undef +dnl ## source.c: +dnl ## #include "config.h" +dnl ## #if < 0 +dnl ## ...stack grow down... +dnl ## #else +dnl ## ...stack grow up... +dnl ## #endif +dnl ## + +AC_DEFUN(AC_CHECK_STACKGROWTH,[dnl +AC_MSG_CHECKING(for direction of stack growth) +AC_CACHE_VAL(ac_cv_check_stackgrowth, [ +cross_compiling=no +AC_TRY_RUN( +changequote(<<, >>)dnl +<< +#include +#include +static int iterate = 10; +static int growsdown(int *x) +{ + auto int y; + y = (x > &y); + if (--iterate > 0) + y = growsdown(&y); + if (y != (x > &y)) + exit(1); + return y; +} +int main(int argc, char *argv[]) +{ + FILE *f; + auto int x; + if ((f = fopen("conftestval", "w")) == NULL) + exit(1); + fprintf(f, "%s\n", growsdown(&x) ? "down" : "up");; + fclose(f); + exit(0); +} +>> +changequote([, ])dnl +, +ac_cv_check_stackgrowth=`cat conftestval`, +ac_cv_check_stackgrowth=down, +ac_cv_check_stackgrowth=down +)dnl +])dnl +AC_MSG_RESULT([$ac_cv_check_stackgrowth]) +if test ".$ac_cv_check_stackgrowth" = ".down"; then + val="-1" +else + val="+1" +fi +AC_DEFINE_UNQUOTED($1, $val, [define for stack growth]) +]) + +dnl ## +dnl ## Check whether SVR4/SUSv2 makecontext(2), swapcontext(2) and +dnl ## friends can be used for user-space context switching +dnl ## +dnl ## configure.ac: +dnl ## AC_CHECK_MCSC(, ) +dnl ## + +AC_DEFUN(AC_CHECK_MCSC, [ +AC_MSG_CHECKING(for usable SVR4/SUSv2 makecontext(2)/swapcontext(2)) +AC_CACHE_VAL(ac_cv_check_mcsc, [ +AC_TRY_RUN([ + +#include +#include +#include + +ucontext_t uc_child; +ucontext_t uc_main; + +void child(void *arg) +{ + if (arg != (void *)12345) + exit(1); + if (swapcontext(&uc_child, &uc_main) != 0) + exit(1); +} + +int main(int argc, char *argv[]) +{ + FILE *fp; + void *stack; + + /* the default is that it fails */ + if ((fp = fopen("conftestval", "w")) == NULL) + exit(1); + fprintf(fp, "no\n"); + fclose(fp); + + /* configure a child user-space context */ + if ((stack = malloc(64*1024)) == NULL) + exit(1); + if (getcontext(&uc_child) != 0) + exit(1); + uc_child.uc_link = NULL; + uc_child.uc_stack.ss_sp = (char *)stack+(32*1024); + uc_child.uc_stack.ss_size = 32*1024; + uc_child.uc_stack.ss_flags = 0; + makecontext(&uc_child, child, 2, (void *)12345); + + /* switch into the user context */ + if (swapcontext(&uc_main, &uc_child) != 0) + exit(1); + + /* Fine, child came home */ + if ((fp = fopen("conftestval", "w")) == NULL) + exit(1); + fprintf(fp, "yes\n"); + fclose(fp); + + /* die successfully */ + exit(0); +} +], +ac_cv_check_mcsc=`cat conftestval`, +ac_cv_check_mcsc=no, +ac_cv_check_mcsc=no +)dnl +])dnl +AC_MSG_RESULT([$ac_cv_check_mcsc]) +if test ".$ac_cv_check_mcsc" = .yes; then + ifelse([$1], , :, [$1]) +else + ifelse([$2], , :, [$2]) +fi +])dnl + +dnl ## +dnl ## Check how stacks have to be setup for the functions +dnl ## sigstack(2), sigaltstack(2) and makecontext(2). +dnl ## +dnl ## configure.ac: +dnl ## AC_CHECK_STACKSETUP(sigstack|sigaltstack|makecontext, , ) +dnl ## acconfig.h: +dnl ## #undef HAVE_{SIGSTACK|SIGALTSTACK|MAKECONTEXT} +dnl ## #undef HAVE_STACK_T +dnl ## header.h.in: +dnl ## @@ +dnl ## @@ +dnl ## source.c: +dnl ## #include "header.h" +dnl ## xxx.sp_ss = (skaddr, sksize); +dnl ## xxx.sp_size = (skaddr, sksize); +dnl ## + +AC_DEFUN(AC_CHECK_STACKSETUP,[dnl +dnl # check for consistent usage +ifelse($1,[sigstack],,[ +ifelse($1,[sigaltstack],,[ +ifelse($1,[makecontext],,[ +errprint(__file__:__line__: [AC_CHECK_STACKSETUP: only sigstack, sigaltstack and makecontext supported +])])])]) +dnl # we require the C compiler and the standard headers +AC_REQUIRE([AC_HEADER_STDC])dnl +dnl # we at least require the function to check +AC_CHECK_FUNCS($1) +dnl # sigaltstack on some platforms uses stack_t instead of struct sigaltstack +ifelse($1, sigaltstack, [ + AC_ONCE(stacksetup_stack_t, [ + AC_CHECK_TYPEDEF(stack_t, signal.h) + ]) +]) +dnl # display processing header +AC_MSG_CHECKING(for stack setup via $1) +dnl # but cache the whole results +AC_CACHE_VAL(ac_cv_stacksetup_$1,[ +if test ".$ac_cv_func_$1" = .no; then + dnl # no need to check anything when function is already missing + ac_cv_stacksetup_$1="N.A.:/*N.A.*/,/*N.A.*/" +else + dnl # setup compile environment + OCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -DTEST_$1" + cross_compiling=no + dnl # compile and run the test program + AC_TRY_RUN([ +#include +#include +#include +#if defined(TEST_sigstack) || defined(TEST_sigaltstack) +#include +#include +#include +#endif +#if defined(TEST_makecontext) +#include +#endif +union alltypes { + long l; + double d; + void *vp; + void (*fp)(void); + char *cp; +}; +static volatile char *handler_addr = (char *)0xDEAD; +#if defined(TEST_sigstack) || defined(TEST_sigaltstack) +static volatile int handler_done = 0; +void handler(int sig) +{ + char garbage[1024]; + int i; + auto int dummy; + for (i = 0; i < 1024; i++) + garbage[i] = 'X'; + handler_addr = (char *)&dummy; + handler_done = 1; + return; +} +#endif +#if defined(TEST_makecontext) +static ucontext_t uc_handler; +static ucontext_t uc_main; +void handler(void) +{ + char garbage[1024]; + int i; + auto int dummy; + for (i = 0; i < 1024; i++) + garbage[i] = 'X'; + handler_addr = (char *)&dummy; + swapcontext(&uc_handler, &uc_main); + return; +} +#endif +int main(int argc, char *argv[]) +{ + FILE *f; + char *skaddr; + char *skbuf; + int sksize; + char result[1024]; + int i; + sksize = 32768; + skbuf = (char *)malloc(sksize*2+2*sizeof(union alltypes)); + if (skbuf == NULL) + exit(1); + for (i = 0; i < sksize*2+2*sizeof(union alltypes); i++) + skbuf[i] = 'A'; + skaddr = skbuf+sizeof(union alltypes); +#if defined(TEST_sigstack) || defined(TEST_sigaltstack) + { + struct sigaction sa; +#if defined(TEST_sigstack) + struct sigstack ss; +#elif defined(TEST_sigaltstack) && defined(HAVE_STACK_T) + stack_t ss; +#else + struct sigaltstack ss; +#endif +#if defined(TEST_sigstack) + ss.ss_sp = (void *)(skaddr + sksize); + ss.ss_onstack = 0; + if (sigstack(&ss, NULL) < 0) + exit(1); +#elif defined(TEST_sigaltstack) + ss.ss_sp = (void *)(skaddr + sksize); + ss.ss_size = sksize; + ss.ss_flags = 0; + if (sigaltstack(&ss, NULL) < 0) + exit(1); +#endif + memset((void *)&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = handler; + sa.sa_flags = SA_ONSTACK; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR1, &sa, NULL); + kill(getpid(), SIGUSR1); + while (!handler_done) + /*nop*/; + } +#endif +#if defined(TEST_makecontext) + { + if (getcontext(&uc_handler) != 0) + exit(1); + uc_handler.uc_link = NULL; + uc_handler.uc_stack.ss_sp = (void *)(skaddr + sksize); + uc_handler.uc_stack.ss_size = sksize; + uc_handler.uc_stack.ss_flags = 0; + makecontext(&uc_handler, handler, 1); + swapcontext(&uc_main, &uc_handler); + } +#endif + if (handler_addr == (char *)0xDEAD) + exit(1); + if (handler_addr < skaddr+sksize) { + /* stack was placed into lower area */ + if (*(skaddr+sksize) != 'A') + sprintf(result, "(skaddr)+(sksize)-%d,(sksize)-%d", + sizeof(union alltypes), sizeof(union alltypes)); + else + strcpy(result, "(skaddr)+(sksize),(sksize)"); + } + else { + /* stack was placed into higher area */ + if (*(skaddr+sksize*2) != 'A') + sprintf(result, "(skaddr),(sksize)-%d", sizeof(union alltypes)); + else + strcpy(result, "(skaddr),(sksize)"); + } + if ((f = fopen("conftestval", "w")) == NULL) + exit(1); + fprintf(f, "%s\n", result); + fclose(f); + exit(0); +} +],[ +dnl # test successully passed +ac_cv_stacksetup_$1=`cat conftestval` +ac_cv_stacksetup_$1="ok:$ac_cv_stacksetup_$1" +],[ +dnl # test failed +ac_cv_stacksetup_$1='guessed:(skaddr),(sksize)' +],[ +dnl # cross-platform => failed +ac_cv_stacksetup_$1='guessed:(skaddr),(sksize)' +]) +dnl # restore original compile environment +CFLAGS="$OCFLAGS" +])dnl +fi +dnl # extract result ingredients of single cached result value +type=`echo $ac_cv_stacksetup_$1 | sed -e 's;:.*$;;'` +addr=`echo $ac_cv_stacksetup_$1 | sed -e 's;^.*:;;' -e 's;,.*$;;'` +size=`echo $ac_cv_stacksetup_$1 | sed -e 's;^.*:;;' -e 's;^.*,;;'` +dnl # export result ingredients +$2="#define $2(skaddr,sksize) ($addr)" +$3="#define $3(skaddr,sksize) ($size)" +AC_SUBST($2)dnl +AC_SUBST($3)dnl +dnl # display result indicator +AC_MSG_RESULT([$type]) +dnl # display results in detail +AC_MSG_VERBOSE([$]$2) +AC_MSG_VERBOSE([$]$3) ]) diff --git a/configure.ac b/configure.ac index c022500b2e..2ce6ae2b38 100644 --- a/configure.ac +++ b/configure.ac @@ -55,13 +55,46 @@ GRAS_ARCH GRAS_CHECK_STRUCT_COMPACTION +dnl ## +dnl ## CONTEXT IMPLEMENTATION +dnl ## + SG_CONFIGURE_PART([Checking for threads, contexts or assimilated...]) -AC_CHECK_UCONTEXT + +dnl # +dnl # 1. determine possibilities +dnl # + +dnl # check for MCSC method AC_MSG_CHECKING(on top of what can we build the contexts) +AC_CHECK_HEADER(ucontext.h,,, [#include ]) +AC_CHECK_FUNCS(makecontext swapcontext getcontext setcontext) +AC_CHECK_MCSC(mcsc=yes, mcsc=no) + +dnl # check for pthread method +AC_CHECK_HEADERS([pthread.h]) +AC_CHECK_LIB(pthread,pthread_create,pthread=yes, pthread=no) + +dnl # +dnl # 2. make a general decision +dnl # + +if test ".$mcsc" = .yes; then + mcsc=yes +elif test ".$pthread" = .yes; then + pthread=yes +else + AC_ERROR([no appropriate backend found]) +fi + +dnl # +dnl # 3. allow decision to be overridden by user +dnl # + +AC_MSG_CHECKING(what kind of backend should we use) AC_ARG_WITH(context, [ --with-context=[ucontext/pthread] Use either (System V) swapcontext or pthread [[default=auto]].],, with_context=auto) - case $with_context in ucontext) ;; pthread) ;; @@ -70,8 +103,8 @@ case $with_context in esac if test "x$with_context" = "xucontext" ; then - if test "x$ac_check_ucontext" = "xyes"; then - AC_MSG_RESULT(found ucontext.h. Great!) + if test ".$mcsc" = .yes; then + AC_MSG_RESULT(found working ucontext. Great!) AC_DEFINE([USE_UCONTEXT],1,[Define if we use ucontext or not]) else ac_header=windows.h @@ -87,13 +120,29 @@ fi if test "x$with_context" = "xpthread"; then AC_CHECK_HEADERS([pthread.h]) -dnl A C_CHECK_LIB(pthread, pthread_mutex_lock, LIBS="$LIBS -lpthread") AC_CHECK_LIB(pthread,pthread_create,, [AC_MSG_ERROR([[Cannot find pthreads, no way (try --with-context=ucontext if you haven't already tried).]])]) AC_DEFINE([USE_PTHREADS],1,[Define if we use pthreads or not]) AC_MSG_RESULT(You have pthreads. Let's use them.) fi +dnl # +dnl # 4. determine a few additional details +dnl # + +if test "x$with_context" = "xucontext" ; then +dnl # direction of stack grow + AC_CHECK_STACKGROWTH(PTH_STACKGROWTH) + if test ".$ac_cv_check_stackgrowth" = ".down"; then + PTH_STACK_GROWTH="down" + else + PTH_STACK_GROWTH="up" + fi + AC_SUBST(PTH_STACK_GROWTH) + + AC_CHECK_STACKSETUP(makecontext, pth_skaddr_makecontext, pth_sksize_makecontext) +fi + ######################################### ## Check for libraries extra-dependencies ## @@ -169,6 +218,7 @@ AC_CONFIG_FILES([ include/Makefile src/Makefile src/amok/Makefile + src/ucontext_stack.h examples/Makefile examples/msg/Makefile examples/msg/run_msg_test examples/gras/Makefile diff --git a/src/ucontext_stack.h.in b/src/ucontext_stack.h.in new file mode 100644 index 0000000000..f144e94d12 --- /dev/null +++ b/src/ucontext_stack.h.in @@ -0,0 +1,13 @@ +/* $Id$ */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#ifndef _UCONTEXT_STACK_H +#define _UCONTEXT_STACK_H + +/* stack setup macros */ +@pth_skaddr_makecontext@ +@pth_sksize_makecontext@ + +#endif /* _UCONTEXT_STACK_H */ diff --git a/src/xbt/context.c b/src/xbt/context.c index 5ab348db85..a2aa4fd0e2 100644 --- a/src/xbt/context.c +++ b/src/xbt/context.c @@ -229,8 +229,8 @@ xbt_context_t xbt_context_new(xbt_context_function_t code, /* WARNING : when this context is over, the current_context (i.e. the father), is awaken... Theorically, the wrapper should prevent using this feature. */ - res->uc.uc_stack.ss_sp = res->stack; - res->uc.uc_stack.ss_size = STACK_SIZE; + res->uc.uc_stack.ss_sp = pth_skaddr_makecontext(res->stack,STACK_SIZE); + res->uc.uc_stack.ss_size = pth_sksize_makecontext(res->stack,STACK_SIZE); #endif res->argc = argc; res->argv = argv; diff --git a/src/xbt/context_private.h b/src/xbt/context_private.h index 5912e5c31c..9e1d69dfe6 100644 --- a/src/xbt/context_private.h +++ b/src/xbt/context_private.h @@ -13,6 +13,7 @@ #include "xbt/swag.h" #include "xbt/dynar.h" /* void_f_pvoid_t */ #include "portable.h" /* loads context system definitions */ +#include "ucontext_stack.h" /* loads context system definitions */ #include "xbt/context.h"