Compare commits

...

7 Commits

Author SHA1 Message Date
John Ravi
d02e931dca updating for generic libcody interface 2020-09-24 03:53:47 +00:00
John Ravi
9eebf96f87 1. renamed libcody lto functions to invoke functions
2. invoke (send to libcody) all the lto trans commands at once
2020-08-29 07:06:28 +00:00
John Ravi
c184dfeffa check lto compilation status 2020-08-23 19:35:35 -07:00
John Ravi
a3385aceea Merge remote-tracking branch 'origin/master' into devel/lto-offload 2020-08-19 19:52:29 +00:00
John Ravi
c647b271e8 adding libcody to lto-wrapper, fork_execute serially 2020-06-30 21:33:25 -04:00
John Ravi
5946cce94d Revert "adding libcody to lto-wrapper, with some leftover debugging code"
This reverts commit 0a1ce58cbd.
2020-06-30 17:31:20 -04:00
John Ravi
0a1ce58cbd adding libcody to lto-wrapper, with some leftover debugging code 2020-06-27 17:21:36 -07:00
14 changed files with 2406 additions and 14 deletions

View File

@@ -226,6 +226,8 @@ HOST_EXPORTS = \
GMPINC="$(HOST_GMPINC)"; export GMPINC; \
ISLLIBS="$(HOST_ISLLIBS)"; export ISLLIBS; \
ISLINC="$(HOST_ISLINC)"; export ISLINC; \
CODYLIB="$(HOST_CODYLIB)"; export CODYLIB; \
CODYLIBINC="$(HOST_CODYLIBINC)"; export CODYLIBINC; \
LIBELFLIBS="$(HOST_LIBELFLIBS)"; export LIBELFLIBS; \
LIBELFINC="$(HOST_LIBELFINC)"; export LIBELFINC; \
XGCC_FLAGS_FOR_TARGET="$(XGCC_FLAGS_FOR_TARGET)"; export XGCC_FLAGS_FOR_TARGET; \
@@ -329,6 +331,10 @@ HOST_GMPINC = @gmpinc@
HOST_ISLLIBS = @isllibs@
HOST_ISLINC = @islinc@
# Where to find libcody
HOST_CODYLIB = @codylib@
HOST_CODYLIBINC = @codylibinc@
# Where to find libelf
HOST_LIBELFLIBS = @libelflibs@
HOST_LIBELFINC = @libelfinc@

View File

@@ -229,6 +229,8 @@ HOST_EXPORTS = \
GMPINC="$(HOST_GMPINC)"; export GMPINC; \
ISLLIBS="$(HOST_ISLLIBS)"; export ISLLIBS; \
ISLINC="$(HOST_ISLINC)"; export ISLINC; \
CODYLIB="$(HOST_CODYLIB)"; export CODYLIB; \
CODYLIBINC="$(HOST_CODYLIBINC)"; export CODYLIBINC; \
LIBELFLIBS="$(HOST_LIBELFLIBS)"; export LIBELFLIBS; \
LIBELFINC="$(HOST_LIBELFINC)"; export LIBELFINC; \
XGCC_FLAGS_FOR_TARGET="$(XGCC_FLAGS_FOR_TARGET)"; export XGCC_FLAGS_FOR_TARGET; \
@@ -332,6 +334,10 @@ HOST_GMPINC = @gmpinc@
HOST_ISLLIBS = @isllibs@
HOST_ISLINC = @islinc@
# Where to find libcody
HOST_CODYLIB = @codylib@
HOST_CODYLIBINC = @codylibinc@
# Where to find libelf
HOST_LIBELFLIBS = @libelflibs@
HOST_LIBELFINC = @libelfinc@

60
configure vendored
View File

@@ -688,6 +688,8 @@ poststage1_ldflags
poststage1_libs
stage1_ldflags
stage1_libs
codylibinc
codylib
extra_isl_gmp_configure_flags
extra_mpc_mpfr_configure_flags
extra_mpc_gmp_configure_flags
@@ -755,6 +757,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -806,6 +809,9 @@ with_gmp_dir
with_gmp
with_gmp_include
with_gmp_lib
with_libcody
with_libcody_include
with_libcody_lib
with_stage1_libs
with_static_standard_libraries
with_stage1_ldflags
@@ -921,6 +927,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1173,6 +1180,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1310,7 +1326,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1470,6 +1486,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1580,6 +1597,14 @@ Optional Packages:
--with-gmp-lib=PATH/lib
--with-gmp-include=PATH specify directory for installed GMP include files
--with-gmp-lib=PATH specify directory for the installed GMP library
--with-libcody=PATH specify prefix directory for installed libcody
package. Equivalent to
--with-libcody-include=PATH/include plus
--with-libcody-lib=PATH/lib
--with-libcody-include=PATH
specify directory for installed libcody include
files
--with-libcody-lib=PATH specify directory for the installed libcody library
--with-stage1-libs=LIBS libraries for stage1
--with-static-standard-libraries
use -static-libstdc++ and -static-libgcc
@@ -6938,6 +6963,39 @@ fi
# Specify a location for libcody
# Check whether --with-libcody was given.
if test "${with_libcody+set}" = set; then :
withval=$with_libcody;
fi
# Check whether --with-libcody-include was given.
if test "${with_libcody_include+set}" = set; then :
withval=$with_libcody_include;
fi
# Check whether --with-libcody-lib was given.
if test "${with_libcody_lib+set}" = set; then :
withval=$with_libcody_lib;
fi
if test "x$with_libcody" != x; then
codylib="-L$with_libcody/lib"
codylibinc="-I$with_libcody/include"
fi
if test "x$with_libcody_include" != x; then
codylibinc="-I$with_libcody_include"
fi
if test "x$with_libcody_lib" != x; then
codylib="-L$with_libcody_lib"
fi
# Libraries to use for stage1 or when not bootstrapping.
# Check whether --with-stage1-libs was given.

View File

