diff --git a/m4/ghc_iomanagers.m4 b/m4/ghc_iomanagers.m4 new file mode 100644 index 0000000000000000000000000000000000000000..dd15758b8d268bcbaca986d02518cabc5872f5ca --- /dev/null +++ b/m4/ghc_iomanagers.m4 @@ -0,0 +1,40 @@ +# GHC_IOMANAGER_ENABLE(iomgr_name, enable_var, output_cpp_var, action_detect) +# --------------------------------------------------------------------- +AC_DEFUN([GHC_IOMANAGER_ENABLE], [ + $4 + AC_MSG_CHECKING( if the the $1 I/O manager should be built) + if test "${$2}" = "YES"; then + AC_MSG_RESULT(yes) + AC_DEFINE([$3], [1], [Define to 1 if the $1 I/O manager should be built]) + else + AC_MSG_RESULT(no) + fi +]) + + +# GHC_IOMANAGER_DEFAULT_SELECT(default_var, iomgr_name, enable_var) +# --------------------------------------------------------------------- +AC_DEFUN([GHC_IOMANAGER_DEFAULT_SELECT], [ + if test "${$3}" = "YES"; then + $1=$2 + fi +]) + + +# GHC_IOMANAGER_DEFAULT_CHECK_NOT_EMPTY(default_var, way) +# --------------------------------------------------------------------- +AC_DEFUN([GHC_IOMANAGER_DEFAULT_CHECK_NOT_EMPTY], [ + if test "${$1}" = ""; then + AC_MSG_ERROR([no suitable I/O manager enabled for the $2 RTS]) + fi +]) + +# GHC_IOMANAGER_DEFAULT_AC_DEFINE(default_var, way, iomgr_name, output_cpp_var) +# --------------------------------------------------------------------- +AC_DEFUN([GHC_IOMANAGER_DEFAULT_AC_DEFINE], [ + if test "${$1}" = "$3"; then + AC_DEFINE([$4], [1], + [Define to 1 if the $3 I/O manager is the default for the $2 RTS]) + fi +]) + diff --git a/rts/IOManager.h b/rts/IOManager.h index bd7ce35ff753f037fe8605ca8a2334a4041d982e..df5f72cdd840c0135673541f56b82d7fc0a026b9 100644 --- a/rts/IOManager.h +++ b/rts/IOManager.h @@ -24,6 +24,104 @@ #include "sm/GC.h" // for evac_fn #include "posix/Select.h" // for LowResTime TODO: switch to normal Time +/* The ./configure gives us a set of CPP flags, one for each named I/O manager: + * IOMGR_BUILD_<name> : which ones should be built (some) + * IOMGR_DEFAULT_NON_THREADED_<name> : which one is default (exactly one) + * IOMGR_DEFAULT_THREADED_<name> : which one is default (exactly one) + * + * The IOMGR_BUILD_<name> flags just says that an I/O manager should be built + * for _some_ RTS way (i.e. threaded or non-threaded). What we need however are + * flags to use for conditional compilation of I/O manager code. These flags + * must take into account whether the particular I/O manager is enabled for the + * RTS way we're currently building, in particular taking into account if we're + * building for a threaded or non-threaded RTS. + * + * So here we define a set of derived flags IOMGR_ENABLED_<name> which says if + * each I/O manager is enabled in the RTS way we're building now. We'll then + * use these flags everywhere else for conditional compilation. + */ + +#if defined(IOMGR_BUILD_SELECT) && !defined(THREADED_RTS) + #define IOMGR_ENABLED_SELECT +#endif +#if defined(IOMGR_BUILD_MIO) && defined(THREADED_RTS) +/* For MIO, it is really two separate I/O manager implementations: one for + * Windows and one for non-Windows. This is clear from both the C code on the + * RTS side and the Haskell code in the base library. By treating them as + * such leads to simpler I/O manager dispatch code. + * + * These two implementations do share a common architecture, and so we still + * use a single name in public interfaces like ./configure and the RTS flags. + */ +#if defined(mingw32_HOST_OS) + #define IOMGR_ENABLED_MIO_WIN32 +#else + #define IOMGR_ENABLED_MIO_POSIX +#endif +#endif +#if defined(IOMGR_BUILD_WINIO) + #define IOMGR_ENABLED_WINIO +#endif +#if defined(IOMGR_BUILD_WIN32_LEGACY) && !defined(THREADED_RTS) + #define IOMGR_ENABLED_WIN32_LEGACY +#endif + +/* To provide a string to use for output of +RTS -? we use the + * IOMGR_DEFAULT_{NON_}THREADED_<name> flags to derived a CPP variable + * IOMGR_DEFAULT_STR with the string name of the default I/O manager for the + * _current_ RTS way. At the same time we can do a sanity check that there is + * actually a default. + */ +#if defined(THREADED_RTS) +#if defined(IOMGR_DEFAULT_THREADED_MIO) + #define IOMGR_DEFAULT_STR "mio" +#elif defined(IOMGR_DEFAULT_THREADED_WINIO) + #define IOMGR_DEFAULT_STR "winio" +#else +#error No I/O default manager. See IOMGR_DEFAULT_THREADED_ flags +#endif +#else // !defined(THREADED_RTS) +#if defined(IOMGR_DEFAULT_NON_THREADED_SELECT) + #define IOMGR_DEFAULT_STR "select" +#elif defined(IOMGR_DEFAULT_NON_THREADED_WINIO) + #define IOMGR_DEFAULT_STR "winio" +#elif defined(IOMGR_DEFAULT_NON_THREADED_WIN32_LEGACY) + #define IOMGR_DEFAULT_STR "win32-legacy" +#else +#error No I/O default manager. See IOMGR_DEFAULT_NON_THREADED_ flags +#endif +#endif + +/* To help with error messages we provide a macro IOMGRS_ENABLED_STR that is + * the stringy list of all enabled I/O managers (with leading and separating + * spaces) + */ +#if defined(IOMGR_ENABLED_SELECT) + #define IOMGR_ENABLED_STR_SELECT " select" +#else + #define IOMGR_ENABLED_STR_SELECT "" +#endif +#if defined(IOMGR_ENABLED_MIO_POSIX) || defined(IOMGR_ENABLED_MIO_WIN32) + #define IOMGR_ENABLED_STR_MIO " mio" +#else + #define IOMGR_ENABLED_STR_MIO "" +#endif +#if defined(IOMGR_ENABLED_WINIO) + #define IOMGR_ENABLED_STR_WINIO " winio" +#else + #define IOMGR_ENABLED_STR_WINIO "" +#endif +#if defined(IOMGR_ENABLED_WIN32_LEGACY) + #define IOMGR_ENABLED_STR_WIN32_LEGACY " win32-legacy" +#else + #define IOMGR_ENABLED_STR_WIN32_LEGACY "" +#endif +#define IOMGRS_ENABLED_STR \ + IOMGR_ENABLED_STR_SELECT \ + IOMGR_ENABLED_STR_MIO \ + IOMGR_ENABLED_STR_WINIO \ + IOMGR_ENABLED_STR_WIN32_LEGACY + /* The per-capability data structures belonging to the I/O manager. * diff --git a/rts/configure.ac b/rts/configure.ac index 76d599ec3eab81462d70a292f9badafbebf9428b..d1ae16fe407c638edf7369ef60d8dfb31fd43f13 100644 --- a/rts/configure.ac +++ b/rts/configure.ac @@ -351,6 +351,93 @@ AS_IF( [test "$CABAL_FLAG_libnuma" = 1], [AC_CHECK_HEADERS([numa.h numaif.h])]) + +dnl ** I/O managers +dnl -------------------------------------------------------------- +dnl +dnl The scheme here is that every I/O manager can be enabled/disabled +dnl at GHC build time (subject to some constraints). More than one I/O +dnl manager can be enabled to be built. At least one I/O manager +dnl supporting the threaded RTS must be enabled as well as at least +dnl one supporting the non-threaded RTS. The I/O managers enabled here +dnl become the choices available at runtime at RTS startup. The choice +dnl can be made with RTS flags. There are separate choices for the +dnl threaded and non-threaded RTS ways, because most I/O managers are +dnl specific to these ways. Furthermore we must establish a default I/O +dnl manager for the threaded and non-threaded RTS. +dnl +dnl Most I/O managers are platform-specific so there are checks to +dnl ensure each one can be enabled on the platform. Such checks are +dnl also where any system dependencies (e.g. libraries) can be checked. +dnl +dnl The output is a set of CPP flags, with one flag per named I/O manager: +dnl * IOMGR_BUILD_<name> : which ones should be built (some) +dnl * IOMGR_DEFAULT_NON_THREADED_<name> : which one is default (exactly one) +dnl * IOMGR_DEFAULT_THREADED_<name> : which one is default (exactly one) +dnl +dnl Note that IOMGR_BUILD_<name> just says that an I/O manager will be +dnl built for _some_ RTS way (i.e. threaded or non-threaded). There is +dnl a set of derived flags IOMGR_ENABLED_<name> in IOManager.h which says +dnl if each I/O manager is enabled in the "current" RTS way. These are +dnl the ones used for conditional compilation of the I/O manager code. +dnl ------------------------------------------------------------------- + +dnl Here we check for platform constraints. The result is the CPP flag +dnl IOMGR_BUILD_<name> and a EnableIOManager<Name> var for use here later. + +GHC_IOMANAGER_ENABLE([select], [EnableIOManagerSelect], [IOMGR_BUILD_SELECT], + [if test "$HostOS" = "mingw32"; then + EnableIOManagerSelect=NO + else + AC_CHECK_HEADER([sys/select.h], + [EnableIOManagerSelect=YES], + [AC_MSG_ERROR([sys/select.h required by select I/O manager])],[]) + fi]) + +GHC_IOMANAGER_ENABLE([mio], [EnableIOManagerMIO], [IOMGR_BUILD_MIO], + [EnableIOManagerMIO=YES]) + +GHC_IOMANAGER_ENABLE([win32-legacy], [EnableIOManagerWin32Legacy], [IOMGR_BUILD_WIN32_LEGACY], + [if test "$HostOS" = "mingw32"; then EnableIOManagerWin32Legacy=YES; fi]) + +GHC_IOMANAGER_ENABLE([winio], [EnableIOManagerWinIO], [IOMGR_BUILD_WINIO], + [if test "$HostOS" = "mingw32"; then EnableIOManagerWinIO=YES; fi]) + +dnl Now we establish a default I/O manager for the threaded and non-threaded +dnl RTS. We select the default based on which I/O managers are enabled. They +dnl are checked in reverse order of priority, the last enabled one wins: +if test "$HostOS" = "mingw32"; then + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerNonThreadedDefault], [winio], [EnableIOManagerWinIO],) + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerNonThreadedDefault], [win32-legacy], [EnableIOManagerWin32Legacy]) + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerThreadedDefault], [winio], [EnableIOManagerWinIO]) + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerThreadedDefault], [mio], [EnableIOManagerMIO]) +else + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerNonThreadedDefault], [select], [EnableIOManagerSelect]) + GHC_IOMANAGER_DEFAULT_SELECT([IOManagerThreadedDefault], [mio], [EnableIOManagerMIO]) +fi +GHC_IOMANAGER_DEFAULT_CHECK_NOT_EMPTY([IOManagerNonThreadedDefault],[non-threaded]) +GHC_IOMANAGER_DEFAULT_CHECK_NOT_EMPTY([IOManagerThreadedDefault],[threaded]) + +AC_MSG_NOTICE(default I/O manager for the non-threaded RTS: ${IOManagerNonThreadedDefault}) +AC_MSG_NOTICE(default I/O manager for the threaded RTS: ${IOManagerThreadedDefault}) + +dnl Now define CPP vars for the default ones (threaded and non-threaded) +GHC_IOMANAGER_DEFAULT_AC_DEFINE([IOManagerNonThreadedDefault], [non-threaded], + [select], [IOMGR_DEFAULT_NON_THREADED_SELECT]) + +GHC_IOMANAGER_DEFAULT_AC_DEFINE([IOManagerNonThreadedDefault], [non-threaded], + [winio], [IOMGR_DEFAULT_NON_THREADED_WINIO]) + +GHC_IOMANAGER_DEFAULT_AC_DEFINE([IOManagerNonThreadedDefault], [non-threaded], + [win32-legacy], [IOMGR_DEFAULT_NON_THREADED_WIN32_LEGACY]) + +GHC_IOMANAGER_DEFAULT_AC_DEFINE([IOManagerThreadedDefault], [threaded], + [mio], [IOMGR_DEFAULT_THREADED_MIO]) + +GHC_IOMANAGER_DEFAULT_AC_DEFINE([IOManagerThreadedDefault], [threaded], + [winio], [IOMGR_DEFAULT_THREADED_WINIO]) + + dnl ** Write config files dnl --------------------------------------------------------------