From 15f4d8679a180b2d1361def20fbe30cf6119730d Mon Sep 17 00:00:00 2001 From: Duncan Coutts <duncan@well-typed.com> Date: Sun, 30 Oct 2022 13:12:24 +0000 Subject: [PATCH] Initial ./configure support for selecting I/O managers In this patch we just define new CPP vars, but don't yet use them or replace the existing approach. That will follow. The intention here is that every I/O manager can be enabled/disabled at GHC build time (subject to some constraints). More than one I/O manager can be enabled to be built. At least one I/O manager supporting the non-threaded RTS must be enabled as well as at least one supporting the non-threaded RTS. The I/O managers enabled here will become the choices available at runtime at RTS startup (in later patches). The choice can be made with RTS flags. There are separate sets of choices for the threaded and non-threaded RTS ways, because most I/O managers are specific to these ways. Furthermore we must establish a default I/O manager for the threaded and non-threaded RTS. Most I/O managers are platform-specific so there are checks to ensure each one can be enabled on the platform. Such checks are also where (in future) any system dependencies (e.g. libraries) can be checked. The output is a set of CPP flags (in the mk/config.h file), with one flag per 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) and a set of derived flags in IOManager.h * IOMGR_ENABLED_<name> : enabled for the current RTS way Note that IOMGR_BUILD_<name> just says that an I/O manager will be built for _some_ RTS way (i.e. threaded or non-threaded). The derived flags IOMGR_ENABLED_<name> in IOManager.h say if each I/O manager is enabled in the "current" RTS way. These are the ones that can be used for conditional compilation of the I/O manager code. Co-authored-by: Pi Delport <pi@well-typed.com> --- m4/ghc_iomanagers.m4 | 40 ++++++++++++++++++ rts/IOManager.h | 98 ++++++++++++++++++++++++++++++++++++++++++++ rts/configure.ac | 87 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 m4/ghc_iomanagers.m4 diff --git a/m4/ghc_iomanagers.m4 b/m4/ghc_iomanagers.m4 new file mode 100644 index 000000000000..dd15758b8d26 --- /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 bd7ce35ff753..df5f72cdd840 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 76d599ec3eab..d1ae16fe407c 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 -------------------------------------------------------------- -- GitLab