@@ -1708,6 +1708,32 @@ AC_SUBST(extra_mpc_gmp_configure_flags)
AC_SUBST(extra_mpc_mpfr_configure_flags)
AC_SUBST(extra_isl_gmp_configure_flags)
# Specify a location for libcody
AC_ARG_WITH(libcody,
[AS_HELP_STRING([--with-libcody=PATH],
[specify prefix directory for installed libcody package.
Equivalent to --with-libcody-include=PATH/include
plus --with-libcody-lib=PATH/lib])])
AC_ARG_WITH(libcody-include,
[AS_HELP_STRING([--with-libcody-include=PATH],
[specify directory for installed libcody include files])])
AC_ARG_WITH(libcody-lib,
[AS_HELP_STRING([--with-libcody-lib=PATH],
[specify directory for the installed libcody library])])
if test "x$with_libcody" != x; then
codylib="-L$with_libcody/lib"
codylibinc="-I$with_libcody/include"
fi
if test "x$with_libcody_include" != x; then
codylibinc="-I$with_libcody_include"
fi
if test "x$with_libcody_lib" != x; then
codylib="-L$with_libcody_lib"
fi
AC_SUBST(codylib)
AC_SUBST(codylibinc)
# Libraries to use for stage1 or when not bootstrapping.
AC_ARG_WITH(stage1-libs,
[AS_HELP_STRING([--with-stage1-libs=LIBS], [libraries for stage1])],

View File

@@ -388,6 +388,10 @@ GMPINC = @GMPINC@
ISLLIBS = @ISLLIBS@
ISLINC = @ISLINC@
# How to find libcody
CODYLIB = @CODYLIB@ -lcody
CODYLIBINC = @CODYLIBINC@
# Set to 'yes' if the LTO front end is enabled.
enable_lto = @enable_lto@
@@ -1068,7 +1072,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
# and the system's installed libraries.
LIBS = @LIBS@ libcommon.a $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) \
$(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS)
BACKENDLIBS = $(ISLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \
BACKENDLIBS = $(ISLLIBS) $(GMPLIBS) $(CODYLIB) $(PLUGINLIBS) $(HOST_LIBS) \
$(ZLIB) $(ZSTD_LIB)
# Any system libraries needed just for GNAT.
SYSLIBS = @GNAT_LIBEXC@
@@ -1102,7 +1106,7 @@ BUILD_ERRORS = build/errors.o
# libintl.h will be found in ../intl if we are using the included libintl.
INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
-I$(srcdir)/../include @INCINTL@ \
$(CPPINC) $(GMPINC) $(DECNUMINC) $(BACKTRACEINC) \
$(CPPINC) $(GMPINC) $(CODYLIBINC) $(DECNUMINC) $(BACKTRACEINC) \
$(ISLINC)
COMPILE.base = $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) -o $@
@@ -1686,7 +1690,7 @@ ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OBJS) $(OBJS-libcommon) \
$(OBJS-libcommon-target) main.o c-family/cppspec.o \
$(COLLECT2_OBJS) $(EXTRA_GCC_OBJS) $(GCOV_OBJS) $(GCOV_DUMP_OBJS) \
$(GCOV_TOOL_OBJS) $(GENGTYPE_OBJS) gcc-ar.o gcc-nm.o gcc-ranlib.o \
lto-wrapper.o collect-utils.o
lto-wrapper.o mapper-client.o mapper-resolver.o mapper-server.o collect-utils.o
# for anything that is shared use the cc1plus profile data, as that
# is likely the most exercised during the build
@@ -1761,16 +1765,22 @@ SELFTEST_DEPS = $(GCC_PASSES) stmp-int-hdrs $(srcdir)/testsuite/selftests
gnat_install_lib = @gnat_install_lib@
# per-language makefile fragments
-include $(LANG_MAKEFRAGS)
ifneq ($(LANG_MAKEFRAGS),)
include $(LANG_MAKEFRAGS)
endif
# target and host overrides must follow the per-language makefile fragments
# so they can override or augment language-specific variables
# target overrides
-include $(tmake_file)
ifneq ($(tmake_file),)
include $(tmake_file)
endif
# host overrides
-include $(xmake_file)
ifneq ($(xmake_file),)
include $(xmake_file)
endif
# all-tree.def includes all the tree.def files.
all-tree.def: s-alltree; @true
@@ -2185,12 +2195,28 @@ collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
CFLAGS-collect2.o += -DTARGET_MACHINE=\"$(target_noncanonical)\" \
@TARGET_SYSTEM_ROOT_DEFINE@
LTO_WRAPPER_OBJS = lto-wrapper.o collect-utils.o ggc-none.o
LTO_WRAPPER_OBJS = lto-wrapper.o mapper-client.o mapper-resolver.o collect-utils.o ggc-none.o
lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o T$@ \
$(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS)
$(LTO_WRAPPER_OBJS) libcommon-target.a $(CODYLIB) $(LIBS)
mv -f T$@ $@
#MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o
#mapper-server$(exeext): $(MAPPER_SERVER_OBJS) $(LIBDEPS)
# +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
# $(MAPPER_SERVER_OBJS) version.o $(CODYLIB) $(LIBIBERTY) $(LIBINTL)
MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o collect-utils.o
mapper-server$(exeext): $(MAPPER_SERVER_OBJS) libcommon-target.a $(LIBDEPS)
+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
$(MAPPER_SERVER_OBJS) libcommon-target.a version.o $(CODYLIB) $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) $(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS)
#MAPPER_SERVER_OBJS := mapper-server.o mapper-resolver.o collect-utils.o
#mapper-server$(exeext): $(MAPPER_SERVER_OBJS) libcommon-target.a $(LIBDEPS)
# +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
# $(MAPPER_SERVER_OBJS) libcommon-target.a version.o $(CODYLIB) $(LIBS)
# Files used by all variants of C or by the stand-alone pre-processor.
CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
@@ -3678,6 +3704,10 @@ install-common: native lang.install-common installdirs
gcov-dump$(exeext) $(DESTDIR)$(bindir)/$(GCOV_DUMP_INSTALL_NAME)$(exeext); \
fi; \
fi
rm -f $(DESTDIR)$(libexecsubdir)/mapper-server$(exeext)
$(INSTALL_PROGRAM) mapper-server$(exeext) \
$(DESTDIR)$(libexecsubdir)/mapper-server$(exeext)
# Install the driver program as $(target_noncanonical)-gcc,
# $(target_noncanonical)-gcc-$(version), and also as gcc if native.

View File

@@ -302,6 +302,24 @@
#endif
/* Define if accept4 provided. */
#ifndef USED_FOR_TARGET
#undef HAVE_ACCEPT4
#endif
/* Define if AF_INET6 supported. */
#ifndef USED_FOR_TARGET
#undef HAVE_AF_INET6
#endif
/* Define if AF_UNIX supported. */
#ifndef USED_FOR_TARGET
#undef HAVE_AF_UNIX
#endif
/* Define if your assembler supports architecture modifiers. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_ARCHITECTURE_MODIFIERS
@@ -1155,6 +1173,18 @@
#endif
/* Define if epoll_create, epoll_ctl, epoll_pwait provided. */
#ifndef USED_FOR_TARGET
#undef HAVE_EPOLL
#endif
/* Define to 1 if you have the `execv' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_EXECV
#endif
/* Define to 1 if you have the <ext/hash_map> header file. */
#ifndef USED_FOR_TARGET
#undef HAVE_EXT_HASH_MAP
@@ -1425,6 +1455,12 @@
#endif
/* Define if inet_ntop provided. */
#ifndef USED_FOR_TARGET
#undef HAVE_INET_NTOP
#endif
/* Define 0/1 if .init_array/.fini_array sections are available and working.
*/
#ifndef USED_FOR_TARGET
@@ -1689,6 +1725,12 @@
#endif
/* Define to 1 if you have the `memrchr' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_MEMRCHR
#endif
/* Define to 1 if you have the `mmap' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_MMAP
@@ -1732,6 +1774,18 @@
#endif
/* Define to 1 if you have the `posix_fallocate' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_POSIX_FALLOCATE
#endif
/* Define if pselect provided. */
#ifndef USED_FOR_TARGET
#undef HAVE_PSELECT
#endif
/* Define to 1 if you have the `putchar_unlocked' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_PUTCHAR_UNLOCKED
@@ -1744,6 +1798,12 @@
#endif
/* Define if select provided. */
#ifndef USED_FOR_TARGET
#undef HAVE_SELECT
#endif
/* Define to 1 if you have the `setlocale' function. */
#ifndef USED_FOR_TARGET
#undef HAVE_SETLOCALE
@@ -1756,6 +1816,12 @@
#endif
/* Define if <sys/signal.h> defines sighandler_t */
#ifndef USED_FOR_TARGET
#undef HAVE_SIGHANDLER_T
#endif
/* Define if the system-provided CRTs are present on Solaris. */
#ifndef USED_FOR_TARGET
#undef HAVE_SOLARIS_CRTS

306
gcc/configure vendored
View File

@@ -639,6 +639,8 @@ PICFLAG
enable_host_shared
enable_plugin
pluginlibs
CODYLIBINC
CODYLIB
ISLINC
ISLLIBS
GMPINC
@@ -1038,7 +1040,9 @@ CPP
GMPLIBS
GMPINC
ISLLIBS
ISLINC'
ISLINC
CODYLIB
CODYLIBINC'
# Initialize some variables set by options.
@@ -1866,6 +1870,8 @@ Some influential environment variables:
GMPINC How to find GMP include files
ISLLIBS How to link isl
ISLINC How to find isl include files
CODYLIB How to link Cody
CODYLIBINC How to find Cody include files
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -10192,6 +10198,14 @@ _ACEOF
fi
ac_fn_cxx_check_type "$LINENO" "sighander_t" "ac_cv_type_sighander_t" "signal.h
"
if test "x$ac_cv_type_sighander_t" = xyes; then :
$as_echo "#define HAVE_SIGHANDLER_T 1" >>confdefs.h
fi
ac_fn_cxx_check_header_preproc "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h"
@@ -11915,6 +11929,296 @@ $as_echo "#define HOST_HAS_F_SETLKW 1" >>confdefs.h
fi
# C++ Modules would like some networking features to provide the mapping
# server. You can still use modules without them though.
# The following network-related checks could probably do with some
# Windows and other non-linux defenses and checking.
# Local socket connectivity wants AF_UNIX networking
# Check for AF_UNIX networking
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AF_UNIX" >&5
$as_echo_n "checking for AF_UNIX... " >&6; }
if ${ac_cv_af_unix+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
int
main ()
{
sockaddr_un un;
un.sun_family = AF_UNSPEC;
int fd = socket (AF_UNIX, SOCK_STREAM, 0);
connect (fd, (sockaddr *)&un, sizeof (un));
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_af_unix=yes
else
ac_cv_af_unix=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_af_unix" >&5
$as_echo "$ac_cv_af_unix" >&6; }
if test $ac_cv_af_unix = yes; then
$as_echo "#define HAVE_AF_UNIX 1" >>confdefs.h
fi
# Remote socket connectivity wants AF_INET6 networking
# Check for AF_INET6 networking
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for AF_INET6" >&5
$as_echo_n "checking for AF_INET6... " >&6; }
if ${ac_cv_af_inet6+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int
main ()
{
sockaddr_in6 in6;
in6.sin6_family = AF_UNSPEC;
struct addrinfo *addrs = 0;
struct addrinfo hints;
hints.ai_flags = 0;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_canonname = 0;
hints.ai_addr = 0;
hints.ai_next = 0;
int e = getaddrinfo ("localhost", 0, &hints, &addrs);
const char *str = gai_strerror (e);
freeaddrinfo (addrs);
int fd = socket (AF_INET6, SOCK_STREAM, 0);
connect (fd, (sockaddr *)&in6, sizeof (in6));
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_af_inet6=yes
else
ac_cv_af_inet6=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_af_inet6" >&5
$as_echo "$ac_cv_af_inet6" >&6; }
if test $ac_cv_af_inet6 = yes; then
$as_echo "#define HAVE_AF_INET6 1" >>confdefs.h
fi
# Efficient server response wants epoll
# Check for epoll_create, epoll_ctl, epoll_pwait
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for epoll" >&5
$as_echo_n "checking for epoll... " >&6; }
if ${ac_cv_epoll+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/epoll.h>
int
main ()
{
int fd = epoll_create (1);
epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = 0;
epoll_ctl (fd, EPOLL_CTL_ADD, 0, &ev);
epoll_pwait (fd, 0, 0, -1, 0);
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_epoll=yes
else
ac_cv_epoll=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_epoll" >&5
$as_echo "$ac_cv_epoll" >&6; }
if test $ac_cv_epoll = yes; then
$as_echo "#define HAVE_EPOLL 1" >>confdefs.h
fi
# If we can't use epoll, try pselect.
# Check for pselect
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pselect" >&5
$as_echo_n "checking for pselect... " >&6; }
if ${ac_cv_pselect+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/select.h>
int
main ()
{
pselect (0, 0, 0, 0, 0, 0);
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_pselect=yes
else
ac_cv_pselect=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pselect" >&5
$as_echo "$ac_cv_pselect" >&6; }
if test $ac_cv_pselect = yes; then
$as_echo "#define HAVE_PSELECT 1" >>confdefs.h
fi
# And failing that, use good old select.
# If we can't even use this, the server is serialized.
# Check for select
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for select" >&5
$as_echo_n "checking for select... " >&6; }
if ${ac_cv_select+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/select.h>
int
main ()
{
select (0, 0, 0, 0, 0);
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_select=yes
else
ac_cv_select=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_select" >&5
$as_echo "$ac_cv_select" >&6; }
if test $ac_cv_select = yes; then
$as_echo "#define HAVE_SELECT 1" >>confdefs.h
fi
# Avoid some fnctl calls by using accept4, when available.
# Check for accept4
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for accept4" >&5
$as_echo_n "checking for accept4... " >&6; }
if ${ac_cv_accept4+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/socket.h>
int
main ()
{
int err = accept4 (1, 0, 0, SOCK_NONBLOCK);
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_accept4=yes
else
ac_cv_accept4=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_accept4" >&5
$as_echo "$ac_cv_accept4" >&6; }
if test $ac_cv_accept4 = yes; then
$as_echo "#define HAVE_ACCEPT4 1" >>confdefs.h
fi
# For better server messages, look for a way to stringize network addresses
# Check for inet_ntop
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop" >&5
$as_echo_n "checking for inet_ntop... " >&6; }
if ${ac_cv_inet_ntop+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <arpa/inet.h>
#include <netinet/in.h>
int
main ()
{
sockaddr_in6 in6;
char buf[INET6_ADDRSTRLEN];
const char *str = inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ac_cv_inet_ntop=yes
else
ac_cv_inet_ntop=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_inet_ntop" >&5
$as_echo "$ac_cv_inet_ntop" >&6; }
if test $ac_cv_inet_ntop = yes; then
$as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h
fi
# Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
CFLAGS="$saved_CFLAGS"
CXXFLAGS="$saved_CXXFLAGS"

View File

@@ -1430,6 +1430,10 @@ fi
AC_CHECK_TYPE(ssize_t, int)
AC_CHECK_TYPE(caddr_t, char *)
AC_CHECK_TYPE(sighander_t,
AC_DEFINE(HAVE_SIGHANDLER_T, 1,
[Define if <sys/signal.h> defines sighandler_t]),
,signal.h)
GCC_AC_FUNC_MMAP_BLACKLIST
@@ -1575,6 +1579,136 @@ if test $ac_cv_f_setlkw = yes; then
[Define if F_SETLKW supported by fcntl.])
fi
# C++ Modules would like some networking features to provide the mapping
# server. You can still use modules without them though.
# The following network-related checks could probably do with some
# Windows and other non-linux defenses and checking.
# C++ LTO will take advantage of these networking features too.
# Local socket connectivity wants AF_UNIX networking
# Check for AF_UNIX networking
AC_CACHE_CHECK(for AF_UNIX, ac_cv_af_unix, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>]],[[
sockaddr_un un;
un.sun_family = AF_UNSPEC;
int fd = socket (AF_UNIX, SOCK_STREAM, 0);
connect (fd, (sockaddr *)&un, sizeof (un));]])],
[ac_cv_af_unix=yes],
[ac_cv_af_unix=no])])
if test $ac_cv_af_unix = yes; then
AC_DEFINE(HAVE_AF_UNIX, 1,
[Define if AF_UNIX supported.])
fi
# Remote socket connectivity wants AF_INET6 networking
# Check for AF_INET6 networking
AC_CACHE_CHECK(for AF_INET6, ac_cv_af_inet6, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>]],[[
sockaddr_in6 in6;
in6.sin6_family = AF_UNSPEC;
struct addrinfo *addrs = 0;
struct addrinfo hints;
hints.ai_flags = 0;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_canonname = 0;
hints.ai_addr = 0;
hints.ai_next = 0;
int e = getaddrinfo ("localhost", 0, &hints, &addrs);
const char *str = gai_strerror (e);
freeaddrinfo (addrs);
int fd = socket (AF_INET6, SOCK_STREAM, 0);
connect (fd, (sockaddr *)&in6, sizeof (in6));]])],
[ac_cv_af_inet6=yes],
[ac_cv_af_inet6=no])])
if test $ac_cv_af_inet6 = yes; then
AC_DEFINE(HAVE_AF_INET6, 1,
[Define if AF_INET6 supported.])
fi
# Efficient server response wants epoll
# Check for epoll_create, epoll_ctl, epoll_pwait
AC_CACHE_CHECK(for epoll, ac_cv_epoll, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/epoll.h>]],[[
int fd = epoll_create (1);
epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = 0;
epoll_ctl (fd, EPOLL_CTL_ADD, 0, &ev);
epoll_pwait (fd, 0, 0, -1, 0);]])],
[ac_cv_epoll=yes],
[ac_cv_epoll=no])])
if test $ac_cv_epoll = yes; then
AC_DEFINE(HAVE_EPOLL, 1,
[Define if epoll_create, epoll_ctl, epoll_pwait provided.])
fi
# If we can't use epoll, try pselect.
# Check for pselect
AC_CACHE_CHECK(for pselect, ac_cv_pselect, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/select.h>]],[[
pselect (0, 0, 0, 0, 0, 0);]])],
[ac_cv_pselect=yes],
[ac_cv_pselect=no])])
if test $ac_cv_pselect = yes; then
AC_DEFINE(HAVE_PSELECT, 1,
[Define if pselect provided.])
fi
# And failing that, use good old select.
# If we can't even use this, the server is serialized.
# Check for select
AC_CACHE_CHECK(for select, ac_cv_select, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/select.h>]],[[
select (0, 0, 0, 0, 0);]])],
[ac_cv_select=yes],
[ac_cv_select=no])])
if test $ac_cv_select = yes; then
AC_DEFINE(HAVE_SELECT, 1,
[Define if select provided.])
fi
# Avoid some fnctl calls by using accept4, when available.
# Check for accept4
AC_CACHE_CHECK(for accept4, ac_cv_accept4, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/socket.h>]],[[
int err = accept4 (1, 0, 0, SOCK_NONBLOCK);]])],
[ac_cv_accept4=yes],
[ac_cv_accept4=no])])
if test $ac_cv_accept4 = yes; then
AC_DEFINE(HAVE_ACCEPT4, 1,
[Define if accept4 provided.])
fi
# For better server messages, look for a way to stringize network addresses
# Check for inet_ntop
AC_CACHE_CHECK(for inet_ntop, ac_cv_inet_ntop, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <arpa/inet.h>
#include <netinet/in.h>]],[[
sockaddr_in6 in6;
char buf[INET6_ADDRSTRLEN];
const char *str = inet_ntop (AF_INET6, &in6, buf, sizeof (buf));]])],
[ac_cv_inet_ntop=yes],
[ac_cv_inet_ntop=no])])
if test $ac_cv_inet_ntop = yes; then
AC_DEFINE(HAVE_INET_NTOP, 1,
[Define if inet_ntop provided.])
fi
# Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
CFLAGS="$saved_CFLAGS"
CXXFLAGS="$saved_CXXFLAGS"
@@ -6683,6 +6817,9 @@ if test "x${ISLLIBS}" != "x" ; then
AC_DEFINE(HAVE_isl, 1, [Define if isl is in use.])
fi
AC_ARG_VAR(CODYLIB,[How to link Cody])
AC_ARG_VAR(CODYLIBINC,[How to find Cody include files])
GCC_ENABLE_PLUGINS
AC_SUBST(pluginlibs)
AC_SUBST(enable_plugin)

View File

@@ -46,7 +46,7 @@ CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h ope
# Note that it would be nice to move the dependency on g++
# into the C++ rule, but that needs a little bit of work
# to do the right thing within all.cross.
c++: cc1plus$(exeext)
c++: cc1plus$(exeext) mapper-server$(exeext)
# Tell GNU make to ignore these if they exist.
.PHONY: c++

View File

@@ -48,6 +48,11 @@ along with GCC; see the file COPYING3. If not see
#include "simple-object.h"
#include "lto-section-names.h"
#include "collect-utils.h"
#include <stdio.h>
#include <unistd.h>
#define MAPPER_FOR_GCC 1
#include "mapper.h"
/* Environment variable, used for passing the names of offload targets from GCC
driver to lto-wrapper. */
@@ -84,6 +89,45 @@ static bool xassembler_options_error = false;
const char tool_name[] = "lto-wrapper";
/********************************************************************/
// FIXME: Put in header somewhere, and maybe verify value
static const location_t main_source_loc = 32;
/* Our module mapper (created lazily). */
module_client *mapper;
static module_client *make_mapper (location_t loc);
inline module_client *get_mapper (location_t loc) {
auto *res = mapper;
if (!res)
res = make_mapper (loc);
return res;
}
/********************************************************************/
/* Create a new mapper connecting to OPTION. */
module_client *
make_mapper (location_t loc)
{
//const char *option = module_mapper_name;
//if (!option)
// option = getenv ("CXX_MODULE_MAPPER");
const char *option = getenv ("CXX_MODULE_MAPPER");
fprintf(stderr, "\tCXX_MODULE_MAPPER option: %s\n", option);
//mapper = module_client::open_module_client(loc, option, &set_cmi_repo, (save_decoded_options[0].opt_index == OPT_SPECIAL_program_name) && save_decoded_options[0].arg != progname ? save_decoded_options[0].arg : nullptr);
fprintf(stderr, "\tcalling module_client constructor\n");
mapper = module_client::open_module_client(loc, option, nullptr, nullptr);
return mapper;
}
/* Delete tempfiles. Called from utils_cleanup. */
void
@@ -1874,6 +1918,9 @@ cont:
qsort (ltrans_priorities, nr, sizeof (int) * 2, cmp_priority);
}
auto *mapper = get_mapper (main_source_loc);
mapper->Cork();
/* Execute the LTRANS stage for each input file (or prepare a
makefile to invoke this in parallel). */
for (i = 0; i < nr; ++i)
@@ -1917,13 +1964,42 @@ cont:
}
else
{
fork_execute (new_argv[0], CONST_CAST (char **, new_argv),
true);
maybe_unlink (input_name);
// TODO: better way to figure out the number of arguments?
for (j = 1; new_argv[j] != NULL; ++j);
fprintf(stderr, "argc: %d\n", j);
mapper->InvokeSubProcess(new_argv, j);
// TODO: unlink input file somewhere
// maybe_unlink (input_name);
}
output_names[i] = output_name;
}
auto response = mapper->Uncork();
auto r_iter = response.begin ();
while(r_iter != response.end()) {
Cody::Packet const &p = *r_iter;
if(p.GetCode() == Cody::Client::PC_OK) {
fprintf(stderr, "\tlto compilation succeeded\n");
}
else {
if(!p.GetString().empty()) {
fprintf(stderr, "\tlto compilation failure message: %s\n", p.GetString().c_str());
}
else {
fprintf(stderr, "\tlto compilation unknown failure\n");
}
}
++r_iter;
}
fprintf(stderr, "\n");
if (parallel)
{
struct pex_obj *pex;

302
gcc/mapper-client.cc Normal file
View File

@@ -0,0 +1,302 @@
/* C++ modules. Experimental!
Copyright (C) 2017-2020 Free Software Foundation, Inc.
Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "line-map.h"
#include "diagnostic-core.h"
#define MAPPER_FOR_GCC 1
#include "mapper.h"
module_client::module_client (pex_obj *p, int fd_from, int fd_to)
: Client (fd_from, fd_to), pex (p)
{
}
static module_client *
spawn_mapper_program (char const **errmsg, std::string &name,
char const *full_program_name)
{
/* Split writable at white-space. No space-containing args for
you! */
// At most every other char could be an argument
char **argv = new char *[name.size () / 2 + 2];
unsigned arg_no = 0;
char *str = new char[name.size ()];
memcpy (str, name.c_str () + 1, name.size ());
for (auto ptr = str; ; ++ptr)
{
while (*ptr == ' ')
ptr++;
if (!*ptr)
break;
argv[arg_no++] = ptr;
while (*ptr && *ptr != ' ')
ptr++;
if (!*ptr)
break;
*ptr = 0;
}
argv[arg_no] = nullptr;
auto *pex = pex_init (PEX_USE_PIPES, progname, NULL);
FILE *to = pex_input_pipe (pex, false);
name = argv[0];
if (!to)
*errmsg = "connecting input";
else
{
int flags = PEX_SEARCH;
if (full_program_name)
{
/* Prepend the invoking path. */
size_t dir_len = progname - full_program_name;
std::string argv0;
argv0.reserve (dir_len + name.size ());
argv0.append (full_program_name, dir_len).append (name);
name = std::move (argv0);
argv[0] = const_cast <char *> (name.c_str ());
flags = 0;
}
int err;
*errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err);
}
delete[] str;
delete[] argv;
int fd_from = -1, fd_to = -1;
if (!*errmsg)
{
FILE *from = pex_read_output (pex, false);
if (from && (fd_to = dup (fileno (to))) >= 0)
fd_from = fileno (from);
else
*errmsg = "connecting output";
fclose (to);
}
if (*errmsg)
{
pex_free (pex);
return nullptr;
}
return new module_client (pex, fd_from, fd_to);
}
module_client *
module_client::open_module_client (location_t loc, const char *o,
void (*set_repo) (const char *),
char const *full_program_name)
{
module_client *c = nullptr;
std::string ident;
std::string name;
char const *errmsg = nullptr;
if (o && o[0])
{
/* Maybe a local or ipv6 address. */
name = o;
auto last = name.find_last_of ('?');
if (last != name.npos)
{
ident = name.substr (last + 1);
name.erase (last);
}
if (name.size ())
{
switch (name[0])
{
case '<':
// <from>to or <>fromto, or <>
{
int fd_from = -1, fd_to = -1;
char const *ptr = name.c_str ();
char *eptr;
fd_from = strtoul (++ptr, &eptr, 0);
if (*eptr == '>')
{
ptr = eptr;
fd_to = strtoul (++ptr, &eptr, 0);
if (eptr != ptr && ptr == name.c_str () + 1)
fd_from = fd_to;
}
if (*eptr)
errmsg = "parsing";
else
{
if (name.size () == 2)
{
fd_from = fileno (stdin);
fd_to = fileno (stdout);
}
c = new module_client (fd_from, fd_to);
}
}
break;
case '=':
// =localsocket
{
int fd = Cody::OpenLocal (&errmsg, name.c_str () + 1);
if (fd >= 0)
c = new module_client (fd, fd);
}
break;
case '|':
// |program and args
c = spawn_mapper_program (&errmsg, name, full_program_name);
break;
default:
// file or hostname:port
{
auto colon = name.find_last_of (':');
if (colon != name.npos)
{
char const *cptr = name.c_str () + colon;
char *endp;
unsigned port = strtoul (cptr + 1, &endp, 10);
if (port && endp != cptr + 1 && !*endp)
{
name[colon] = 0;
int fd = Cody::OpenInet6 (&errmsg, name.c_str (), port);
name[colon] = ':';
if (fd >= 0)
c = new module_client (fd, fd);
}
}
}
break;
}
}
}
if (!c)
{
// Make a default in-process client
auto r = new module_resolver ();
auto *s = new Cody::Server (r);
c = new module_client (s);
if (!errmsg && !name.empty ())
{
int fd = open (name.c_str (), O_RDONLY | O_CLOEXEC);
if (fd < 0)
errmsg = "opening";
else
{
if (r->read_tuple_file (fd, ident, false))
errmsg = "reading";
close (fd);
}
}
else
{
r->set_repo ("gcm.cache");
r->set_default (true);
}
}
#ifdef SIGPIPE
if (!c->IsDirect ())
/* We need to ignore sig pipe for a while. */
c->sigpipe = signal (SIGPIPE, SIG_IGN);
#endif
if (errmsg)
error_at (loc, "failed %s mapper %qs", errmsg, name.c_str ());
// now wave hello!
c->Cork ();
c->Connect (std::string ("GCC"), ident);
//c->ModuleRepo ();
auto packets = c->Uncork ();
auto &connect = packets[0];
if (connect.GetCode () == Cody::Client::PC_CONNECT)
;
else if (connect.GetCode () == Cody::Client::PC_ERROR)
error_at (loc, "failed mapper handshake %s", connect.GetString ().c_str ());
//auto &repo = packets[1];
//if (repo.GetCode () == Cody::Client::PC_MODULE_REPO)
// set_repo (repo.GetString ().c_str ());
return c;
}
void
module_client::close_module_client (location_t loc, module_client *mapper)
{
if (mapper->IsDirect ())
{
auto *s = mapper->GetServer ();
auto *r = s->GetResolver ();
delete s;
delete r;
}
else
{
if (mapper->pex)
{
int fd_write = mapper->GetFDWrite ();
if (fd_write >= 0)
close (fd_write);
int status;
pex_get_status (mapper->pex, 1, &status);
pex_free (mapper->pex);
mapper->pex = NULL;
if (WIFSIGNALED (status))
error_at (loc, "mapper died by signal %s",
strsignal (WTERMSIG (status)));
else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
error_at (loc, "mapper exit status %d",
WEXITSTATUS (status));
}
else
{
int fd_read = mapper->GetFDRead ();
close (fd_read);
}
#ifdef SIGPIPE
// Restore sigpipe
if (mapper->sigpipe != SIG_IGN)
signal (SIGPIPE, mapper->sigpipe);
#endif
}
delete mapper;
}

271
gcc/mapper-resolver.cc Normal file
View File

@@ -0,0 +1,271 @@
/* C++ modules. Experimental! -*- c++-mode -*-
Copyright (C) 2017-2020 Free Software Foundation, Inc.
Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "mapper.h"
// C++
#include <algorithm>
// C
#include <cstring>
// OS
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "collect-utils.h"
module_resolver::module_resolver (bool def)
: provide_default (def)
{
}
module_resolver::~module_resolver ()
{
if (fd_repo >= 0)
close (fd_repo);
}
bool
module_resolver::set_repo (std::string &&r, bool force)
{
if (force || repo.empty ())
{
repo = std::move (r);
force = true;
}
return force;
}
bool
module_resolver::add_mapping (std::string &&module, std::string &&file,
bool force)
{
auto res = map.emplace (std::move (module), std::move (file));
if (res.second)
force = true;
else if (force)
res.first->second = std::move (file);
return force;
}
int
module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
{
struct stat stat;
if (fstat (fd, &stat) < 0)
return -errno;
// Just Map the file, we're gonna read all of it, so no need for
// line buffering
void *buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buffer == MAP_FAILED)
return -errno;
size_t prefix_len = prefix ? strlen (prefix) : 0;
unsigned lineno = 0;
for (char const *begin = reinterpret_cast <char const *> (buffer),
*end = begin + stat.st_size, *eol;
begin != end; begin = eol + 1)
{
lineno++;
eol = std::find (begin, end, '\n');
if (eol == end)
// last line has no \n, ignore the line, you lose
break;
auto *pos = begin;
bool pfx_search = prefix_len != 0;
pfx_search:
while (*pos == ' ' || *pos == '\t')
pos++;
auto *space = pos;
while (*space != '\n' && *space != ' ' && *space != '\t')
space++;
if (pos == space)
// at end of line, nothing here
continue;
if (pfx_search)
{
if (size_t (space - pos) == prefix_len
&& std::equal (pos, space, prefix))
pfx_search = false;
pos = space;
goto pfx_search;
}
std::string module (pos, space);
while (*space == ' ' || *space == '\t')
space++;
std::string file (space, eol);
if (module[0] == '$')
{
if (module == "$root")
set_repo (std::move (file));
else
return lineno;
}
else
{
if (file.empty ())
file = GetCMIName (module);
add_mapping (std::move (module), std::move (file), force);
}
}
munmap (buffer, stat.st_size);
return 0;
}
char const *
module_resolver::GetCMISuffix ()
{
return "gcm";
}
module_resolver *
module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
std::string &a, std::string &i)
{
if (!version || version > Cody::Version)
s->ErrorResponse ("version mismatch");
else if (a != "GCC")
// Refuse anything but GCC
ErrorResponse (s, std::string ("only GCC supported"));
else if (!ident.empty () && ident != i)
// Failed ident check
ErrorResponse (s, std::string ("bad ident"));
else
// Success!
s->ConnectResponse ("gcc");
return this;
}
int
module_resolver::ModuleRepoRequest (Cody::Server *s)
{
s->PathnameResponse (repo);
return 0;
}
int
module_resolver::cmi_response (Cody::Server *s, std::string &module)
{
auto iter = map.find (module);
if (iter == map.end ())
{
std::string file;
if (provide_default)
file = std::move (GetCMIName (module));
auto res = map.emplace (module, file);
iter = res.first;
}
if (iter->second.empty ())
s->ErrorResponse ("no such module");
else
s->PathnameResponse (iter->second);
return 0;
}
int
module_resolver::ModuleExportRequest (Cody::Server *s, std::string &module)
{
return cmi_response (s, module);
}
int
module_resolver::ModuleImportRequest (Cody::Server *s, std::string &module)
{
return cmi_response (s, module);
}
int
module_resolver::IncludeTranslateRequest (Cody::Server *s,
std::string &include)
{
auto iter = map.find (include);
if (iter == map.end ())
{
// Not found, look for it
if (fd_repo == -1 && !repo.empty ())
{
fd_repo = open (repo.c_str (), O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (fd_repo < 0)
fd_repo = -2;
}
if (fd_repo >= 0 || repo.empty ())
{
auto file = GetCMIName (include);
struct stat statbuf;
if (fstatat (repo.empty () ? AT_FDCWD : fd_repo,
file.c_str (), &statbuf, 0) < 0
|| !S_ISREG (statbuf.st_mode))
// Mark as not present
file.clear ();
auto res = map.emplace (include, file);
iter = res.first;
}
}
if (iter == map.end () || iter->second.empty ())
s->BoolResponse (false);
else
s->PathnameResponse (iter->second);
return 0;
}
int module_resolver::InvokeSubProcessRequest (Cody::Server *s, std::vector<std::string> &args) {
char **new_argv = (char **)malloc((args.size()) * sizeof(char *));
new_argv[args.size()-1] = NULL;
int i = 0;
for (std::vector<std::string>::iterator arg = args.begin() ; arg != args.end(); ++arg, ++i) {
// ignore "INVOKE"
if(i == 0) continue;
//new_argv[i++] = (char *)malloc(args[i].length() * sizeof(char));
// TODO: type safety
new_argv[i-1] = (char *)(*arg).c_str();
//fprintf(stderr, "*arg[?] = %s\n", (*arg).c_str());
//fprintf(stderr, "*new_argv[%d] = %s\n", i-1, new_argv[i-1]);
}
//fprintf(stderr, "\tcalling fork_execute\n");
fork_execute (new_argv[0], new_argv, true);
// TODO: send back a compile status response
s->OKResponse();
return 0;
}

990
gcc/mapper-server.cc Normal file
View File

@@ -0,0 +1,990 @@
/* C++ modules. Experimental!
Copyright (C) 2018-2020 Free Software Foundation, Inc.
Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "mapper.h"
// C++
#include <set>
#include <vector>
// GCC
#define INCLUDE_VECTOR
#define INCLUDE_MAP
#define INCLUDE_SET
// Network
/* Include network stuff first. Excitingly OSX10.14 uses bcmp here, which
we poison later! */
#if defined (HAVE_AF_UNIX) || defined (HAVE_AF_INET6)
/* socket, bind, listen, accept{4} */
# define NETWORKING 1
# include <sys/socket.h>
# ifdef HAVE_AF_UNIX
/* sockaddr_un */
# include <sys/un.h>
# endif
# include <netinet/in.h>
# ifdef HAVE_AF_INET6
/* sockaddr_in6, getaddrinfo, freeaddrinfo, gai_sterror, ntohs, htons. */
# include <netdb.h>
# endif
#ifdef HAVE_INET_NTOP
/* inet_ntop. */
#include <arpa/inet.h>
#endif
#endif
#ifndef HAVE_AF_INET6
# define gai_strerror(X) ""
#endif
// Excitingly Darwin uses bcmp in its network headers, and we poison
// that in our setup.
#include "system.h"
#include "version.h"
#include "intl.h"
#include <getopt.h>
// Select or epoll
#ifdef NETWORKING
#ifdef HAVE_EPOLL
/* epoll_create, epoll_ctl, epoll_pwait */
#include <sys/epoll.h>
#endif
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
/* pselect or select */
#include <sys/select.h>
#endif
#endif
#ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t) (int);
#endif
struct netmask {
in6_addr addr;
unsigned bits;
netmask (const in6_addr &a, unsigned b)
{
if (b > sizeof (in6_addr) * 8)
b = sizeof (in6_addr) * 8;
bits = b;
unsigned byte = (b + 7) / 8;
unsigned ix = 0;
for (ix = 0; ix < byte; ix++)
addr.s6_addr[ix] = a.s6_addr[ix];
for (; ix != sizeof (in6_addr); ix++)
addr.s6_addr[ix] = 0;
if (b & 3)
addr.s6_addr[b/7] &= (255 << 8) >> (b & 3);
}
bool includes (const in6_addr &a) const
{
unsigned byte = bits / 8;
for (unsigned ix = 0; ix != byte; ix++)
if (addr.s6_addr[ix] != a.s6_addr[ix])
return false;
if (bits & 3)
if ((addr.s6_addr[byte] ^ a.s6_addr[byte]) >> (8 - (bits & 3)))
return false;
return true;
}
};
/* Netmask comparison. */
struct netmask_cmp {
bool operator() (const netmask &a, const netmask &b) const
{
if (a.bits != b.bits)
return a.bits < b.bits;
for (unsigned ix = 0; ix != sizeof (in6_addr); ix++)
if (a.addr.s6_addr[ix] != b.addr.s6_addr[ix])
return a.addr.s6_addr[ix] < b.addr.s6_addr[ix];
return false;
}
};
typedef std::set<netmask, netmask_cmp> netmask_set_t;
typedef std::vector<netmask> netmask_vec_t;
const char *progname;
/* Speak thoughts out loud. */
static bool flag_noisy = false;
/* One and done. */
static bool flag_one = false;
/* Serialize connections. */
static bool flag_sequential = false;
/* Fallback to default if map file is unrewarding. */
static bool flag_fallback = false;
/* Root binary directory. */
static const char *flag_root = "gcm.cache";
static netmask_set_t netmask_set;
static netmask_vec_t accept_addrs;
/* Strip out the source directory from FILE. */
static const char *
trim_src_file (const char *file)
{
static const char me[] = __FILE__;
unsigned pos = 0;
while (file[pos] == me[pos] && me[pos])
pos++;
while (pos && !IS_DIR_SEPARATOR (me[pos-1]))
pos--;
return file + pos;
}
/* TODO: Delete tempfiles. Called from utils_cleanup. */
void tool_cleanup (bool) {
}
// TODO: undefined reference?
unsigned int input_location=0;
void fatal_error (unsigned int f, const char *str, ...) {
}
/* Die screaming. */
void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
internal_error (const char *fmt, ...)
{
fprintf (stderr, "%s:Internal error ", progname);
va_list args;
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
/* Hooked to from gcc_assert & gcc_unreachable. */
void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
fancy_abort (const char *file, int line, const char *func)
{
internal_error ("in %s, at %s:%d", func, trim_src_file (file), line);
}
/* Exploded on a signal. */
static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD
crash_signal (int sig)
{
signal (sig, SIG_DFL);
internal_error ("signal %s", strsignal (sig));
}
/* A fatal error of some kind. */
static void ATTRIBUTE_NORETURN ATTRIBUTE_COLD ATTRIBUTE_PRINTF_1
error (const char *msg, ...)
{
fprintf (stderr, "%s:error: ", progname);
va_list args;
va_start (args, msg);
vfprintf (stderr, msg, args);
va_end (args);
fprintf (stderr, "\n");
exit (1);
}
/* Progress messages to the user. */
static bool ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD
noisy (const char *fmt, ...)
{
fprintf (stderr, "%s:", progname);
va_list args;
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fprintf (stderr, "\n");
return false;
}
/* More messages to the user. */
static void ATTRIBUTE_PRINTF_2
fnotice (FILE *file, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vfprintf (file, _(fmt), args);
va_end (args);
}
static void ATTRIBUTE_NORETURN
print_usage (int error_p)
{
FILE *file = error_p ? stderr : stdout;
int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
fnotice (file, "Usage: cxx-mapper [OPTION...] [CONNECTION] [MAPPINGS...] \n\n");
fnotice (file, "C++ Module Mapper.\n\n");
fnotice (file, " -a, --accept Netmask to accept from\n");
fnotice (file, " -f, --fallback Use fallback for missing mappings\n");
fnotice (file, " -h, --help Print this help, then exit\n");
fnotice (file, " -n, --noisy Print progress messages\n");
fnotice (file, " -1, --one One connection and then exit\n");
fnotice (file, " -r, --root DIR Root compiled module directory\n");
fnotice (file, " -s, --sequential Process connections sequentially\n");
fnotice (file, " -v, --version Print version number, then exit\n");
fnotice (file, "Send SIGTERM(%d) to terminate\n", SIGTERM);
fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
bug_report_url);
exit (status);
}
/* Print version information and exit. */
static void ATTRIBUTE_NORETURN
print_version (void)
{
fnotice (stdout, "cxx-mapper %s%s\n", pkgversion_string, version_string);
fprintf (stdout, "Copyright %s 2018-2020 Free Software Foundation, Inc.\n",
_("(C)"));
fnotice (stdout,
_("This is free software; see the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or \n"
"FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
exit (SUCCESS_EXIT_CODE);
}
/* ARG is a netmask to accept from. Add it to the table. Return
false if we fail to resolve it. */
static bool
accept_from (char *arg)
{
bool ok = true;
#if HAVE_AF_INET6
unsigned bits = sizeof (in6_addr) * 8;
char *slash = strrchr (arg, '/');
if (slash)
{
*slash = 0;
if (slash[1])
{
char *endp;
bits = strtoul (slash + 1, &endp, 0);
}
}
addrinfo hints;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
hints.ai_addr = NULL;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
struct addrinfo *addrs = NULL;
if (int e = getaddrinfo (slash == arg ? NULL : arg, "0", &hints, &addrs))
{
noisy ("cannot resolve '%s': %s", arg, gai_strerror (e));
ok = false;
}
else
for (addrinfo *next = addrs; next; next = next->ai_next)
if (next->ai_family == AF_INET6)
{
netmask mask (((const sockaddr_in6 *)next->ai_addr)->sin6_addr, bits);
netmask_set.insert (mask);
}
freeaddrinfo (addrs);
#endif
return ok;
}
/* Process args, return index to first non-arg. */
static int
process_args (int argc, char **argv)
{
static const struct option options[] =
{
{ "accept", required_argument, NULL, 'a' },
{ "fallback",no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "noisy", no_argument, NULL, 'n' },
{ "one", no_argument, NULL, '1' },
{ "root", required_argument, NULL, 'r' },
{ "sequential", no_argument, NULL, 's' },
{ "version", no_argument, NULL, 'v' },
{ 0, 0, 0, 0 }
};
int opt;
bool bad_accept = false;
const char *opts = "a:fhn1r:sv";
while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
{
switch (opt)
{
case 'a':
if (!accept_from (optarg))
bad_accept = true;
break;
case 'f':
flag_fallback = true;
break;
case 'h':
print_usage (false);
/* print_usage will exit. */
case 'n':
flag_noisy = true;
break;
case '1':
flag_one = true;
break;
case 'r':
flag_root = optarg;
break;
case 's':
flag_sequential = true;
break;
case 'v':
print_version ();
/* print_version will exit. */
default:
print_usage (true);
/* print_usage will exit. */
}
}
if (bad_accept)
error ("failed to resolve all accept addresses");
return optind;
}
/* Manipulate the EPOLL state, or do nothing, if there is epoll. */
#ifdef HAVE_EPOLL
static inline void
do_epoll_ctl (int epoll_fd, int code, int event, int fd, unsigned data)
{
epoll_event ev;
ev.events = event;
ev.data.u32 = data;
if (epoll_ctl (epoll_fd, code, fd, &ev))
{
noisy ("epoll_ctl error:%s", xstrerror (errno));
gcc_unreachable ();
}
}
#define my_epoll_ctl(EFD,C,EV,FD,CL) \
((EFD) >= 0 ? do_epoll_ctl (EFD,C,EV,FD,CL) : (void)0)
#else
#define my_epoll_ctl(EFD,C,EV,FD,CL) ((void)(EFD), (void)(FD), (void)(CL))
#endif
#ifdef NETWORKING
/* We increment this to tell the server to shut down. */
static volatile int term = false;
static volatile int kill_sock_fd = -1;
#if !defined (HAVE_PSELECT) && defined (HAVE_SELECT)
static int term_pipe[2] = {-1, -1};
#else
#define term_pipe ((int *)NULL)
#endif
/* A terminate signal. Shutdown gracefully. */
static void
term_signal (int sig)
{
signal (sig, term_signal);
term = term + 1;
if (term_pipe && term_pipe[1] >= 0)
write (term_pipe[1], &term_pipe[1], 1);
}
/* A kill signal. Shutdown immediately. */
static void
kill_signal (int sig)
{
signal (sig, SIG_DFL);
int sock_fd = kill_sock_fd;
if (sock_fd >= 0)
close (sock_fd);
exit (2);
}
bool process_server (Cody::Server *server, unsigned slot, int epoll_fd)
{
switch (server->GetDirection ())
{
case Cody::Server::READING:
if (int err = server->Read ())
return !(err == EINTR || err == EAGAIN);
server->ProcessRequests ();
server->PrepareToWrite ();
break;
case Cody::Server::WRITING:
if (int err = server->Write ())
return !(err == EINTR || err == EAGAIN);
server->PrepareToRead ();
break;
default:
// We should never get here
return true;
}
// We've changed direction, so update epoll
gcc_assert (server->GetFDRead () == server->GetFDWrite ());
my_epoll_ctl (epoll_fd, EPOLL_CTL_MOD,
server->GetDirection () == Cody::Server::READING
? EPOLLIN : EPOLLOUT, server->GetFDRead (), slot + 1);
return false;
}
void close_server (Cody::Server *server, int epoll_fd)
{
my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, server->GetFDRead (), 0);
close (server->GetFDRead ());
delete server;
}
int open_server (bool ip6, int sock_fd)
{
sockaddr_in6 addr;
socklen_t addr_len = sizeof (addr);
#ifdef HAVE_ACCEPT4
int client_fd = accept4 (sock_fd, ip6 ? (sockaddr *)&addr : nullptr,
&addr_len, SOCK_NONBLOCK);
#else
int client_fd = accept (sock_fd, ip6 ? (sockaddr *)&addr : nullptr, &addr_len);
#endif
if (client_fd < 0)
{
error ("cannot accept: %s", xstrerror (errno));
flag_one = true;
}
else if (ip6)
{
const char *str = NULL;
#if HAVE_INET_NTOP
char name[INET6_ADDRSTRLEN];
str = inet_ntop (addr.sin6_family, &addr.sin6_addr, name, sizeof (name));
#endif
if (!accept_addrs.empty ())
{
netmask_vec_t::iterator e = accept_addrs.end ();
for (netmask_vec_t::iterator i = accept_addrs.begin ();
i != e; ++i)
if (i->includes (addr.sin6_addr))
goto present;
close (client_fd);
client_fd = -1;
noisy ("Rejecting connection from disallowed source '%s'",
str ? str : "");
present:;
}
if (client_fd >= 0)
flag_noisy && noisy ("Accepting connection from '%s'", str ? str : "");
}
return client_fd;
}
/* A server listening on bound socket SOCK_FD. */
static void
server (bool ipv6, int sock_fd, module_resolver *resolver)
{
int epoll_fd = -1;
signal (SIGTERM, term_signal);
#ifdef HAVE_EPOLL
epoll_fd = epoll_create (1);
#endif
if (epoll_fd >= 0)
my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
sigset_t mask;
{
sigset_t block;
sigemptyset (&block);
sigaddset (&block, SIGTERM);
sigprocmask (SIG_BLOCK, &block, &mask);
}
#endif
#ifdef HAVE_EPOLL
const unsigned max_events = 20;
epoll_event events[max_events];
#endif
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
fd_set readers, writers;
#endif
if (term_pipe)
pipe (term_pipe);
// We need stable references to servers, so this array can contain nulls
std::vector<Cody::Server *> connections;
unsigned live = 0;
while (sock_fd >= 0 || live)
{
/* Wait for one or more events. */
bool eintr = false;
int event_count;
if (epoll_fd >= 0)
{
#ifdef HAVE_EPOLL
event_count = epoll_pwait (epoll_fd, events, max_events, -1, &mask);
#endif
}
else
{
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
FD_ZERO (&readers);
FD_ZERO (&writers);
unsigned limit = 0;
if (sock_fd >= 0
&& !(term || (live && (flag_one || flag_sequential))))
{
FD_SET (sock_fd, &readers);
limit = sock_fd + 1;
}
if (term_pipe && term_pipe[0] >= 0)
{
FD_SET (term_pipe[0], &readers);
if (unsigned (term_pipe[0]) >= limit)
limit = term_pipe[0] + 1;
}
for (auto iter = connections.begin ();
iter != connections.end (); ++iter)
if (auto *server = *iter)
{
int fd = -1;
switch (server->GetDirection ())
{
case Cody::Server::READING:
fd = server->GetFDRead ();
FD_SET (fd, &readers);
break;
case Cody::Server::WRITING:
fd = server->GetFDWrite ();
FD_SET (fd, &writers);
break;
default:
break;
}
if (fd >= 0 && limit <= unsigned (fd))
limit = fd + 1;
}
#ifdef HAVE_PSELECT
event_count = pselect (limit, &readers, &writers, NULL, NULL, &mask);
#else
event_count = select (limit, &readers, &writers, NULL, NULL);
#endif
if (term_pipe && FD_ISSET (term_pipe[0], &readers))
{
/* Fake up an interrupted system call. */
event_count = -1;
errno = EINTR;
}
#endif
}
if (event_count < 0)
{
// Error in waiting
if (errno == EINTR)
{
flag_noisy && noisy ("Interrupted wait");
eintr = true;
}
else
error ("cannot %s: %s", epoll_fd >= 0 ? "epoll_wait"
#ifdef HAVE_PSELECT
: "pselect",
#else
: "select",
#endif
xstrerror (errno));
event_count = 0;
}
auto iter = connections.begin ();
while (event_count--)
{
// Process an event
int active = -2;
if (epoll_fd >= 0)
{
#ifdef HAVE_EPOLL
/* See PR c++/88664 for why a temporary is used. */
unsigned data = events[event_count].data.u32;
active = int (data) - 1;
#endif
}
else
{
for (; iter != connections.end (); ++iter)
if (auto *server = *iter)
{
bool found = false;
switch (server->GetDirection ())
{
#if defined (HAVE_PSELECT) || defined (HAVE_SELECT)
case Cody::Server::READING:
found = FD_ISSET (server->GetFDRead (), &readers);
break;
case Cody::Server::WRITING:
found = FD_ISSET (server->GetFDWrite (), &writers);
break;
#endif
default:
break;
}
if (found)
{
active = iter - connections.begin ();
++iter;
break;
}
}
if (active < 0 && sock_fd >= 0 && FD_ISSET (sock_fd, &readers))
active = -1;
}
if (active >= 0)
{
// Do the action
auto *server = connections[active];
if (process_server (server, active, epoll_fd))
{
connections[active] = nullptr;
close_server (server, epoll_fd);
live--;
if (flag_sequential)
my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, sock_fd, 0);
}
}
else if (active == -1 && !eintr)
{
// New connection
int fd = open_server (ipv6, sock_fd);
if (fd >= 0)
{
#if !defined (HAVE_ACCEPT4) \
&& (defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT))
int flags = fcntl (fd, F_GETFL, 0);
fcntl (fd, F_SETFL, flags | O_NONBLOCK);
#endif
auto *server = new Cody::Server (resolver, fd);
unsigned slot = connections.size ();
if (live == slot)
connections.push_back (server);
else
for (auto iter = connections.begin (); ; ++iter)
if (!*iter)
{
*iter = server;
slot = iter - connections.begin ();
break;
}
live++;
my_epoll_ctl (epoll_fd, EPOLL_CTL_ADD, EPOLLIN, fd, slot + 1);
}
}
if (sock_fd >= 0
&& (term || (live && (flag_one || flag_sequential))))
{
/* Stop paying attention to sock_fd. */
my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, sock_fd, 0);
if (flag_one || term)
{
close (sock_fd);
sock_fd = -1;
}
}
}
}
#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
/* Restore the signal mask. */
sigprocmask (SIG_SETMASK, &mask, NULL);
#endif
gcc_assert (sock_fd < 0);
if (epoll_fd >= 0)
close (epoll_fd);
if (term_pipe && term_pipe[0] >= 0)
{
close (term_pipe[0]);
close (term_pipe[1]);
}
}
#if 0
if (eintr)
flag_noisy && noisy ("Interrupted wait");
if (sock_fd >= 0 && (term || flag_one || flag_sequential))
{
/* Stop paying attention to sock_fd. */
my_epoll_ctl (epoll_fd, EPOLL_CTL_DEL, EPOLLIN, sock_fd, NULL);
if (flag_one || term)
{
close (sock_fd);
sock_fd = -1;
}
}
}
#if defined (HAVE_EPOLL) || defined (HAVE_PSELECT) || defined (HAVE_SELECT)
/* Restore the signal mask. */
sigprocmask (SIG_SETMASK, &mask, NULL);
#endif
gcc_assert (sock_fd < 0);
if (epoll_fd >= 0)
close (epoll_fd);
if (term_pipe && term_pipe[0] >= 0)
{
close (term_pipe[0]);
close (term_pipe[1]);
}
}
#endif
#endif
static int maybe_parse_socket (std::string &option, module_resolver *r)
{
/* Local or ipv6 address. */
auto last = option.find_last_of ('?');
if (last != option.npos)
{
r->set_ident (option.c_str () + last + 1);
option.erase (last);
}
int fd = -2;
char const *errmsg = nullptr;
/* Does it look like a socket? */
if (option[0] == '=')
/* A local socket. */
fd = Cody::ListenLocal (&errmsg, option.c_str () + 1);
else
{
auto colon = option.find_last_of (':');
if (colon != option.npos)
{
/* Try a hostname:port address. */
char const *cptr = option.c_str () + colon;
char *endp;
unsigned port = strtoul (cptr + 1, &endp, 10);
if (port && endp != cptr + 1 && !*endp)
{
/* Ends in ':number', treat as ipv6 domain socket. */
option.erase (colon);
fd = Cody::ListenInet6 (&errmsg, option.c_str (), port);
}
}
}
if (errmsg)
error ("failed to open socket: %s", errmsg);
return fd;
}
int
main (int argc, char *argv[])
{
const char *p = argv[0] + strlen (argv[0]);
while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
--p;
progname = p;
xmalloc_set_program_name (progname);
#ifdef SIGSEGV
signal (SIGSEGV, crash_signal);
#endif
#ifdef SIGILL
signal (SIGILL, crash_signal);
#endif
#ifdef SIGBUS
signal (SIGBUS, crash_signal);
#endif
#ifdef SIGABRT
signal (SIGABRT, crash_signal);
#endif
#ifdef SIGFPE
signal (SIGFPE, crash_signal);
#endif
#ifdef SIGPIPE
/* Ignore sigpipe, so read/write get an error. */
signal (SIGPIPE, SIG_IGN);
#endif
#ifdef SIGINT
signal (SIGINT, kill_signal);
#endif
int argno = process_args (argc, argv);
module_resolver r;
if (flag_root)
r.set_repo (flag_root);
std::string name;
int sock_fd = -1; /* Socket fd, otherwise stdin/stdout. */
if (argno != argc)
{
name = argv[argno];
sock_fd = maybe_parse_socket (name, &r);
if (!name.empty ())
argno++;
}
if (argno != argc)
for (; argno != argc; argno++)
{
std::string option = argv[argno];
char const *prefix = nullptr;
auto ident = option.find_last_of ('?');
if (ident != option.npos)
{
prefix = option.c_str () + ident + 1;
option[ident] = 0;
}
int fd = open (option.c_str (), O_RDONLY | O_CLOEXEC);
int err = 0;
if (fd < 0)
err = errno;
else
{
err = r.read_tuple_file (fd, prefix, false);
close (fd);
}
if (err)
error ("failed reading '%s': %s", option.c_str (), xstrerror (err));
}
else
flag_fallback = true;
r.set_default (flag_fallback);
#ifdef HAVE_AF_INET6
netmask_set_t::iterator end = netmask_set.end ();
for (netmask_set_t::iterator iter = netmask_set.begin ();
iter != end; ++iter)
{
netmask_vec_t::iterator e = accept_addrs.end ();
for (netmask_vec_t::iterator i = accept_addrs.begin (); i != e; ++i)
if (i->includes (iter->addr))
goto present;
accept_addrs.push_back (*iter);
present:;
}
#endif
#ifdef NETWORKING
if (sock_fd >= 0)
{
server (name[0] != '=', sock_fd, &r);
if (name[0] == '=')
unlink (name.c_str () + 1);
}
else
#endif
{
gcc_assert (sock_fd < 0);
auto server = Cody::Server (&r, 0, 1);
int err = 0;
for (;;)
{
server.PrepareToRead ();
while ((err = server.Read ()))
{
if (err == EINTR || err == EAGAIN)
continue;
goto done;
}
server.ProcessRequests ();
server.PrepareToWrite ();
while ((err = server.Write ()))
{
if (err == EINTR || err == EAGAIN)
continue;
goto done;
}
}
done:;
if (err > 0)
error ("communication error:%s", xstrerror (err));
}
return 0;
}

120
gcc/mapper.h Normal file
View File

@@ -0,0 +1,120 @@
/* C++ modules. Experimental! -*- c++ -*-
Copyright (C) 2017-2020 Free Software Foundation, Inc.
Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
// Mapper interface for client and server bits
#include "cody.hh"
// C++
#include <string>
#include <map>
// This is a GCC class, so GCC coding conventions on new bits.
class module_resolver : public Cody::Resolver
{
public:
using parent = Cody::Resolver;
using module_map = std::map<std::string, std::string>;
private:
std::string repo;
std::string ident;
module_map map;
int fd_repo = -1;
bool provide_default = true;
public:
module_resolver (bool def = true);
virtual ~module_resolver () override;
public:
void set_default (bool d)
{
provide_default = d;
}
void set_ident (char const *i)
{
ident = i;
}
bool set_repo (std::string &&repo, bool force = false);
bool add_mapping (std::string &&module, std::string &&file,
bool force = false);
// Return +ve line number of error, or -ve errno
int read_tuple_file (int fd, char const *prefix, bool force = false);
int read_tuple_file (int fd, std::string const &prefix,
bool force = false)
{
return read_tuple_file (fd, prefix.empty () ? nullptr : prefix.c_str (),
force);
}
public:
// Virtual overriders, names are controlle by Cody::Resolver
virtual module_resolver *ConnectRequest (Cody::Server *, unsigned version,
std::string &agent,
std::string &ident)
override;
virtual int ModuleRepoRequest (Cody::Server *) override;
virtual int ModuleExportRequest (Cody::Server *s, std::string &module)
override;
virtual int ModuleImportRequest (Cody::Server *s, std::string &module)
override;
virtual int IncludeTranslateRequest (Cody::Server *s, std::string &include)
override;
virtual int InvokeSubProcessRequest (Cody::Server *s, std::vector<std::string> &args)
override;
private:
virtual char const *GetCMISuffix () override;
private:
int cmi_response (Cody::Server *s, std::string &module);
};
#ifdef MAPPER_FOR_GCC
#ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t) (int);
#endif
class module_client : public Cody::Client
{
pex_obj *pex = nullptr;
sighandler_t sigpipe = SIG_IGN;
public:
module_client (Cody::Server *s)
: Client (s)
{
}
module_client (pex_obj *pex, int fd_from, int fd_to);
module_client (int fd_from, int fd_to)
: Client (fd_from, fd_to)
{
}
public:
static module_client *open_module_client (location_t loc, const char *option,
void (*set_repo) (const char *),
char const *);
static void close_module_client (location_t loc, module_client *);
};
#endif