1
1

Merge pull request #1495 from hjelmn/new_hooks

Add new patcher memory hooks
Этот коммит содержится в:
Nathan Hjelm 2016-04-13 18:19:23 -06:00
родитель e500ea2c8c c2b6fbb124
Коммит 1e6b4f2f55
74 изменённых файлов: 2356 добавлений и 11349 удалений

Просмотреть файл

@ -283,7 +283,8 @@ else
OPAL_ENABLE_DLOPEN_SUPPORT=1 OPAL_ENABLE_DLOPEN_SUPPORT=1
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
fi fi
AC_DEFINE_UNQUOTED(OPAL_ENABLE_DLOPEN_SUPPORT, $OPAL_ENABLE_DLOPEN_SUPPORT,
[Whether we want to enable dlopen support])
# #
# Heterogeneous support # Heterogeneous support

Просмотреть файл

@ -1,4 +1,3 @@
enable_dlopen=no
enable_mem_profile=no enable_mem_profile=no
enable_binaries=yes enable_binaries=yes
enable_heterogeneous=no enable_heterogeneous=no
@ -33,8 +32,5 @@ enable_mca_direct=pml-ob1
# enable development headers # enable development headers
with_devel_headers=yes with_devel_headers=yes
# enable ptmalloc (enables lazy deregistration)
with_memory_manager=linux
# disable valgrind # disable valgrind
with_valgrind=no with_valgrind=no

Просмотреть файл

@ -1,5 +1,3 @@
enable_dlopen=no
enable_mem_profile=no enable_mem_profile=no
enable_binaries=yes enable_binaries=yes
@ -40,8 +38,5 @@ enable_mca_direct=pml-ob1
# enable development headers # enable development headers
with_devel_headers=yes with_devel_headers=yes
# enable ptmalloc (enables lazy deregistration)
with_memory_manager=linux
# disable valgrind # disable valgrind
with_valgrind=no with_valgrind=no

Просмотреть файл

@ -1,7 +1,6 @@
# (c) 2013 Los Alamos National Security, LLC. All rights reserved. # (c) 2013 Los Alamos National Security, LLC. All rights reserved.
# Open MPI common configuration for TOSS/TOSS2 v1.7.x/1.8.x # Open MPI common configuration for TOSS/TOSS2 v1.7.x/1.8.x
enable_dlopen=no
enable_binaries=yes enable_binaries=yes
enable_heterogeneous=no enable_heterogeneous=no
enable_shared=yes enable_shared=yes

Просмотреть файл

@ -98,15 +98,13 @@
#endif #endif
#include "ompi/runtime/ompi_cr.h" #include "ompi/runtime/ompi_cr.h"
#if defined(MEMORY_LINUX_PTMALLOC2) && MEMORY_LINUX_PTMALLOC2 #include "opal/mca/memory/base/base.h"
#include "opal/mca/memory/linux/memory_linux.h"
/* So this sucks, but with OPAL in its own library that is brought in /* So this sucks, but with OPAL in its own library that is brought in
implicity from libmpi, there are times when the malloc initialize implicity from libmpi, there are times when the malloc initialize
hook in the memory component doesn't work. So we have to do it hook in the memory component doesn't work. So we have to do it
from here, since any MPI code is going to call MPI_Init... */ from here, since any MPI code is going to call MPI_Init... */
OPAL_DECLSPEC void (*__malloc_initialize_hook) (void) = OPAL_DECLSPEC void (*__malloc_initialize_hook) (void) =
opal_memory_linux_malloc_init_hook; opal_memory_base_malloc_init_hook;
#endif /* defined(MEMORY_LINUX_PTMALLOC2) && MEMORY_LINUX_PTMALLOC2 */
/* This is required for the boundaries of the hash tables used to store /* This is required for the boundaries of the hash tables used to store
* the F90 types returned by the MPI_Type_create_f90_XXX functions. * the F90 types returned by the MPI_Type_create_f90_XXX functions.

Просмотреть файл

@ -4,3 +4,4 @@ opal_show_help_yyleng
opal_show_help_yytext opal_show_help_yytext
opal_util_keyval_yyleng opal_util_keyval_yyleng
opal_util_keyval_yytext opal_util_keyval_yytext
__curbrk

Просмотреть файл

@ -2562,39 +2562,6 @@ btl_openib_component_init(int *num_btl_modules,
goto no_btls; goto no_btls;
} }
/* If we are using ptmalloc2 and there are no posix threads
available, this will cause memory corruption. Refuse to run.
Right now, ptmalloc2 is the only memory manager that we have on
OS's that support OpenFabrics that provide both FREE and MUNMAP
support, so the following test is [currently] good enough... */
value = opal_mem_hooks_support_level();
/* If we have a memory manager available, and
opal_leave_pinned==-1, then unless the user explicitly set
opal_leave_pinned_pipeline==0, then set opal_leave_pinned to 1.
We have a memory manager if we have both FREE and MUNMAP
support */
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) & value)) {
if (0 == opal_leave_pinned_pipeline &&
-1 == opal_leave_pinned) {
opal_leave_pinned = 1;
}
} else {
opal_leave_pinned = 0;
opal_leave_pinned_pipeline = 0;
}
#if OPAL_CUDA_SUPPORT
if (mca_btl_openib_component.cuda_want_gdr && (0 == opal_leave_pinned)) {
opal_show_help("help-mpi-btl-openib.txt",
"CUDA_gdr_and_nopinned", true,
opal_process_info.nodename);
goto no_btls;
}
#endif /* OPAL_CUDA_SUPPORT */
index = mca_base_var_find("ompi", "btl", "openib", "max_inline_data"); index = mca_base_var_find("ompi", "btl", "openib", "max_inline_data");
if (index >= 0) { if (index >= 0) {
if (OPAL_SUCCESS == mca_base_var_get_value(index, NULL, &source, NULL)) { if (OPAL_SUCCESS == mca_base_var_get_value(index, NULL, &source, NULL)) {
@ -2931,6 +2898,22 @@ btl_openib_component_init(int *num_btl_modules,
mca_btl_openib_component.if_exclude_list = NULL; mca_btl_openib_component.if_exclude_list = NULL;
} }
/* If we are using ptmalloc2 and there are no posix threads
available, this will cause memory corruption. Refuse to run.
Right now, ptmalloc2 is the only memory manager that we have on
OS's that support OpenFabrics that provide both FREE and MUNMAP
support, so the following test is [currently] good enough... */
value = opal_mem_hooks_support_level();
#if OPAL_CUDA_SUPPORT
if (mca_btl_openib_component.cuda_want_gdr && (0 == opal_leave_pinned)) {
opal_show_help("help-mpi-btl-openib.txt",
"CUDA_gdr_and_nopinned", true,
opal_process_info.nodename);
goto no_btls;
}
#endif /* OPAL_CUDA_SUPPORT */
mca_btl_openib_component.memory_registration_verbose = opal_output_open(NULL); mca_btl_openib_component.memory_registration_verbose = opal_output_open(NULL);
opal_output_set_verbosity (mca_btl_openib_component.memory_registration_verbose, opal_output_set_verbosity (mca_btl_openib_component.memory_registration_verbose,
mca_btl_openib_component.memory_registration_verbose_level); mca_btl_openib_component.memory_registration_verbose_level);

Просмотреть файл

@ -331,26 +331,6 @@ btl_ugni_component_close(void)
return OPAL_SUCCESS; return OPAL_SUCCESS;
} }
static void mca_btl_ugni_autoset_leave_pinned (void) {
if (MCA_BTL_UGNI_RCACHE_UDREG != mca_btl_ugni_component.rcache_type) {
int value = opal_mem_hooks_support_level();
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) & value)) {
/* Set leave pinned to 1 if leave pinned pipeline is not set */
if (-1 == opal_leave_pinned) {
opal_leave_pinned = !opal_leave_pinned_pipeline;
}
} else {
opal_leave_pinned = 0;
opal_leave_pinned_pipeline = 0;
}
} else if (-1 == opal_leave_pinned) {
/* if udreg is in use we can set leave pinned without checking for the
* memory hooks. */
opal_leave_pinned = !opal_leave_pinned_pipeline;
}
}
static mca_btl_base_module_t ** static mca_btl_base_module_t **
mca_btl_ugni_component_init (int *num_btl_modules, mca_btl_ugni_component_init (int *num_btl_modules,
bool enable_progress_threads, bool enable_progress_threads,
@ -409,8 +389,6 @@ mca_btl_ugni_component_init (int *num_btl_modules,
} }
} }
mca_btl_ugni_autoset_leave_pinned ();
mca_btl_ugni_module.super.btl_rdma_pipeline_send_length = mca_btl_ugni_module.super.btl_eager_limit; mca_btl_ugni_module.super.btl_rdma_pipeline_send_length = mca_btl_ugni_module.super.btl_eager_limit;
for (i = 0 ; i < mca_btl_ugni_component.ugni_num_btls ; ++i) { for (i = 0 ; i < mca_btl_ugni_component.ugni_num_btls ; ++i) {

Просмотреть файл

@ -32,5 +32,7 @@ BEGIN_C_DECLS
*/ */
OPAL_DECLSPEC extern mca_base_framework_t opal_memory_base_framework; OPAL_DECLSPEC extern mca_base_framework_t opal_memory_base_framework;
OPAL_DECLSPEC void opal_memory_base_malloc_init_hook (void);
END_C_DECLS END_C_DECLS
#endif /* OPAL_BASE_MEMORY_H */ #endif /* OPAL_BASE_MEMORY_H */

Просмотреть файл

@ -13,6 +13,8 @@
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2016 Research Organization for Information Science * Copyright (c) 2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved. * and Technology (RIST). All rights reserved.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$ * $COPYRIGHT$
* *
* Additional copyrights may follow * Additional copyrights may follow
@ -43,20 +45,22 @@ static int empty_process(void)
return OPAL_SUCCESS; return OPAL_SUCCESS;
} }
static int empty_query (int *priority)
{
*priority = 0;
return OPAL_SUCCESS;
}
/* /*
* Local variables * Local variables
*/ */
static opal_memory_base_component_2_0_0_t empty_component = { static opal_memory_base_component_2_0_0_t empty_component = {
/* Don't care about the version info */
{ 0, },
/* Don't care about the data */
{ 0, },
/* Empty / safe functions to call if no memory componet is selected */ /* Empty / safe functions to call if no memory componet is selected */
empty_process, .memoryc_query = empty_query,
opal_memory_base_component_register_empty, .memoryc_process = empty_process,
opal_memory_base_component_deregister_empty, .memoryc_register = opal_memory_base_component_register_empty,
opal_memory_base_component_set_alignment_empty, .memoryc_deregister = opal_memory_base_component_deregister_empty,
.memoryc_set_alignment = opal_memory_base_component_set_alignment_empty,
}; };
@ -66,6 +70,12 @@ static opal_memory_base_component_2_0_0_t empty_component = {
opal_memory_base_component_2_0_0_t *opal_memory = &empty_component; opal_memory_base_component_2_0_0_t *opal_memory = &empty_component;
void opal_memory_base_malloc_init_hook (void)
{
if (opal_memory->memoryc_init_hook) {
opal_memory->memoryc_init_hook ();
}
}
/* /*
* Function for finding and opening either all MCA components, or the one * Function for finding and opening either all MCA components, or the one
@ -73,23 +83,36 @@ opal_memory_base_component_2_0_0_t *opal_memory = &empty_component;
*/ */
static int opal_memory_base_open(mca_base_open_flag_t flags) static int opal_memory_base_open(mca_base_open_flag_t flags)
{ {
mca_base_component_list_item_t *item, *next;
opal_memory_base_component_2_0_0_t *tmp;
int priority, highest_priority = 0;
int ret; int ret;
/* Open up all available components */ /* can only be zero or one */
OPAL_LIST_FOREACH(item, &opal_memory_base_framework.framework_components, mca_base_component_list_item_t) {
tmp = (opal_memory_base_component_2_0_0_t *) item->cli_component;
ret = tmp->memoryc_query (&priority);
if (OPAL_SUCCESS != ret || priority < highest_priority) {
continue;
}
highest_priority = priority;
opal_memory = tmp;
}
OPAL_LIST_FOREACH_SAFE(item, next, &opal_memory_base_framework.framework_components, mca_base_component_list_item_t) {
if ((void *) opal_memory != (void *) item->cli_component) {
mca_base_component_unload (item->cli_component, opal_memory_base_framework.framework_output);
opal_list_remove_item (&opal_memory_base_framework.framework_components, &item->super);
}
}
/* open remaining component */
ret = mca_base_framework_components_open (&opal_memory_base_framework, flags); ret = mca_base_framework_components_open (&opal_memory_base_framework, flags);
if (ret != OPAL_SUCCESS) { if (ret != OPAL_SUCCESS) {
return ret; return ret;
} }
/* can only be zero or one */
if (opal_list_get_size(&opal_memory_base_framework.framework_components) == 1) {
mca_base_component_list_item_t *item;
item = (mca_base_component_list_item_t*)
opal_list_get_first(&opal_memory_base_framework.framework_components);
opal_memory = (opal_memory_base_component_2_0_0_t*)
item->cli_component;
}
/* All done */ /* All done */
return OPAL_SUCCESS; return OPAL_SUCCESS;
} }

Просмотреть файл

@ -1,19 +0,0 @@
Copyright (c) 2001-2004 Wolfram Gloger
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that (i) the above copyright notices and this permission
notice appear in all copies of the software and related documentation,
and (ii) the name of Wolfram Gloger may not be used in any advertising
or publicity relating to the software.
THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

Просмотреть файл

@ -1,181 +0,0 @@
2004-11-05 Wolfram Gloger <wg@malloc.de>
* malloc/hooks.c (malloc_starter, memalign_starter): Call
ptmalloc_init_minimal().
2004-11-04 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c (USE_STARTER): New macro.
* malloc/hooks.c: Use USE_STARTER.
* malloc/arena.c: Use USE_STARTER.
2004-08-13 Ulrich Drepper <drepper@redhat.com>
* malloc/malloc.c: Use strong_alias instead of weak_alias wherever
possible.
2002-12-06 Roland McGrath <roland@redhat.com>
* malloc/arena.c (ptmalloc_init_minimal): New function, broken out
of ptmalloc_init.
2002-08-23 Roland McGrath <roland@redhat.com>
* malloc/hooks.c (__malloc_initialize_hook, __free_hook,
__malloc_hook, __realloc_hook, __memalign_hook,
__after_morecore_hook): Variable definitions moved to ...
* malloc/malloc.c: ... here, so as to be before all references.
2004-10-19 Wolfram Gloger <wg@malloc.de>
* malloc/hooks.c (mem2chunk_check, top_check): Handle
non-contiguous arena. Reported by Michael Dalton
<mwdalton@stanford.edu> [BZ #457]. Add further checks for top
chunk.
2004-08-08 Wolfram Gloger <wg@malloc.de>
* include/malloc.h (mstate): Move type declaration from here...
* malloc/malloc.h: ...to here.
(struct malloc_arena_info, struct malloc_global_info): New types.
(_int_get_arena, _int_get_arena_info, _int_get_global_info): New
functions.
* malloc/malloc.c (mSTATS, public_mSTATs, mALLINFo): Remove.
(_int_get_arena_info, _int_get_global_info): New functions.
* malloc/arena.c (_int_get_arena): New function.
* malloc/malloc-stats.c: New file.
* malloc/tst-mstats.c: New file.
* malloc/Makefile (tests): Add tst-mstats.
(distribute): Remove no-longer existing thread-m.h.
(dist-routines): Add malloc-stats.
* malloc/Versions: Add _int_get_arena, _int_get_arena_info,
_int_get_global_info.
2004-07-25 Wolfram Gloger <wg@malloc.de>
* sysdeps/generic/thread-st.h: New file.
* sysdeps/pthread/thread-st.h: New file.
* sysdeps/sproc/thread-st.h: New file.
* sysdeps/solaris/thread-st.h: New file.
* thread-st.h: Removed.
2004-03-18 Ulrich Drepper <drepper@redhat.com>
* malloc/malloc.c (__posix_memalign): Correct alignment check.
Reported by Don Heller <dheller@cse.psu.edu>.
2003-12-17 Jakub Jelinek <jakub@redhat.com>
* malloc/malloc.c (__posix_memalign): If __memalign_hook != NULL,
call it directly instead of memalign_internal.
2003-09-27 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c: Include <malloc-machine.h> earlier instead of
"thread-m.h", so that default parameters can be overridden in a
system-specific malloc-machine.h. Remove extra ; from extern "C"
closing brace.
* sysdeps/generic/malloc-machine.h: New file.
* malloc/thread-m.h: Removed.
2003-09-08 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c (sYSMALLOc): Move foreign sbrk accounting into
contiguous case. Bug report from Prem Gopalan
<prem@mazunetworks.com>.
2003-08-18 Art Haas <ahaas@airmail.net>
* malloc/malloc.h: Remove unneeded ';' where closing the C++
extern block.
2003-06-18 Ulrich Drepper <drepper@redhat.com>
* malloc/malloc.c (public_mALLINFo): Initialize malloc if it
hasn't happened yet.
2003-05-28 Roland McGrath <roland@redhat.com>
* malloc/malloc.h [! __GNUC__] (__const): Define if undefined.
2003-05-04 H.J. Lu <hongjiu.lu@intel.com>
* malloc/arena.c (arena_get2): Add atomic_write_barrier.
* malloc/thread-m.h: Include <atomic.h>.
(atomic_full_barrier): Provide default.
(atomic_read_barrier): Likewise.
(atomic_write_barrier): Likewise.
2003-05-01 Ulrich Drepper <drepper@redhat.com>
* malloc/malloc.c (mSTATs): Call ptmalloc_init if necessary.
2003-01-27 Wolfram Gloger <wg@malloc.de>
* malloc/hooks.c (mem2chunk_check): Check alignment of mem
pointer, not of the computed chunk. Bug report from Carlos
O'Donell <carlos@baldric.uwo.ca>.
2002-12-27 Jakub Jelinek <jakub@redhat.com>
* malloc/arena.c (ptmalloc_init): Don't call next_env_entry if
_environ is NULL.
2002-12-17 Ulrich Drepper <drepper@redhat.com>
* malloc/malloc.c (mALLOPt): Make sure malloc is initialized.
2002-12-06 Roland McGrath <roland@redhat.com>
* malloc/hooks.c [_LIBC && (USE___THREAD || (USE_TLS && !SHARED))]
(malloc_starter, memalign_starter, free_starter): Don't define these.
* malloc/hooks.c (memalign_starter): New function.
* malloc/malloc.c: Declare it.
* malloc/arena.c (save_memalign_hook): New variable.
(ptmalloc_init): Set __memalign_hook to memalign_starter.
2002-11-18 Wolfram Gloger <wg@malloc.de>
* malloc/arena.c
(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2): Do
nothing if not initialized. Bug report from Marcus Brinkmann
<Marcus.Brinkmann@ruhr-uni-bochum.de>.
2002-10-07 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c (sYSMALLOc): Only check for breakage due
to foreign sbrk()'s if arena is contiguous. Bug report from
Bruno Haible <bruno@clisp.org>.
2002-07-11 Wolfram Gloger <wmglo@dent.med.uni-muenchen.de>
* malloc/hooks.c: typo fix in NO_THREADS case, realloc_check
fix in HAVE_MREMAP case.
2002-06-11 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c: Fix error path when new_heap() returns NULL.
Reported by Michael Meissner <meissner@redhat.com>.
2002-03-29 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c: Add short description and prototypes for
malloc_get_state, malloc_set_state and posix_memalign, for
consistency and to avoid warnings with -Wstrict-prototypes.
Reported by Andreas Jaeger <aj@suse.de>.
2002-03-13 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c (sYSMALLOc): Don't change brk if mmap
failed.
2002-01-18 Wolfram Gloger <wg@malloc.de>
* malloc/malloc.c: Rewrite, adapted from Doug Lea's malloc-2.7.0.c.
* malloc/malloc.h: Likewise.
* malloc/arena.c: New file.
* malloc/hooks.c: New file.
* malloc/tst-mallocstate.c: New file.
* malloc/Makefile: Add new testcase tst-mallocstate.
Add arena.c and hooks.c to distribute. Fix commented CPPFLAGS.

Просмотреть файл

@ -1,92 +0,0 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
AM_CPPFLAGS = -DMALLOC_DEBUG=0
AM_CPPFLAGS += \
-D_GNU_SOURCE=1 \
-DMALLOC_HOOKS=1 \
-I$(srcdir)/sysdeps/pthread
# this must come *after* the threads -Is
AM_CPPFLAGS += -I$(srcdir)/sysdeps/generic
# ptmalloc requires us to include the copyright notice in the
# software. So install it in the same place that we install ROMIO's
# copyright notices.
docdir = $(opaldatadir)/doc
doc_DATA = COPYRIGHT-ptmalloc2.txt
# Help file
dist_opaldata_DATA = help-opal-memory-linux.txt
# This component is only ever built statically (i.e., slurped into
# libopen-pal) -- it is never built as a DSO.
noinst_LTLIBRARIES = libmca_memory_linux.la
libmca_memory_linux_la_SOURCES = \
memory_linux.h \
memory_linux_component.c
libmca_memory_linux_la_LDFLAGS = \
-module -avoid-version $(memory_linux_LDFLAGS)
libmca_memory_linux_la_LIBADD = $(memory_linux_LIBS)
# Do we have ptmalloc2 support?
if MEMORY_LINUX_PTMALLOC2
libmca_memory_linux_la_SOURCES += \
memory_linux_ptmalloc2.c \
memory_linux_munmap.c \
rename.h \
malloc.c \
malloc-stats.c \
malloc.h
endif
# Do we have ummunotify support?
if MEMORY_LINUX_UMMUNOTIFY
libmca_memory_linux_la_SOURCES += memory_linux_ummunotify.c public.h
endif
# these are included directly and shouldn't be built solo
EXTRA_libmca_memory_linux_la_SOURCES = \
arena.c \
hooks.c
EXTRA_DIST = \
README-open-mpi.txt \
README-ptmalloc2.txt \
ChangeLog-ptmalloc2.txt \
COPYRIGHT-ptmalloc2.txt \
lran2.h \
t-test.h \
t-test1.c \
t-test2.c \
tst-mallocstate.c \
tst-mstats.c \
sysdeps/sproc/malloc-machine.h \
sysdeps/sproc/thread-st.h \
sysdeps/pthread/malloc-machine.h \
sysdeps/pthread/thread-st.h \
sysdeps/solaris/malloc-machine.h \
sysdeps/solaris/thread-st.h \
sysdeps/generic/malloc-machine.h \
sysdeps/generic/thread-st.h \
sysdeps/generic/atomic.h \
$(doc_DATA)

Просмотреть файл

@ -1,161 +0,0 @@
30 March 2009
This file documents Open MPI's usage of ptmalloc2. This is perhaps
our 7,208,499th iteration of ptmalloc2 support, so let's document it
here so that some future developer might spend *slightly* less time
understanding what the heck is going on.
See glibc documentation about malloc hooks before continuing. This is
pretty much required reading before reading the rest of this file /
having a hope of understanding what's going on here:
http://www.gnu.org/software/libc/manual/html_mono/libc.html#Hooks-for-Malloc
The overall goal is that we're using the Linux glibc hooks to wholly
replace the underlying allocator. We *used* to use horrid linker
tricks to interpose OMPI's ptmalloc2 symbols with the glibc ones --
meaning that user apps would call our symbols and not the glibc ones.
But that scheme is fraught with problems, not the least of which is
that *all* MPI applications will be forced to use our overridden
allocator (not just the ones that need it, such as the ones running on
OpenFabrics-based networks). Instead, what we do here is, frankly,
quite similar to what is done in MX: we use the 4 glibc hooks to
assert our own malloc, realloc, free, and memalign functions. This
allows the decision as to whether to use this internal ptmalloc2
allocate to be a run-time decision. This is quite important; using
this internal allocator has both benefits (allowing using
mpi_leave_pinned=1 behavior) and drawbacks (breaking some debuggers,
being unnecessary for non-OpenFabrics-based networks, etc.).
Here's how it works...
This component *must* be linked statically as part of libopen-pal; it
*cannot* be a DSO. Specifically, this library must be present during
pre-main() initialization phases so that its __malloc_initialize_hook
can be found and executed. Loading it as a DSO during MPI_INIT is far
too late. In configure.m4, we define the M4 macro
MCA_memory_ptmalloc2_COMPILE_MODE to always compile this component in
static mode. Yay flexible build system.
This component provides an munmap() function that will intercept calls
to munmap() and do the Right Thing. That is fairly straightforward to
do. Intercepting the malloc/free/etc. allocator is much more
complicated.
All the ptmalloc2 public symbols in this component have been name
shifted via the rename.h file. Hence, what used to be "malloc" is now
opal_memory_ptmalloc2_malloc. Since all the public symbols are
name-shifted, we can safely link this component in all MPI
applications. Specifically: just because this ptmalloc2 allocator is
present in all OMPI executables and user-level applications, it won't
necessarily be used -- it's a separate/run-time decision as to whether
it will be used.
We set the __malloc_initialize_hook variable to point to
opal_memory_ptmalloc2_malloc_init_hook (in hooks.c). This function is
called by the underlying glibc allocator before any allocations occur
and before the memory allocation subsystem is setup. As such, this
function is *extremely* restricted in what it can do. It cannot call
any form of malloc, for example (which seems fairly obvious, but it's
worth mentioning :-) ). This function is one of the determining
steps as to whether we'll use the internal ptmalloc2 allocator or
not. Several checks are performed:
- Was either the MCA params mpi_leave_pinned or
mpi_leave_pinned_pipeline set?
- Is a driver found to be active indicating that an OS-bypass network
is in effect (OpenFabrics, MX, Open-MX, ...etc.)
- Was an environment variable set indicating that we want to disable
this component?
If the $OMPI_MCA_memory_ptmalloc2_disable or the $FAKEROOTKEY env
variables are set, we don't enable the memory hooks.
We then use the following matrix to determine whether to enable the
memory hooks or not (explanation of the matrix is below):
lp / lpp yes no runtime not found
yes yes yes yes yes
no yes no no no
runtime yes no runtime runtime
not found yes no runtime runtime
lp = leave_pinned (the rows), lpp = leave_pinned_pipeline (the columns)
yes = found that variable to be set to "yes" (i.e., 1)
no = found that variable to be set to "no" (i.e., 0)
runtime = found that variable to be set to "determine at runtime" (i.e., -1)
not found = that variable was not set at all
Hence, if we end up on a "yes" block in the matrix, we enable the
hooks. If we end up in a "no" block in the matrix, we disable the
hooks. If we end up in a "runtime" block in the matrix, then we
enable the hooks *if* we can find indications that an OS bypass
network is present and available for use (e.g., OpenFabrics, MX,
Open-MX, ...etc.).
To be clear: sometime during process startup, this function will
definitely be called. It will either set the 4 hook functions to
point to our name-shifted ptmalloc2 functions, or it won't. If the 4
hook functions are set, then the underlying glibc allocator will
always call our 4 functions in all the relevant places instead of
calling its own functions. Specifically: the process is calling the
underlying glibc allocator, but that underlying glibc allocator will
make function pointer callbacks to our name-shifted ptmalloc2
functions to actually do the work.
Note that because we know our ptmalloc will not be providing all 5
hook variables (because we want to use the underlying glibc hook
variables), they are #if 0'ed out in our malloc.c. This has the
direct consequence that the *_hook_ini() in hooks.c are never used.
So to avoid compiler/linker warnings, I #if 0'ed those out as well.
All the public functions in malloc.c that call hook functions were
modified to #if 0 the hook function invocations. After all, that's
something that we want the *underlying* glibc allocator to do -- but
we are putting these functions as the hooks, so we don't want to
invoke ourselves in an infinite loop!
The next thing that happens in the startup sequence is that the
ptmalloc2 memory component's "open" function is called during
MPI_INIT. But we need to test to see if the glibc memory hooks have
been overridden before MPI_INIT was invoked. If so, we need to signal
that our allocator support may not be complete.
Patrick Geoffray/MX suggests a simple test: malloc() 4MB and then free
it. Watch to see if our name-shifted ptmalloc2 free() function was
invoked. If it was, then all of our hooks are probably in place and
we can proceed. If not, then set flags indicating that this memory
allocator only supports MUNMAP (not FREE/CHUNK).
We actually perform this test for malloc, realloc, and memalign. If
they all pass, then we say that the memory allocator supports
everything. If any of them fail, then we say that the memory
allocator does not support FREE/CHUNK.
NOTE: we *used* to simply set the FREE/CHUNK support flags during our
ptmalloc2's internal ptmalloc_init() function. This is not a good
idea becaus even after our ptmalloc_init() function has been invoked,
someone may come in an override our memory hooks. Doing tests during
the ptmalloc2 memory component's open function seems to be the safest
way to test whether we *actually* support FREE/CHUNK (this is what MX
does, too).
As stated above, we always intercept munmap() -- this is acceptable in
all environments. But we test that, too, just to be sure that the
munmap intercept is working. If we verify that it is working
properly, then we set that we have MUNMAP support.
Much later in the init sequence during MPI_INIT, components indicate
whether they want to use mpi_leave_pinned[_pipeline] support or not.
For example, the openib BTL queries the opal_mem_hooks_support_level()
function to see if FREE and MUNMAP are supported. If they are, then
the openib BTL sets mpi_leave_pinned = 1.
Finally, the mpool base does a final check. If
mpi_leave_pinned[_pipeline] is set to 1 and/or use_mem_hooks is set,
if FREE/MUNMAP are not set in the supported flags, then a warning is
printed. Otherwise, life continues (assumedly using
mpi_leave_pinned[_pipeline] support).
Simple, right?

Просмотреть файл

@ -1,192 +0,0 @@
ptmalloc2 - a multi-thread malloc implementation
================================================
Wolfram Gloger (wg@malloc.de)
Nov 2004
Introduction
============
This package is a modified version of Doug Lea's malloc-2.7.1pre
implementation (available seperately from ftp://g.oswego.edu/pub/misc)
that I adapted for multiple threads, while trying to avoid lock
contention as much as possible. Many thanks should go to Doug Lea
(dl@cs.oswego.edu) for the great original malloc implementation.
As part of the GNU C library, the source files are available under the
GNU Library General Public License (see the comments in the files).
But as part of this stand-alone package, the code is also available
under the (probably less restrictive) conditions described in the file
'COPYRIGHT'. In any case, there is no warranty whatsoever for this
package.
The current distribution should be available from:
http://www.malloc.de/malloc/ptmalloc2.tar.gz
Compilation
===========
It should be possible to build ptmalloc2 on any UN*X-like system that
implements the sbrk(), mmap(), munmap() and mprotect() calls. If
mmap() is not available, it is only possible to produce a
non-threadsafe implementation. Since there are now several source
files, a library (libmalloc.a) is generated. See the Makefile for
examples of the compile-time options.
Note that support for non-ANSI compilers is no longer a significant
goal.
Several example targets are provided in the Makefile:
o Posix threads (pthreads), compile with "make posix"
o Posix threads with explicit initialization, compile with
"make posix-explicit" (known to be required on HPUX)
o Posix threads without "tsd data hack" (see below), compile with
"make posix-with-tsd"
o Solaris threads, compile with "make solaris"
o SGI sproc() threads, compile with "make sproc"
o no threads, compile with "make nothreads"
For Linux:
o make "linux-pthread" (almost the same as "make posix")
Note that some compilers need special flags for multi-threaded code,
e.g. with Solaris cc with Posix threads, one should use:
% make posix SYS_FLAGS='-mt'
Some additional targets, ending in `-libc', are also provided in the
Makefile, to compare performance of the test programs to the case when
linking with the standard malloc implementation in libc.
A potential problem remains: If any of the system-specific functions
for getting/setting thread-specific data or for locking a mutex call
one of the malloc-related functions internally, the implementation
cannot work at all due to infinite recursion. One example seems to be
Solaris 2.4. I would like to hear if this problem occurs on other
systems, and whether similar workarounds could be applied.
For Posix threads, too, an optional hack like that has been integrated
(activated when defining USE_TSD_DATA_HACK) which depends on
`pthread_t' being convertible to an integral type (which is of course
not generally guaranteed). USE_TSD_DATA_HACK is now the default
because I haven't yet found a non-glibc pthreads system where this
hack is _not_ needed.
*NEW* and _important_: In (currently) one place in the ptmalloc2
source, a write memory barrier is needed, named
atomic_write_barrier(). This macro needs to be defined at the end of
malloc-machine.h. For gcc, a fallback in the form of a full memory
barrier is already defined, but you may need to add another definition
if you don't use gcc.
Usage
=====
Just link libmalloc.a into your application.
Some wicked systems (e.g. HPUX apparently) won't let malloc call _any_
thread-related functions before main(). On these systems,
USE_STARTER=2 must be defined during compilation (see "make
posix-explicit" above) and the global initialization function
ptmalloc_init() must be called explitly, preferably at the start of
main().
Otherwise, when using ptmalloc2, no special precautions are necessary.
Link order is important
=======================
On some systems, when overriding malloc and linking against shared
libraries, the link order becomes very important. E.g., when linking
C++ programs on Solaris, don't rely on libC being included by default,
but instead put `-lthread' behind `-lC' on the command line:
CC ... libmalloc.a -lC -lthread
This is because there are global constructors in libC that need
malloc/ptmalloc, which in turn needs to have the thread library to be
already initialized.
Debugging hooks
===============
All calls to malloc(), realloc(), free() and memalign() are routed
through the global function pointers __malloc_hook, __realloc_hook,
__free_hook and __memalign_hook if they are not NULL (see the malloc.h
header file for declarations of these pointers). Therefore the malloc
implementation can be changed at runtime, if care is taken not to call
free() or realloc() on pointers obtained with a different
implementation than the one currently in effect. (The easiest way to
guarantee this is to set up the hooks before any malloc call, e.g.
with a function pointed to by the global variable
__malloc_initialize_hook).
A useful application of the hooks is built-in into ptmalloc2: The
implementation is usually very unforgiving with respect to misuse,
such as free()ing a pointer twice or free()ing a pointer not obtained
with malloc() (these will typically crash the application
immediately). To debug in such situations, you can set the
environment variable `MALLOC_CHECK_' (note the trailing underscore).
Performance will suffer somewhat, but you will get more controlled
behaviour in the case of misuse. If MALLOC_CHECK_=0, wrong free()s
will be silently ignored, if MALLOC_CHECK_=1, diagnostics will be
printed on stderr, and if MALLOC_CHECK_=2, abort() will be called on
any error.
You can now also tune other malloc parameters (normally adjused via
mallopt() calls from the application) with environment variables:
MALLOC_TRIM_THRESHOLD_ for deciding to shrink the heap (in bytes)
MALLOC_TOP_PAD_ how much extra memory to allocate on
each system call (in bytes)
MALLOC_MMAP_THRESHOLD_ min. size for chunks allocated via
mmap() (in bytes)
MALLOC_MMAP_MAX_ max. number of mmapped regions to use
Tests
=====
Two testing applications, t-test1 and t-test2, are included in this
source distribution. Both perform pseudo-random sequences of
allocations/frees, and can be given numeric arguments (all arguments
are optional):
% t-test[12] <n-total> <n-parallel> <n-allocs> <size-max> <bins>
n-total = total number of threads executed (default 10)
n-parallel = number of threads running in parallel (2)
n-allocs = number of malloc()'s / free()'s per thread (10000)
size-max = max. size requested with malloc() in bytes (10000)
bins = number of bins to maintain
The first test `t-test1' maintains a completely seperate pool of
allocated bins for each thread, and should therefore show full
parallelism. On the other hand, `t-test2' creates only a single pool
of bins, and each thread randomly allocates/frees any bin. Some lock
contention is to be expected in this case, as the threads frequently
cross each others arena.
Performance results from t-test1 should be quite repeatable, while the
behaviour of t-test2 depends on scheduling variations.
Conclusion
==========
I'm always interested in performance data and feedback, just send mail
to ptmalloc@malloc.de.
Good luck!

Просмотреть файл

@ -1,805 +0,0 @@
/* Malloc implementation for multiple threads without lock contention.
Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* $Id: arena.c,v 1.9 2004/11/05 14:42:23 wg Exp $ */
/* Compile-time constants. */
#define HEAP_MIN_SIZE (32*1024)
#ifndef HEAP_MAX_SIZE
#define HEAP_MAX_SIZE (1024*1024) /* must be a power of two */
#endif
/* HEAP_MIN_SIZE and HEAP_MAX_SIZE limit the size of mmap()ed heaps
that are dynamically created for multi-threaded programs. The
maximum size must be a power of two, for fast determination of
which heap belongs to a chunk. It should be much larger than the
mmap threshold, so that requests with a size just below that
threshold can be fulfilled without creating too many heaps. */
#ifndef THREAD_STATS
#define THREAD_STATS 0
#endif
/* If THREAD_STATS is non-zero, some statistics on mutex locking are
computed. */
/***************************************************************************/
#define top(ar_ptr) ((ar_ptr)->top)
/* A heap is a single contiguous memory region holding (coalesceable)
malloc_chunks. It is allocated with mmap() and always starts at an
address aligned to HEAP_MAX_SIZE. Not used unless compiling with
USE_ARENAS. */
typedef struct _heap_info {
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t pad; /* Make sure the following data is properly aligned. */
} heap_info;
/* Thread specific data */
static tsd_key_t arena_key;
static mutex_t list_lock;
#if THREAD_STATS
static int stat_n_heaps;
#define THREAD_STAT(x) x
#else
#define THREAD_STAT(x) do ; while(0)
#endif
/* Mapped memory in non-main arenas (reliable only for NO_THREADS). */
static unsigned long arena_mem;
/* Already initialized? */
int __malloc_initialized = -1;
/**************************************************************************/
#if USE_ARENAS
/* arena_get() acquires an arena and locks the corresponding mutex.
First, try the one last locked successfully by this thread. (This
is the common case and handled with a macro for speed.) Then, loop
once over the circularly linked list of arenas. If no arena is
readily available, create a new one. In this latter case, `size'
is just a hint as to how much memory will be required immediately
in the new arena. */
#define arena_get(ptr, size) do { \
Void_t *vptr = NULL; \
ptr = (mstate)tsd_getspecific(arena_key, vptr); \
if(ptr && !mutex_trylock(&ptr->mutex)) { \
THREAD_STAT(++(ptr->stat_lock_direct)); \
} else \
ptr = arena_get2(ptr, (size)); \
} while(0)
/* find the heap and corresponding arena for a given ptr */
#define heap_for_ptr(ptr) \
((heap_info *)((unsigned long)(ptr) & ~(HEAP_MAX_SIZE-1)))
#define arena_for_chunk(ptr) \
(chunk_non_main_arena(ptr) ? heap_for_ptr(ptr)->ar_ptr : &main_arena)
#else /* !USE_ARENAS */
/* There is only one arena, main_arena. */
#if THREAD_STATS
#define arena_get(ar_ptr, sz) do { \
ar_ptr = &main_arena; \
if(!mutex_trylock(&ar_ptr->mutex)) \
++(ar_ptr->stat_lock_direct); \
else { \
(void)mutex_lock(&ar_ptr->mutex); \
++(ar_ptr->stat_lock_wait); \
} \
} while(0)
#else
#define arena_get(ar_ptr, sz) do { \
ar_ptr = &main_arena; \
(void)mutex_lock(&ar_ptr->mutex); \
} while(0)
#endif
#define arena_for_chunk(ptr) (&main_arena)
#endif /* USE_ARENAS */
/**************************************************************************/
#ifndef NO_THREADS
/* atfork support. */
static __malloc_ptr_t (*save_malloc_hook) __MALLOC_P ((size_t __size,
__const __malloc_ptr_t));
# if !defined _LIBC || !defined USE_TLS || (defined SHARED && !USE___THREAD)
static __malloc_ptr_t (*save_memalign_hook) __MALLOC_P ((size_t align,
size_t __size,
__const __malloc_ptr_t));
# endif
static void (*save_free_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
__const __malloc_ptr_t));
static Void_t* save_arena;
/* Magic value for the thread-specific arena pointer when
malloc_atfork() is in use. */
#define ATFORK_ARENA_PTR ((Void_t*)-1)
/* The following hooks are used while the `atfork' handling mechanism
is active. */
static Void_t*
malloc_atfork(size_t sz, const Void_t *caller)
{
Void_t *vptr = NULL;
Void_t *victim;
tsd_getspecific(arena_key, vptr);
if(vptr == ATFORK_ARENA_PTR) {
/* We are the only thread that may allocate at all. */
if(save_malloc_hook != malloc_check) {
return _int_malloc(&main_arena, sz);
} else {
if(top_check()<0)
return 0;
victim = _int_malloc(&main_arena, sz+1);
return mem2mem_check(victim, sz);
}
} else {
/* Suspend the thread until the `atfork' handlers have completed.
By that time, the hooks will have been reset as well, so that
mALLOc() can be used again. */
(void)mutex_lock(&list_lock);
(void)mutex_unlock(&list_lock);
return public_mALLOc(sz);
}
}
static void
free_atfork(Void_t* mem, const Void_t *caller)
{
Void_t *vptr = NULL;
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
if (mem == 0) /* free(0) has no effect */
return;
p = mem2chunk(mem); /* do not bother to replicate free_check here */
#if HAVE_MMAP
if (chunk_is_mmapped(p)) /* release mmapped memory. */
{
munmap_chunk(p);
return;
}
#endif
ar_ptr = arena_for_chunk(p);
tsd_getspecific(arena_key, vptr);
if(vptr != ATFORK_ARENA_PTR)
(void)mutex_lock(&ar_ptr->mutex);
_int_free(ar_ptr, mem);
if(vptr != ATFORK_ARENA_PTR)
(void)mutex_unlock(&ar_ptr->mutex);
}
/* The following two functions are registered via thread_atfork() to
make sure that the mutexes remain in a consistent state in the
fork()ed version of a thread. Also adapt the malloc and free hooks
temporarily, because the `atfork' handler mechanism may use
malloc/free internally (e.g. in LinuxThreads). */
static void
ptmalloc_lock_all __MALLOC_P((void))
{
mstate ar_ptr;
if(__malloc_initialized < 1)
return;
(void)mutex_lock(&list_lock);
for(ar_ptr = &main_arena;;) {
(void)mutex_lock(&ar_ptr->mutex);
ar_ptr = ar_ptr->next;
if(ar_ptr == &main_arena) break;
}
save_malloc_hook = __malloc_hook;
save_free_hook = __free_hook;
__malloc_hook = malloc_atfork;
__free_hook = free_atfork;
/* Only the current thread may perform malloc/free calls now. */
tsd_getspecific(arena_key, save_arena);
tsd_setspecific(arena_key, ATFORK_ARENA_PTR);
}
static void
ptmalloc_unlock_all __MALLOC_P((void))
{
mstate ar_ptr;
if(__malloc_initialized < 1)
return;
tsd_setspecific(arena_key, save_arena);
__malloc_hook = save_malloc_hook;
__free_hook = save_free_hook;
for(ar_ptr = &main_arena;;) {
(void)mutex_unlock(&ar_ptr->mutex);
ar_ptr = ar_ptr->next;
if(ar_ptr == &main_arena) break;
}
(void)mutex_unlock(&list_lock);
}
#ifdef __linux__
/* In LinuxThreads, unlocking a mutex in the child process after a
fork() is currently unsafe, whereas re-initializing it is safe and
does not leak resources. Therefore, a special atfork handler is
installed for the child. */
static void
ptmalloc_unlock_all2 __MALLOC_P((void))
{
mstate ar_ptr;
if(__malloc_initialized < 1)
return;
#if defined _LIBC || defined MALLOC_HOOKS
tsd_setspecific(arena_key, save_arena);
__malloc_hook = save_malloc_hook;
__free_hook = save_free_hook;
#endif
for(ar_ptr = &main_arena;;) {
(void)mutex_init(&ar_ptr->mutex);
ar_ptr = ar_ptr->next;
if(ar_ptr == &main_arena) break;
}
(void)mutex_init(&list_lock);
}
#else
#define ptmalloc_unlock_all2 ptmalloc_unlock_all
#endif
#endif /* !defined NO_THREADS */
/* Initialization routine. */
#ifdef _LIBC
#include <string.h>
extern char **_environ;
static char *
internal_function
next_env_entry (char ***position)
{
char **current = *position;
char *result = NULL;
while (*current != NULL)
{
if (__builtin_expect ((*current)[0] == 'M', 0)
&& (*current)[1] == 'A'
&& (*current)[2] == 'L'
&& (*current)[3] == 'L'
&& (*current)[4] == 'O'
&& (*current)[5] == 'C'
&& (*current)[6] == '_')
{
result = &(*current)[7];
/* Save current position for next visit. */
*position = ++current;
break;
}
++current;
}
return result;
}
#endif /* _LIBC */
/* Set up basic state so that _int_malloc et al can work. */
static void
ptmalloc_init_minimal __MALLOC_P((void))
{
#if DEFAULT_TOP_PAD != 0
mp_.top_pad = DEFAULT_TOP_PAD;
#endif
mp_.n_mmaps_max = DEFAULT_MMAP_MAX;
mp_.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
mp_.trim_threshold = DEFAULT_TRIM_THRESHOLD;
mp_.pagesize = malloc_getpagesize;
}
#if !(USE_STARTER & 2)
static
#endif
void
ptmalloc_init __MALLOC_P((void))
{
#if __STD_C
const char* s;
#else
char* s;
#endif
int secure = 0;
if(__malloc_initialized >= 0) return;
__malloc_initialized = 0;
if (mp_.pagesize == 0)
ptmalloc_init_minimal();
#ifndef NO_THREADS
# if USE_STARTER & 1
/* With some threads implementations, creating thread-specific data
or initializing a mutex may call malloc() itself. Provide a
simple starter version (realloc() won't work). */
save_malloc_hook = __malloc_hook;
save_memalign_hook = __memalign_hook;
save_free_hook = __free_hook;
__malloc_hook = malloc_starter;
__memalign_hook = memalign_starter;
__free_hook = free_starter;
# ifdef _LIBC
/* Initialize the pthreads interface. */
if (__pthread_initialize != NULL)
__pthread_initialize();
# endif /* !defined _LIBC */
# endif /* USE_STARTER & 1 */
#endif /* !defined NO_THREADS */
mutex_init(&main_arena.mutex);
main_arena.next = &main_arena;
mutex_init(&list_lock);
tsd_key_create(&arena_key, NULL);
tsd_setspecific(arena_key, (Void_t *)&main_arena);
thread_atfork(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
#ifndef NO_THREADS
# if USE_STARTER & 1
__malloc_hook = save_malloc_hook;
__memalign_hook = save_memalign_hook;
__free_hook = save_free_hook;
# endif
# if USE_STARTER & 2
__malloc_hook = 0;
__memalign_hook = 0;
__free_hook = 0;
# endif
#endif
#ifdef _LIBC
secure = __libc_enable_secure;
s = NULL;
if (__builtin_expect (_environ != NULL, 1))
{
char **runp = _environ;
char *envline;
while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
0))
{
size_t len = strcspn (envline, "=");
if (envline[len] != '=')
/* This is a "MALLOC_" variable at the end of the string
without a '=' character. Ignore it since otherwise we
will access invalid memory below. */
continue;
switch (len)
{
case 6:
if (memcmp (envline, "CHECK_", 6) == 0)
s = &envline[7];
break;
case 8:
if (! secure && memcmp (envline, "TOP_PAD_", 8) == 0)
mALLOPt(M_TOP_PAD, atoi(&envline[9]));
break;
case 9:
if (! secure && memcmp (envline, "MMAP_MAX_", 9) == 0)
mALLOPt(M_MMAP_MAX, atoi(&envline[10]));
break;
case 15:
if (! secure)
{
if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
mALLOPt(M_TRIM_THRESHOLD, atoi(&envline[16]));
else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
mALLOPt(M_MMAP_THRESHOLD, atoi(&envline[16]));
}
break;
default:
break;
}
}
}
#else
if (! secure)
{
if((s = getenv("MALLOC_TRIM_THRESHOLD_")))
mALLOPt(M_TRIM_THRESHOLD, atoi(s));
if((s = getenv("MALLOC_TOP_PAD_")))
mALLOPt(M_TOP_PAD, atoi(s));
if((s = getenv("MALLOC_MMAP_THRESHOLD_")))
mALLOPt(M_MMAP_THRESHOLD, atoi(s));
if((s = getenv("MALLOC_MMAP_MAX_")))
mALLOPt(M_MMAP_MAX, atoi(s));
}
s = getenv("MALLOC_CHECK_");
#endif
if(s) {
if(s[0]) mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0'));
__malloc_check_init();
}
#if 0
/* OMPI Change: Don't call the initialize hook; it was us. */
if(__malloc_initialize_hook != NULL)
(*__malloc_initialize_hook)();
#endif
__malloc_initialized = 1;
}
/* There are platforms (e.g. Hurd) with a link-time hook mechanism. */
#ifdef thread_atfork_static
thread_atfork_static(ptmalloc_lock_all, ptmalloc_unlock_all, \
ptmalloc_unlock_all2)
#endif
/* Managing heaps and arenas (for concurrent threads) */
#if USE_ARENAS
#if MALLOC_DEBUG > 1
/* Print the complete contents of a single heap to stderr. */
static void
#if __STD_C
dump_heap(heap_info *heap)
#else
dump_heap(heap) heap_info *heap;
#endif
{
char *ptr;
mchunkptr p;
fprintf(stderr, "Heap %p, size %10lx:\n", heap, (long)heap->size);
ptr = (heap->ar_ptr != (mstate)(heap+1)) ?
(char*)(heap + 1) : (char*)(heap + 1) + sizeof(struct malloc_state);
p = (mchunkptr)(((unsigned long)ptr + MALLOC_ALIGN_MASK) &
~MALLOC_ALIGN_MASK);
for(;;) {
fprintf(stderr, "chunk %p size %10lx", p, (long)p->size);
if(p == top(heap->ar_ptr)) {
fprintf(stderr, " (top)\n");
break;
} else if(p->size == (0|PREV_INUSE)) {
fprintf(stderr, " (fence)\n");
break;
}
fprintf(stderr, "\n");
p = next_chunk(p);
}
}
#endif /* MALLOC_DEBUG > 1 */
/* Create a new heap. size is automatically rounded up to a multiple
of the page size. */
static heap_info *
internal_function
#if __STD_C
new_heap(size_t size, size_t top_pad)
#else
new_heap(size, top_pad) size_t size, top_pad;
#endif
{
size_t page_mask = malloc_getpagesize - 1;
char *p1, *p2;
unsigned long ul;
heap_info *h;
if(size+top_pad < HEAP_MIN_SIZE)
size = HEAP_MIN_SIZE;
else if(size+top_pad <= HEAP_MAX_SIZE)
size += top_pad;
else if(size > HEAP_MAX_SIZE)
return 0;
else
size = HEAP_MAX_SIZE;
size = (size + page_mask) & ~page_mask;
/* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed.
No swap space needs to be reserved for the following large
mapping (on Linux, this is the case for all non-writable mappings
anyway). */
p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE);
if(p1 != MAP_FAILED) {
p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1)) & ~(HEAP_MAX_SIZE-1));
ul = p2 - p1;
munmap(p1, ul);
munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
} else {
/* Try to take the chance that an allocation of only HEAP_MAX_SIZE
is already aligned. */
p2 = (char *)MMAP(0, HEAP_MAX_SIZE, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE);
if(p2 == MAP_FAILED)
return 0;
if((unsigned long)p2 & (HEAP_MAX_SIZE-1)) {
munmap(p2, HEAP_MAX_SIZE);
return 0;
}
}
if(mprotect(p2, size, PROT_READ|PROT_WRITE) != 0) {
munmap(p2, HEAP_MAX_SIZE);
return 0;
}
h = (heap_info *)p2;
h->size = size;
THREAD_STAT(stat_n_heaps++);
return h;
}
/* Grow or shrink a heap. size is automatically rounded up to a
multiple of the page size if it is positive. */
static int
#if __STD_C
grow_heap(heap_info *h, long diff)
#else
grow_heap(h, diff) heap_info *h; long diff;
#endif
{
size_t page_mask = malloc_getpagesize - 1;
long new_size;
if(diff >= 0) {
diff = (diff + page_mask) & ~page_mask;
new_size = (long)h->size + diff;
if(new_size > HEAP_MAX_SIZE)
return -1;
if(mprotect((char *)h + h->size, diff, PROT_READ|PROT_WRITE) != 0)
return -2;
} else {
new_size = (long)h->size + diff;
if(new_size < (long)sizeof(*h))
return -1;
if(mprotect((char *)h + new_size, -diff, PROT_NONE) != 0)
return -2;
/*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
}
h->size = new_size;
return 0;
}
/* Delete a heap. */
#define delete_heap(heap) munmap((char*)(heap), HEAP_MAX_SIZE)
static int
internal_function
#if __STD_C
heap_trim(heap_info *heap, size_t pad)
#else
heap_trim(heap, pad) heap_info *heap; size_t pad;
#endif
{
mstate ar_ptr = heap->ar_ptr;
unsigned long pagesz = mp_.pagesize;
mchunkptr top_chunk = top(ar_ptr), p, bck, fwd;
heap_info *prev_heap;
long new_size, top_size, extra;
/* Can this heap go away completely? */
while(top_chunk == chunk_at_offset(heap, sizeof(*heap))) {
prev_heap = heap->prev;
p = chunk_at_offset(prev_heap, prev_heap->size - (MINSIZE-2*SIZE_SZ));
assert(p->size == (0|PREV_INUSE)); /* must be fencepost */
p = prev_chunk(p);
new_size = chunksize(p) + (MINSIZE-2*SIZE_SZ);
assert(new_size>0 && new_size<(long)(2*MINSIZE));
if(!prev_inuse(p))
new_size += p->prev_size;
assert(new_size>0 && new_size<HEAP_MAX_SIZE);
if(new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz)
break;
ar_ptr->system_mem -= heap->size;
arena_mem -= heap->size;
delete_heap(heap);
heap = prev_heap;
if(!prev_inuse(p)) { /* consolidate backward */
p = prev_chunk(p);
unlink(p, bck, fwd);
}
assert(((unsigned long)((char*)p + new_size) & (pagesz-1)) == 0);
assert( ((char*)p + new_size) == ((char*)heap + heap->size) );
top(ar_ptr) = top_chunk = p;
set_head(top_chunk, new_size | PREV_INUSE);
/*check_chunk(ar_ptr, top_chunk);*/
}
top_size = chunksize(top_chunk);
extra = ((top_size - pad - MINSIZE + (pagesz-1))/pagesz - 1) * pagesz;
if(extra < (long)pagesz)
return 0;
/* Try to shrink. */
if(grow_heap(heap, -extra) != 0)
return 0;
ar_ptr->system_mem -= extra;
arena_mem -= extra;
/* Success. Adjust top accordingly. */
set_head(top_chunk, (top_size - extra) | PREV_INUSE);
/*check_chunk(ar_ptr, top_chunk);*/
return 1;
}
static mstate
internal_function
#if __STD_C
arena_get2(mstate a_tsd, size_t size)
#else
arena_get2(a_tsd, size) mstate a_tsd; size_t size;
#endif
{
mstate a;
int err;
if(!a_tsd)
a = a_tsd = &main_arena;
else {
a = a_tsd->next;
if(!a) {
/* This can only happen while initializing the new arena. */
(void)mutex_lock(&main_arena.mutex);
THREAD_STAT(++(main_arena.stat_lock_wait));
return &main_arena;
}
}
/* Check the global, circularly linked list for available arenas. */
repeat:
do {
if(!mutex_trylock(&a->mutex)) {
THREAD_STAT(++(a->stat_lock_loop));
tsd_setspecific(arena_key, (Void_t *)a);
return a;
}
a = a->next;
} while(a != a_tsd);
/* If not even the list_lock can be obtained, try again. This can
happen during `atfork', or for example on systems where thread
creation makes it temporarily impossible to obtain _any_
locks. */
if(mutex_trylock(&list_lock)) {
a = a_tsd;
goto repeat;
}
(void)mutex_unlock(&list_lock);
/* Nothing immediately available, so generate a new arena. */
a = _int_new_arena(size);
if(!a)
return 0;
tsd_setspecific(arena_key, (Void_t *)a);
mutex_init(&a->mutex);
err = mutex_lock(&a->mutex); /* remember result */
/* Add the new arena to the global list. */
(void)mutex_lock(&list_lock);
a->next = main_arena.next;
/* OMPI: use our barriers
atomic_write_barrier ();
*/
opal_atomic_wmb();
main_arena.next = a;
(void)mutex_unlock(&list_lock);
if(err) /* locking failed; keep arena for further attempts later */
return 0;
THREAD_STAT(++(a->stat_lock_loop));
return a;
}
/* Create a new arena with initial size "size". */
mstate
_int_new_arena(size_t size)
{
mstate a;
heap_info *h;
char *ptr;
unsigned long misalign;
h = new_heap(size + (sizeof(*h) + sizeof(*a) + MALLOC_ALIGNMENT),
mp_.top_pad);
if(!h) {
/* Maybe size is too large to fit in a single heap. So, just try
to create a minimally-sized arena and let _int_malloc() attempt
to deal with the large request via mmap_chunk(). */
h = new_heap(sizeof(*h) + sizeof(*a) + MALLOC_ALIGNMENT, mp_.top_pad);
if(!h)
return 0;
}
a = h->ar_ptr = (mstate)(h+1);
malloc_init_state(a);
/*a->next = NULL;*/
a->system_mem = a->max_system_mem = h->size;
arena_mem += h->size;
#ifdef NO_THREADS
if((unsigned long)(mp_.mmapped_mem + arena_mem + main_arena.system_mem) >
mp_.max_total_mem)
mp_.max_total_mem = mp_.mmapped_mem + arena_mem + main_arena.system_mem;
#endif
/* Set up the top chunk, with proper alignment. */
ptr = (char *)(a + 1);
misalign = (unsigned long)chunk2mem(ptr) & MALLOC_ALIGN_MASK;
if (misalign > 0)
ptr += MALLOC_ALIGNMENT - misalign;
top(a) = (mchunkptr)ptr;
set_head(top(a), (((char*)h + h->size) - ptr) | PREV_INUSE);
return a;
}
/* Obtain the arena number n. Needed in malloc_stats. */
mstate
_int_get_arena (int n)
{
mstate a = &main_arena;
while (n-- != 0) {
a = a->next;
if (a == &main_arena)
return 0;
}
return a;
}
#endif /* USE_ARENAS */
/*
* Local variables:
* c-basic-offset: 2
* End:
*/

Просмотреть файл

@ -1,236 +0,0 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
AC_DEFUN([MCA_opal_memory_linux_PRIORITY], [40])
AC_DEFUN([MCA_opal_memory_linux_COMPILE_MODE], [
AC_MSG_CHECKING([for MCA component $2:$3 compile mode])
$4="static"
AC_MSG_RESULT([$$4])
])
# MCA_memory_linux_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_memory_linux_CONFIG],[
AC_CONFIG_FILES([opal/mca/memory/linux/Makefile])
OPAL_VAR_SCOPE_PUSH([memory_linux_ptmalloc2_happy memory_linux_ummu_happy memory_linux_requested icc_major_ver icc_minor_ver memory_linux_mmap memory_linux_munmap memory_linux_LIBS_SAVE])
# Only allow this component to build on Linux-based systems
AC_MSG_CHECKING([operating system])
case $host in
*linux*)
AC_MSG_RESULT([$host -- supported])
memory_linux_ptmalloc2_happy=yes
memory_linux_ummu_happy=yes
;;
*)
AC_MSG_RESULT([$host -- unsupported])
memory_linux_ptmalloc2_happy=no
memory_linux_ummu_happy=no
;;
esac
AS_IF([test "$with_memory_manager" = "linux"],
[memory_linux_ptmalloc2_happy=yes
memory_linux_ummu_happy=yes
memory_linux_requested=1],
[memory_linux_requested=0
AS_IF([test -z "$with_memory_manager" || test "$with_memory_manager" = "yes"],
[memory_linux_ptmalloc2_happy=yes
memory_linux_ummu_happy=yes],
[memory_linux_ptmalloc2_happy=no
memory_linux_ummu_happy=no])])
######################################################################
# if memory hook available
######################################################################
memory_hook_found=1
AS_IF([test "$memory_hook_found" -eq 1],
[memory_hook_found=0 AC_CHECK_HEADER([malloc.h],
[AC_CHECK_FUNC([__malloc_initialize_hook],
[AC_CHECK_FUNC([__malloc_hook],
[AC_CHECK_FUNC([__realloc_hook],
[AC_CHECK_FUNC([__free_hook],
[memory_hook_found=1])])])])])])
AC_MSG_CHECKING([whether the system can use malloc hooks])
AS_IF([test "$memory_hook_found" = "0"],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes])])
AC_DEFINE_UNQUOTED([MEMORY_LINUX_HAVE_MALLOC_HOOK_SUPPORT], [$memory_hook_found],
[Whether the system has Memory Allocation Hooks])
AC_ARG_ENABLE(memory-linux-malloc-alignment,
AC_HELP_STRING([--enable-memory-linux-malloc-alignment], [Enable support for allocated memory alignment. Default: enabled if supported, disabled otherwise.]))
malloc_align_enabled=0
AS_IF([test "$enable_memory_linux_malloc_alignment" != "no"],
[malloc_align_enabled=$memory_hook_found])
AS_IF([test "$enable_memory_linux_malloc_alignment" = "yes" && test "$malloc_align_enabled" = "0"],
[AC_MSG_ERROR([memory linux malloc alignment is requested but __malloc_hook is not available])])
AC_MSG_CHECKING([whether the memory linux will use malloc alignment])
AS_IF([test "$malloc_align_enabled" = "0"],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes])])
AC_DEFINE_UNQUOTED(MEMORY_LINUX_MALLOC_ALIGN_ENABLED, [$malloc_align_enabled],
[Whether the memory linux malloc alignment is enabled])
######################################################################
# ptmalloc2
######################################################################
# Per ticket #227, Intel 9.0 v20051201 on ia64 with optimization
# of -O2 or higher will bork linux in strange in mysterious ways.
# Doh! So if the compiler vendor is intel and we're on an ia64
# box, run "icc --version" and snarf the version string. If it's
# 9.0 and the version is <= 20051201, then disable ptmalloc2.
# Executive decision: ignore optimization levels (even though -O1
# and -O0 seem to work). The upgrade to 9.1 is free, so that's a
# better path than trying to make a much more complicated test
# here.
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[case $host in
ia64-*)
AS_IF([test "$opal_c_vendor" = "intel"],
[# check for v9.0 <= 20051201
icc_major_ver="`$CC --version | head -n 1 | awk '{ print [$]3 }'`"
icc_minor_ver="`$CC --version | head -n 1 | awk '{ print [$]4 }'`"
AS_IF([test "$icc_major_ver" = "9.0" && test "`expr $icc_minor_ver \<= 20051201`" = "1"],
[memory_linux_ptmalloc2_happy=no
AC_MSG_WARN([*** Detected Intel C compiler v9.0 <= 20051201 on ia64])
AC_MSG_WARN([*** This compiler/platform combination has known problems with ptmalloc2])
AC_MSG_WARN([*** Disabling ptmalloc2])])])
;;
esac])
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[# check for malloc.h
AC_CHECK_HEADER([malloc.h],
[memory_linux_ptmalloc2_happy=yes],
[memory_linux_ptmalloc2_happy=no])])
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[# check for init hook symbol
AC_CHECK_DECL([__malloc_initialize_hook],
[memory_linux_ptmalloc2_happy=yes],
[memory_linux_ptmalloc2_happy=no],
[AC_INCLUDES_DEFAULT
#include <malloc.h>])])
#
# See if we have sbrk prototyped
#
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[AC_CHECK_DECLS([sbrk])])
#
# Figure out how we're going to call mmap/munmap for real
#
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[memory_linux_mmap=0
memory_linux_munmap=1
# it's nearly impossible to call mmap from syscall(), so
# only go this route if we can't get at munmap any other
# way.
AC_CHECK_HEADER([syscall.h],
[AC_CHECK_FUNCS([syscall], [], [memory_linux_munmap=0])])
# Always look for __munmap and __mmap
AC_CHECK_FUNCS([__munmap], [memory_linux_mmap=1])
AC_CHECK_FUNCS([__mmap])
# only allow dlsym (and therefore add -ldl) if we
# really need to
AS_IF([test "$memory_linux_mmap" = "0"],
[memory_linux_LIBS_SAVE="$LIBS"
AC_CHECK_LIB([dl],
[dlsym],
[LIBS="$LIBS -ldl"
memory_linux_LIBS="-ldl"
memory_linux_mmap=1])
AC_CHECK_FUNCS([dlsym])
LIBS="$memory_linux_LIBS_SAVE"])
AS_IF([test "$memory_linux_mmap" = "0" && test "$memory_linux_munmap" = "0"],
[memory_linux_ptmalloc2_happy=no])])
# If all is good, save the extra libs for the wrapper
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes],
[value=1],
[value=0])
AC_DEFINE_UNQUOTED([MEMORY_LINUX_PTMALLOC2], [$value],
[Whether ptmalloc2 is supported on this system or not])
AM_CONDITIONAL([MEMORY_LINUX_PTMALLOC2],
[test "$memory_linux_ptmalloc2_happy" = yes])
######################################################################
# ummunotify
######################################################################
# Check for the relevant header
AS_IF([test "$memory_linux_ummu_happy" = yes],
[# check for linux/ummunotify.h
AC_CHECK_HEADER([linux/ummunotify.h],
[memory_linux_ummu_happy=yes],
[memory_linux_ummu_happy=no])])
# <stropts.h> has the Linux declaration for ioctl
AC_CHECK_HEADERS([stropts.h])
# If all is good, set the header file that we want the rest of the
# code base to use
AS_IF([test "$memory_linux_ummu_happy" = yes],
[memory_base_include="linux/public.h"
value=1],
[value=0])
AC_DEFINE_UNQUOTED([MEMORY_LINUX_UMMUNOTIFY], [$value],
[Whether ummunotify is supported on this system or not])
AM_CONDITIONAL([MEMORY_LINUX_UMMUNOTIFY],
[test "$memory_linux_ummu_happy" = yes])
######################################################################
# post processing
######################################################################
AS_IF([test "$memory_malloc_hooks_requested" = 1 && \
test "$memory_linux_ptmalloc2_happy" = no && \
test "$memory_linux_ummu_happy" = no],
[AC_MSG_ERROR([linux memory management requested but neither ptmalloc2 nor ummunotify are available. Aborting.])])
AC_SUBST([memory_linux_LIBS])
AS_IF([test "$memory_linux_ptmalloc2_happy" = yes || \
test "$memory_linux_ummu_happy" = yes],
[memory_base_found=1
$1],
[memory_base_found=0
memory_base_include=
$2])
OPAL_VAR_SCOPE_POP
])

Просмотреть файл

@ -1,29 +0,0 @@
# -*- text -*-
#
# Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
# Copyright (c) 2010-2014 Cisco Systems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# This is the US/English help file for Open MPI's memory/linux component.
#
[ummunotify eaccess]
Open MPI was unable to open the UMMU notification device. This is
likely a permissions problem on the device itself. UMMU notification
support is therefore disabled in this process; an alternate memory
hook manager *may* be used instead (if available).
Local host: %s
UMMU device: %s
#
[ummunotify open error]
Open MPI was unable to open the UMMU notification device. UMMU
notification support is therefore disabled in this process; an
alternate memory hook manager *may* be used instead (if available).
Local host: %s
UMMU device: %s
Error: %s (%d)

Просмотреть файл

@ -1,895 +0,0 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2012-2013 Los Alamos National Security, LLC. All rights
* reserved.
*
* Additional copyrights may follow.
*/
/* Malloc implementation for multiple threads without lock contention.
Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* $Id: hooks.c,v 1.12 2004/11/05 14:42:32 wg Exp $ */
#include "opal_config.h"
#include "opal/mca/mca.h"
#include "opal/mca/memory/memory.h"
#include "opal/constants.h"
#include "opal/memoryhooks/memory.h"
#include "opal/mca/memory/linux/memory_linux.h"
#ifndef DEFAULT_CHECK_ACTION
#define DEFAULT_CHECK_ACTION 1
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h> /* for stat */
#endif /* HAVE_SYS_STAT_H */
/* Defined in memory_linux_component.c */
extern bool opal_memory_linux_disable;
/* What to do if the standard debugging hooks are in place and a
corrupt pointer is detected: do nothing (0), print an error message
(1), or call abort() (2). */
/* Hooks for debugging versions. The initial hooks just call the
initialization routine, then do the normal work. */
#if !(USE_STARTER & 2)
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
malloc_hook_ini(size_t sz, const __malloc_ptr_t caller)
#else
malloc_hook_ini(sz, caller)
size_t sz; const __malloc_ptr_t caller;
#endif
{
__malloc_hook = NULL;
ptmalloc_init();
return public_mALLOc(sz);
}
#endif
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
realloc_hook_ini(Void_t* ptr, size_t sz, const __malloc_ptr_t caller)
#else
realloc_hook_ini(ptr, sz, caller)
Void_t* ptr; size_t sz; const __malloc_ptr_t caller;
#endif
{
__malloc_hook = NULL;
__realloc_hook = NULL;
ptmalloc_init();
return public_rEALLOc(ptr, sz);
}
#endif
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
memalign_hook_ini(size_t alignment, size_t sz, const __malloc_ptr_t caller)
#else
memalign_hook_ini(alignment, sz, caller)
size_t alignment; size_t sz; const __malloc_ptr_t caller;
#endif
{
__memalign_hook = NULL;
ptmalloc_init();
return public_mEMALIGn(alignment, sz);
}
#endif
#endif /* !(USE_STARTER & 2) */
static int check_action = DEFAULT_CHECK_ACTION;
/* Whether we are using malloc checking. */
static int using_malloc_checking;
/* A flag that is set by malloc_set_state, to signal that malloc checking
must not be enabled on the request from the user (via the MALLOC_CHECK_
environment variable). It is reset by __malloc_check_init to tell
malloc_set_state that the user has requested malloc checking.
The purpose of this flag is to make sure that malloc checking is not
enabled when the heap to be restored was constructed without malloc
checking, and thus does not contain the required magic bytes.
Otherwise the heap would be corrupted by calls to free and realloc. If
it turns out that the heap was created with malloc checking and the
user has requested it malloc_set_state just calls __malloc_check_init
again to enable it. On the other hand, reusing such a heap without
further malloc checking is safe. */
static int disallow_malloc_check;
/* Activate a standard set of debugging hooks. */
void
__malloc_check_init()
{
if (disallow_malloc_check) {
disallow_malloc_check = 0;
return;
}
using_malloc_checking = 1;
__malloc_hook = malloc_check;
__free_hook = free_check;
__realloc_hook = realloc_check;
__memalign_hook = memalign_check;
if(check_action & 1)
fprintf(stderr, "malloc: using debugging hooks\n");
}
/* A simple, standard set of debugging hooks. Overhead is `only' one
byte per chunk; still this will catch most cases of double frees or
overruns. The goal here is to avoid obscure crashes due to invalid
usage, unlike in the MALLOC_DEBUG code. */
#define MAGICBYTE(p) ( ( ((size_t)p >> 3) ^ ((size_t)p >> 11)) & 0xFF )
/* Instrument a chunk with overrun detector byte(s) and convert it
into a user pointer with requested size sz. */
static Void_t*
internal_function
#if __STD_C
mem2mem_check(Void_t *ptr, size_t sz)
#else
mem2mem_check(ptr, sz) Void_t *ptr; size_t sz;
#endif
{
mchunkptr p;
unsigned char* m_ptr = (unsigned char*)BOUNDED_N(ptr, sz);
size_t i;
if (!ptr)
return ptr;
p = mem2chunk(ptr);
for(i = chunksize(p) - (chunk_is_mmapped(p) ? 2*SIZE_SZ+1 : SIZE_SZ+1);
i > sz;
i -= 0xFF) {
if(i-sz < 0x100) {
m_ptr[i] = (unsigned char)(i-sz);
break;
}
m_ptr[i] = 0xFF;
}
m_ptr[sz] = MAGICBYTE(p);
return (Void_t*)m_ptr;
}
/* Convert a pointer to be free()d or realloc()ed to a valid chunk
pointer. If the provided pointer is not valid, return NULL. */
static mchunkptr
internal_function
#if __STD_C
mem2chunk_check(Void_t* mem)
#else
mem2chunk_check(mem) Void_t* mem;
#endif
{
mchunkptr p;
INTERNAL_SIZE_T sz, c;
unsigned char magic;
if(!aligned_OK(mem)) return NULL;
p = mem2chunk(mem);
if (!chunk_is_mmapped(p)) {
/* Must be a chunk in conventional heap memory. */
int contig = contiguous(&main_arena);
sz = chunksize(p);
if((contig &&
((char*)p<mp_.sbrk_base ||
((char*)p + sz)>=(mp_.sbrk_base+main_arena.system_mem) )) ||
sz<MINSIZE || sz&MALLOC_ALIGN_MASK || !inuse(p) ||
( !prev_inuse(p) && (p->prev_size&MALLOC_ALIGN_MASK ||
(contig && (char*)prev_chunk(p)<mp_.sbrk_base) ||
next_chunk(prev_chunk(p))!=p) ))
return NULL;
magic = MAGICBYTE(p);
for(sz += SIZE_SZ-1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
}
((unsigned char*)p)[sz] ^= 0xFF;
} else {
unsigned long offset, page_mask = malloc_getpagesize-1;
/* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
alignment relative to the beginning of a page. Check this
first. */
offset = (unsigned long)mem & page_mask;
if((offset!=MALLOC_ALIGNMENT && offset!=0 && offset!=0x10 &&
offset!=0x20 && offset!=0x40 && offset!=0x80 && offset!=0x100 &&
offset!=0x200 && offset!=0x400 && offset!=0x800 && offset!=0x1000 &&
offset<0x2000) ||
!chunk_is_mmapped(p) || (p->size & PREV_INUSE) ||
( (((unsigned long)p - p->prev_size) & page_mask) != 0 ) ||
( (sz = chunksize(p)), ((p->prev_size + sz) & page_mask) != 0 ) )
return NULL;
magic = MAGICBYTE(p);
for(sz -= 1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
}
((unsigned char*)p)[sz] ^= 0xFF;
}
return p;
}
/* Check for corruption of the top chunk, and try to recover if
necessary. */
static int
internal_function
#if __STD_C
top_check(void)
#else
top_check()
#endif
{
mchunkptr t = top(&main_arena);
char* brk, * new_brk;
INTERNAL_SIZE_T front_misalign, sbrk_size;
unsigned long pagesz = malloc_getpagesize;
if (t == initial_top(&main_arena) ||
(!chunk_is_mmapped(t) &&
chunksize(t)>=MINSIZE &&
prev_inuse(t) &&
(!contiguous(&main_arena) ||
(char*)t + chunksize(t) == mp_.sbrk_base + main_arena.system_mem)))
return 0;
if(check_action & 1)
fprintf(stderr, "malloc: top chunk is corrupt\n");
if(check_action & 2)
abort();
/* Try to set up a new top chunk. */
brk = MORECORE(0);
front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
if (front_misalign > 0)
front_misalign = MALLOC_ALIGNMENT - front_misalign;
sbrk_size = front_misalign + mp_.top_pad + MINSIZE;
sbrk_size += pagesz - ((unsigned long)(brk + sbrk_size) & (pagesz - 1));
new_brk = (char*)(MORECORE (sbrk_size));
if (new_brk == (char*)(MORECORE_FAILURE)) return -1;
/* Call the `morecore' hook if necessary. */
if (__after_morecore_hook)
(*__after_morecore_hook) ();
main_arena.system_mem = (new_brk - mp_.sbrk_base) + sbrk_size;
top(&main_arena) = (mchunkptr)(brk + front_misalign);
set_head(top(&main_arena), (sbrk_size - front_misalign) | PREV_INUSE);
return 0;
}
static Void_t*
#if __STD_C
malloc_check(size_t sz, const Void_t *caller)
#else
malloc_check(sz, caller) size_t sz; const Void_t *caller;
#endif
{
Void_t *victim;
(void)mutex_lock(&main_arena.mutex);
victim = (top_check() >= 0) ? _int_malloc(&main_arena, sz+1) : NULL;
(void)mutex_unlock(&main_arena.mutex);
return mem2mem_check(victim, sz);
}
static void
#if __STD_C
free_check(Void_t* mem, const Void_t *caller)
#else
free_check(mem, caller) Void_t* mem; const Void_t *caller;
#endif
{
mchunkptr p;
if(!mem) return;
(void)mutex_lock(&main_arena.mutex);
p = mem2chunk_check(mem);
if(!p) {
(void)mutex_unlock(&main_arena.mutex);
if(check_action & 1)
fprintf(stderr, "free(): invalid pointer %p!\n", mem);
if(check_action & 2)
abort();
return;
}
#if HAVE_MMAP
if (chunk_is_mmapped(p)) {
(void)mutex_unlock(&main_arena.mutex);
munmap_chunk(p);
return;
}
#endif
#if 0 /* Erase freed memory. */
memset(mem, 0, chunksize(p) - (SIZE_SZ+1));
#endif
_int_free(&main_arena, mem);
(void)mutex_unlock(&main_arena.mutex);
}
static Void_t*
#if __STD_C
realloc_check(Void_t* oldmem, size_t bytes, const Void_t *caller)
#else
realloc_check(oldmem, bytes, caller)
Void_t* oldmem; size_t bytes; const Void_t *caller;
#endif
{
mchunkptr oldp;
INTERNAL_SIZE_T nb, oldsize;
Void_t* newmem = 0;
if (oldmem == 0) return malloc_check(bytes, NULL);
(void)mutex_lock(&main_arena.mutex);
oldp = mem2chunk_check(oldmem);
(void)mutex_unlock(&main_arena.mutex);
if(!oldp) {
if(check_action & 1)
fprintf(stderr, "realloc(): invalid pointer %p!\n", oldmem);
if(check_action & 2)
abort();
return malloc_check(bytes, NULL);
}
oldsize = chunksize(oldp);
checked_request2size(bytes+1, nb);
(void)mutex_lock(&main_arena.mutex);
#if HAVE_MMAP
if (chunk_is_mmapped(oldp)) {
#if HAVE_MREMAP
mchunkptr newp = mremap_chunk(oldp, nb);
if(newp)
newmem = chunk2mem(newp);
else
#endif
{
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb)
newmem = oldmem; /* do nothing */
else {
/* Must alloc, copy, free. */
if (top_check() >= 0)
newmem = _int_malloc(&main_arena, bytes+1);
if (newmem) {
MALLOC_COPY(BOUNDED_N(newmem, bytes+1), oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
}
}
}
} else {
#endif /* HAVE_MMAP */
if (top_check() >= 0)
newmem = _int_realloc(&main_arena, oldmem, bytes+1);
#if 0 /* Erase freed memory. */
if(newmem)
newp = mem2chunk(newmem);
nb = chunksize(newp);
if(oldp<newp || oldp>=chunk_at_offset(newp, nb)) {
memset((char*)oldmem + 2*sizeof(mbinptr), 0,
oldsize - (2*sizeof(mbinptr)+2*SIZE_SZ+1));
} else if(nb > oldsize+SIZE_SZ) {
memset((char*)BOUNDED_N(chunk2mem(newp), bytes) + oldsize,
0, nb - (oldsize+SIZE_SZ));
}
#endif
#if HAVE_MMAP
}
#endif
(void)mutex_unlock(&main_arena.mutex);
return mem2mem_check(newmem, bytes);
}
static Void_t*
#if __STD_C
memalign_check(size_t alignment, size_t bytes, const Void_t *caller)
#else
memalign_check(alignment, bytes, caller)
size_t alignment; size_t bytes; const Void_t *caller;
#endif
{
INTERNAL_SIZE_T nb;
Void_t* mem;
if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL);
if (alignment < MINSIZE) alignment = MINSIZE;
checked_request2size(bytes+1, nb);
(void)mutex_lock(&main_arena.mutex);
mem = (top_check() >= 0) ? _int_memalign(&main_arena, alignment, bytes+1) :
NULL;
(void)mutex_unlock(&main_arena.mutex);
return mem2mem_check(mem, bytes);
}
#if !defined NO_THREADS && USE_STARTER
/* The following hooks are used when the global initialization in
ptmalloc_init() hasn't completed yet. */
static Void_t*
#if __STD_C
malloc_starter(size_t sz, const Void_t *caller)
#else
malloc_starter(sz, caller) size_t sz; const Void_t *caller;
#endif
{
Void_t* victim;
ptmalloc_init_minimal();
victim = _int_malloc(&main_arena, sz);
return victim ? BOUNDED_N(victim, sz) : 0;
}
static Void_t*
#if __STD_C
memalign_starter(size_t align, size_t sz, const Void_t *caller)
#else
memalign_starter(align, sz, caller) size_t align, sz; const Void_t *caller;
#endif
{
Void_t* victim;
ptmalloc_init_minimal();
victim = _int_memalign(&main_arena, align, sz);
return victim ? BOUNDED_N(victim, sz) : 0;
}
static void
#if __STD_C
free_starter(Void_t* mem, const Void_t *caller)
#else
free_starter(mem, caller) Void_t* mem; const Void_t *caller;
#endif
{
mchunkptr p;
if(!mem) return;
p = mem2chunk(mem);
#if HAVE_MMAP
if (chunk_is_mmapped(p)) {
munmap_chunk(p);
return;
}
#endif
_int_free(&main_arena, mem);
}
#endif /* !defined NO_THREADS && USE_STARTER */
/* Get/set state: malloc_get_state() records the current state of all
malloc variables (_except_ for the actual heap contents and `hook'
function pointers) in a system dependent, opaque data structure.
This data structure is dynamically allocated and can be free()d
after use. malloc_set_state() restores the state of all malloc
variables to the previously obtained state. This is especially
useful when using this malloc as part of a shared library, and when
the heap contents are saved/restored via some other method. The
primary example for this is GNU Emacs with its `dumping' procedure.
`Hook' function pointers are never saved or restored by these
functions, with two exceptions: If malloc checking was in use when
malloc_get_state() was called, then malloc_set_state() calls
__malloc_check_init() if possible; if malloc checking was not in
use in the recorded state but the user requested malloc checking,
then the hooks are reset to 0. */
#define MALLOC_STATE_MAGIC 0x444c4541l
#define MALLOC_STATE_VERSION (0*0x100l + 2l) /* major*0x100 + minor */
struct malloc_save_state {
long magic;
long version;
mbinptr av[NBINS * 2 + 2];
char* sbrk_base;
int sbrked_mem_bytes;
unsigned long trim_threshold;
unsigned long top_pad;
unsigned int n_mmaps_max;
unsigned long mmap_threshold;
int check_action;
unsigned long max_sbrked_mem;
unsigned long max_total_mem;
unsigned int n_mmaps;
unsigned int max_n_mmaps;
unsigned long mmapped_mem;
unsigned long max_mmapped_mem;
int using_malloc_checking;
};
Void_t*
public_gET_STATe(void)
{
struct malloc_save_state* ms;
int i;
mbinptr b;
ms = (struct malloc_save_state*)public_mALLOc(sizeof(*ms));
if (!ms)
return 0;
(void)mutex_lock(&main_arena.mutex);
malloc_consolidate(&main_arena);
ms->magic = MALLOC_STATE_MAGIC;
ms->version = MALLOC_STATE_VERSION;
ms->av[0] = 0;
ms->av[1] = 0; /* used to be binblocks, now no longer used */
ms->av[2] = top(&main_arena);
ms->av[3] = 0; /* used to be undefined */
for(i=1; i<NBINS; i++) {
b = bin_at(&main_arena, i);
if(first(b) == b)
ms->av[2*i+2] = ms->av[2*i+3] = 0; /* empty bin */
else {
ms->av[2*i+2] = first(b);
ms->av[2*i+3] = last(b);
}
}
ms->sbrk_base = mp_.sbrk_base;
ms->sbrked_mem_bytes = main_arena.system_mem;
ms->trim_threshold = mp_.trim_threshold;
ms->top_pad = mp_.top_pad;
ms->n_mmaps_max = mp_.n_mmaps_max;
ms->mmap_threshold = mp_.mmap_threshold;
ms->check_action = check_action;
ms->max_sbrked_mem = main_arena.max_system_mem;
#ifdef NO_THREADS
ms->max_total_mem = mp_.max_total_mem;
#else
ms->max_total_mem = 0;
#endif
ms->n_mmaps = mp_.n_mmaps;
ms->max_n_mmaps = mp_.max_n_mmaps;
ms->mmapped_mem = mp_.mmapped_mem;
ms->max_mmapped_mem = mp_.max_mmapped_mem;
ms->using_malloc_checking = using_malloc_checking;
(void)mutex_unlock(&main_arena.mutex);
return (Void_t*)ms;
}
int
public_sET_STATe(Void_t* msptr)
{
struct malloc_save_state* ms = (struct malloc_save_state*)msptr;
int i;
mbinptr b;
disallow_malloc_check = 1;
ptmalloc_init();
if(ms->magic != MALLOC_STATE_MAGIC) return -1;
/* Must fail if the major version is too high. */
if((ms->version & ~0xffl) > (MALLOC_STATE_VERSION & ~0xffl)) return -2;
(void)mutex_lock(&main_arena.mutex);
/* There are no fastchunks. */
clear_fastchunks(&main_arena);
set_max_fast(&main_arena, DEFAULT_MXFAST);
for (i=0; i<(int)NFASTBINS; ++i)
main_arena.fastbins[i] = 0;
for (i=0; i<(int)BINMAPSIZE; ++i)
main_arena.binmap[i] = 0;
top(&main_arena) = ms->av[2];
main_arena.last_remainder = 0;
for(i=1; i<NBINS; i++) {
b = bin_at(&main_arena, i);
if(ms->av[2*i+2] == 0) {
assert(ms->av[2*i+3] == 0);
first(b) = last(b) = b;
} else {
if(i<(int)NSMALLBINS || ((int)largebin_index(chunksize(ms->av[2*i+2]))==i &&
(int)largebin_index(chunksize(ms->av[2*i+3]))==i)) {
first(b) = ms->av[2*i+2];
last(b) = ms->av[2*i+3];
/* Make sure the links to the bins within the heap are correct. */
first(b)->bk = b;
last(b)->fd = b;
/* Set bit in binblocks. */
mark_bin(&main_arena, i);
} else {
/* Oops, index computation from chunksize must have changed.
Link the whole list into unsorted_chunks. */
first(b) = last(b) = b;
b = unsorted_chunks(&main_arena);
ms->av[2*i+2]->bk = b;
ms->av[2*i+3]->fd = b->fd;
b->fd->bk = ms->av[2*i+3];
b->fd = ms->av[2*i+2];
}
}
}
mp_.sbrk_base = ms->sbrk_base;
main_arena.system_mem = ms->sbrked_mem_bytes;
mp_.trim_threshold = ms->trim_threshold;
mp_.top_pad = ms->top_pad;
mp_.n_mmaps_max = ms->n_mmaps_max;
mp_.mmap_threshold = ms->mmap_threshold;
check_action = ms->check_action;
main_arena.max_system_mem = ms->max_sbrked_mem;
#ifdef NO_THREADS
mp_.max_total_mem = ms->max_total_mem;
#endif
mp_.n_mmaps = ms->n_mmaps;
mp_.max_n_mmaps = ms->max_n_mmaps;
mp_.mmapped_mem = ms->mmapped_mem;
mp_.max_mmapped_mem = ms->max_mmapped_mem;
/* add version-dependent code here */
if (ms->version >= 1) {
/* Check whether it is safe to enable malloc checking, or whether
it is necessary to disable it. */
if (ms->using_malloc_checking && !using_malloc_checking &&
!disallow_malloc_check)
__malloc_check_init ();
else if (!ms->using_malloc_checking && using_malloc_checking) {
__malloc_hook = 0;
__free_hook = 0;
__realloc_hook = 0;
__memalign_hook = 0;
using_malloc_checking = 0;
}
}
check_malloc_state(&main_arena);
(void)mutex_unlock(&main_arena.mutex);
return 0;
}
/*-------------------------------------------------------------------------
OMPI change: Per
http://www.gnu.org/software/libc/manual/html_mono/libc.html#Hooks-for-Malloc,
we can define the __malloc_initialize_hook variable to be a
function that is invoked before the first allocation is ever
performed. We use this hook to wholly replace the underlying
allocator to our own allocator if a few conditions are met.
Remember that this hook is called probably at the very very very
beginning of the process. MCA parameters haven't been setup yet --
darn near nothing has been setup yet. Indeed, we're effectively in
signal context because we can't call anything that calls malloc.
So we can basically have some hard-coded tests for things to see if
we want to setup to use our internal ptmalloc2 or not. */
static void *opal_memory_linux_malloc_hook(size_t sz,
const __malloc_ptr_t caller)
{
return public_mALLOc(sz);
}
static void *opal_memory_linux_realloc_hook(Void_t* ptr, size_t sz,
const __malloc_ptr_t caller)
{
return public_rEALLOc(ptr, sz);
}
static void *opal_memory_linux_memalign_hook(size_t alignment, size_t sz,
const __malloc_ptr_t caller)
{
return public_mEMALIGn(alignment, sz);
}
static void opal_memory_linux_free_hook(__malloc_ptr_t __ptr,
const __malloc_ptr_t caller)
{
public_fREe(__ptr);
}
typedef enum {
RESULT_NO,
RESULT_YES,
RESULT_RUNTIME,
RESULT_NOT_FOUND
} check_result_t;
static check_result_t check(const char *name)
{
char *s = getenv(name);
if (NULL == s) {
return RESULT_NOT_FOUND;
}
if ('0' == s[0] && '\0' == s[1]) {
/* A value of 0 means "don't use!" */
return RESULT_NO;
} else if ('-' == s[0] && '1' == s[1] && '\0' == s[2]) {
/* A value of -1 means "use it if it would be advantageous */
return RESULT_RUNTIME;
} else {
/* Any other value means "use the hooks, Luke!" */
return RESULT_YES;
}
}
/* This function is called on loading libmpi in case system has Memory Allocation Hooks
* (see ompi/runtime/ompi_mpi_init.c for details)
*/
void opal_memory_linux_malloc_init_hook(void)
{
check_result_t r1, lp, lpp;
bool want_rcache = false, found_driver = false;
/* First, check for a FAKEROOT environment. If we're in a
fakeroot, then access() (and likely others) have been replaced
and are not safe to call here in this pre-main environment. So
check for the environment markers that we're in a FAKEROOT.
And if so, return immediately.
Note that this check was inspired by a problem with Debian's
"fakeroot" build environment that allocates memory during
stat() (see http://bugs.debian.org/531522). It may not be
necessary any more since we're using access(), not stat(). But
we'll leave the check, anyway.
This is also an issue when using Gentoo's version of
'fakeroot', sandbox v2.5. Sandbox environments can also be
detected fairly easily by looking for SANDBOX_ON. */
if (getenv("FAKEROOTKEY") != NULL ||
getenv("FAKED_MODE") != NULL ||
getenv("SANDBOX_ON") != NULL ) {
return;
}
#if MEMORY_LINUX_UMMUNOTIFY
/* Next, check if ummunotify is present on the system. If it is,
and if we were compile with ummunotify support, then we don't
need to do the following ptmalloc2 hacks. open/mmap on the
device may fail during init, but if /dev/ummunotify exists, we
assume that the user/administrator *wants* to use
ummunotify. */
if (access("/dev/ummunotify", F_OK) == 0) {
return;
}
#endif
/* Yes, checking for an MPI MCA parameter here is an abstraction
violation. Cope. Yes, even checking for *any* MCA parameter
here (without going through the MCA param API) is an
abstraction violation. Fricken' cope, will ya?
(unfortunately, there's really no good way to do this other
than this abstraction violation :-( ) */
lp = check("OPAL_MCA_leave_pinned");
if( RESULT_NOT_FOUND == lp ) lp = check(OPAL_MCA_PREFIX"mpi_leave_pinned");
lpp = check("OPAL_MCA_leave_pinned_pipeline");
if( RESULT_NOT_FOUND == lpp ) lpp = check(OPAL_MCA_PREFIX"mpi_leave_pinned_pipeline");
/* See if we want to disable this component. */
r1 = check(OPAL_MCA_PREFIX"memory_linux_disable");
if (RESULT_NOT_FOUND != r1 && RESULT_NO != r1) {
return;
}
/* Look for sentinel files (directories) to see if various network
drivers are loaded (yes, I know, further abstraction
violations...).
* All OpenFabrics devices will have files in
/sys/class/infiniband (even iWARP)
* Open-MX doesn't currently use a reg cache, but it might
someday. So be conservative and check for /dev/open-mx.
* MX will have one or more of /dev/myri[0-9]. Yuck.
*/
if (0 == access("/sys/class/infiniband", F_OK) ||
0 == access("/dev/open-mx", F_OK) ||
0 == access("/dev/myri0", F_OK) ||
0 == access("/dev/myri1", F_OK) ||
0 == access("/dev/myri2", F_OK) ||
0 == access("/dev/myri3", F_OK) ||
0 == access("/dev/myri4", F_OK) ||
0 == access("/dev/myri5", F_OK) ||
0 == access("/dev/myri6", F_OK) ||
0 == access("/dev/myri7", F_OK) ||
0 == access("/dev/myri8", F_OK) ||
0 == access("/dev/myri9", F_OK) ||
0 == access("/dev/ipath", F_OK) ||
0 == access("/dev/kgni0", F_OK) ||
0 == access("/dev/mic/scif", F_OK) ||
0 == access("/dev/scif", F_OK)) {
found_driver = true;
}
/* Simple combination of the results of these two environment
variables (if both "yes" and "no" are specified, then be
conservative and assume "yes"):
lp / lpp yes no runtime not found
yes yes yes yes yes
no yes no no no
runtime yes no runtime runtime
not found yes no runtime runtime
*/
if (RESULT_YES == lp || RESULT_YES == lpp) {
want_rcache = true;
} else if (RESULT_NO == lp || RESULT_NO == lpp) {
want_rcache = false;
} else {
want_rcache = found_driver;
}
if (want_rcache) {
/* Initialize ptmalloc */
ptmalloc_init();
/* Now set the hooks to point to our functions */
__free_hook = opal_memory_linux_free_hook;
__malloc_hook = opal_memory_linux_malloc_hook;
__memalign_hook = opal_memory_linux_memalign_hook;
__realloc_hook = opal_memory_linux_realloc_hook;
}
}
/* OMPI change: prototype the function below, otherwise we'll get
warnings about it not being declared (at least in developer/debug
builds). This function is not DECLSPEC'ed because we don't want it
visible outside of this component (i.e., libopen-pal, since this
component is never built as a DSO; it's always slurped into
libopen-pal). This declaration is not in malloc.h because this
function only exists as a horrid workaround to force linkers to
pull in this .o file (see explanation below). */
void opal_memory_linux_hook_pull(bool *want_hooks);
/* OMPI change: add a dummy function here that will be called by the
linux component open() function. This dummy function is
necessary for when OMPI is built as --disable-shared
--enable-static --disable-dlopen, because we won't use
-Wl,--export-dynamic when building OMPI. So we need to ensure that
not only that all the symbols in this file end up in libopen-pal.a,
but they also end up in the final exectuable (so that
__malloc_initialize_hook is there, overrides the weak symbol in
glibc, ....etc.). */
void opal_memory_linux_hook_pull(bool *want_hooks)
{
/* Make this slightly less than a dummy function -- register the
MCA parameter here (that way we keep the name of this MCA
parameter here within this one, single file). Register solely
so that it shows up in ompi_info -- by the time we register it,
the _malloc_init_hook() has almost certainly already fired, so
whatever value was set via normal MCA mechanisms likely won't
be see if it wasn't already see by the getenv() in the
_malloc_init_hook(). */
*want_hooks = !opal_memory_linux_disable;
}
/*
* Local variables:
* c-basic-offset: 4
* End:
*/

Просмотреть файл

@ -1,51 +0,0 @@
/* lran2.h
* by Wolfram Gloger 1996.
*
* A small, portable pseudo-random number generator.
*/
#ifndef _LRAN2_H
#define _LRAN2_H
#define LRAN2_MAX 714025l /* constants for portable */
#define IA 1366l /* random number generator */
#define IC 150889l /* (see e.g. `Numerical Recipes') */
struct lran2_st {
long x, y, v[97];
};
static void
lran2_init(struct lran2_st* d, long seed)
{
long x;
int j;
x = (IC - seed) % LRAN2_MAX;
if(x < 0) x = -x;
for(j=0; j<97; j++) {
x = (IA*x + IC) % LRAN2_MAX;
d->v[j] = x;
}
d->x = (IA*x + IC) % LRAN2_MAX;
d->y = d->x;
}
#ifdef __GNUC__
__inline__
#endif
static long
lran2(struct lran2_st* d)
{
int j = (d->y % 97);
d->y = d->v[j];
d->x = (IA*d->x + IC) % LRAN2_MAX;
d->v[j] = d->x;
return d->y;
}
#undef IA
#undef IC
#endif

Просмотреть файл

@ -1,169 +0,0 @@
/*
* Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
*
* Additional copyrights may follow.
*/
/* Malloc implementation for multiple threads; statistics printing.
Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>, 2004.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* $Id: $ */
/* OMPI change: Name-shift all the internal symbols */
#include "opal/mca/memory/linux/rename.h"
#include <stdio.h> /* needed for malloc_stats */
#include <malloc-machine.h>
#include "malloc.h"
/*
Define HAVE_MMAP as true to optionally make malloc() use mmap() to
allocate very large blocks. These will be returned to the
operating system immediately after a free(). Also, if mmap
is available, it is used as a backup strategy in cases where
MORECORE fails to provide space from system.
This malloc is best tuned to work with mmap for large requests.
If you do not have mmap, operations involving very large chunks (1MB
or so) may be slower than you'd like.
*/
#ifndef HAVE_MMAP
#define HAVE_MMAP 1
#endif
#ifdef USE_DL_PREFIX
#define public_mSTATs dlmalloc_stats
#else /* USE_DL_PREFIX */
#ifdef _LIBC
#define public_mSTATs __malloc_stats
#else /* !_LIBC */
#define public_mSTATs malloc_stats
#endif /* _LIBC */
#endif /* USE_DL_PREFIX */
/*
malloc_stats();
Prints on stderr the amount of space obtained from the system (both
via sbrk and mmap), the maximum amount (which may be more than
current if malloc_trim and/or munmap got called), and the current
number of bytes allocated via malloc (or realloc, etc) but not yet
freed. Note that this is the number of bytes allocated, not the
number requested. It will be larger than the number requested
because of alignment and bookkeeping overhead. Because it includes
alignment wastage as being in use, this figure may be greater than
zero even when no user-level chunks are allocated.
The reported current and maximum system memory can be inaccurate if
a program makes other calls to system memory allocation functions
(normally sbrk) outside of malloc.
malloc_stats prints only the most commonly interesting statistics.
More information can be obtained by calling mallinfo.
*/
void public_mSTATs __MALLOC_P((void));
/*
------------------------------ malloc_stats ------------------------------
*/
void public_mSTATs()
{
int i;
mstate ar_ptr;
struct malloc_global_info mgi;
struct malloc_arena_info mai;
unsigned long in_use_b, system_b, avail_b;
#if defined(THREAD_STATS) && THREAD_STATS
long stat_lock_direct = 0, stat_lock_loop = 0, stat_lock_wait = 0;
#endif
#if 0
if(__malloc_initialized < 0)
ptmalloc_init ();
#endif
_int_get_global_info(&mgi);
system_b = in_use_b = mgi.mmapped_mem;
#ifdef _LIBC
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
#endif
for (i=0; (ar_ptr = _int_get_arena(i)); i++) {
_int_get_arena_info(ar_ptr, &mai);
avail_b = mai.fastavail + mai.binavail + mai.top_size;
fprintf(stderr, "Arena %d:\n", i);
fprintf(stderr, "system bytes = %10lu\n",
(unsigned long)mai.system_mem);
fprintf(stderr, "in use bytes = %10lu\n",
(unsigned long)(mai.system_mem - avail_b));
#if MALLOC_DEBUG > 1
if (i > 0)
dump_heap(heap_for_ptr(top(ar_ptr)));
#endif
system_b += mai.system_mem;
in_use_b += mai.system_mem - avail_b;
#if defined(THREAD_STATS) && THREAD_STATS
stat_lock_direct += mai.stat_lock_direct;
stat_lock_loop += mai.stat_lock_loop;
stat_lock_wait += mai.stat_lock_wait;
#endif
}
#if HAVE_MMAP
fprintf(stderr, "Total (incl. mmap):\n");
#else
fprintf(stderr, "Total:\n");
#endif
fprintf(stderr, "system bytes = %10lu\n", system_b);
fprintf(stderr, "in use bytes = %10lu\n", in_use_b);
#ifdef NO_THREADS
fprintf(stderr, "max system bytes = %10lu\n",
(unsigned long)mgi.max_total_mem);
#endif
#if HAVE_MMAP
fprintf(stderr, "max mmap regions = %10u\n", (unsigned int)mgi.max_n_mmaps);
fprintf(stderr, "max mmap bytes = %10lu\n",
(unsigned long)mgi.max_mmapped_mem);
#endif
#if defined(THREAD_STATS) && THREAD_STATS
fprintf(stderr, "heaps created = %10d\n", mgi.stat_n_heaps);
fprintf(stderr, "locked directly = %10ld\n", stat_lock_direct);
fprintf(stderr, "locked in loop = %10ld\n", stat_lock_loop);
fprintf(stderr, "locked waiting = %10ld\n", stat_lock_wait);
fprintf(stderr, "locked total = %10ld\n",
stat_lock_direct + stat_lock_loop + stat_lock_wait);
#endif
#ifdef _LIBC
((_IO_FILE *) stderr)->_flags2 |= old_flags2;
_IO_funlockfile (stderr);
#endif
}
#ifdef _LIBC
weak_alias (__malloc_stats, malloc_stats)
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,300 +0,0 @@
/* Prototypes and definition for malloc implementation.
Copyright (C) 1996,97,99,2000,2002,2003,2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _MALLOC_H
#define _MALLOC_H 1
/* add the opal config header file for the OPAL_DECLSPEC */
#include "opal_config.h"
#ifdef _LIBC
#include <features.h>
#endif
/*
$Id: malloc.h,v 1.7 2004/08/08 12:34:57 wg Exp $
`ptmalloc2', a malloc implementation for multiple threads without
lock contention, by Wolfram Gloger <wg@malloc.de>.
VERSION 2.7.0
This work is mainly derived from malloc-2.7.0 by Doug Lea
<dl@cs.oswego.edu>, which is available from:
ftp://gee.cs.oswego.edu/pub/misc/malloc.c
This trimmed-down header file only provides function prototypes and
the exported data structures. For more detailed function
descriptions and compile-time options, see the source file
`malloc.c'.
*/
#if defined(__STDC__) || defined (__cplusplus)
# include <stddef.h>
# define __malloc_ptr_t void *
#else
# undef size_t
# define size_t unsigned int
# undef ptrdiff_t
# define ptrdiff_t int
# define __malloc_ptr_t char *
#endif
#ifdef _LIBC
/* Used by GNU libc internals. */
# define __malloc_size_t size_t
# define __malloc_ptrdiff_t ptrdiff_t
#elif !defined __attribute_malloc__
# define __attribute_malloc__
#endif
#ifdef __GNUC__
/* GCC can always grok prototypes. For C++ programs we add throw()
to help it optimize the function calls. But this works only with
gcc 2.8.x and egcs. */
# if defined __cplusplus && (__GNUC__ >= 3 || __GNUC_MINOR__ >= 8)
# define __THROW throw ()
# else
#ifdef __THROW
# undef __THROW
#endif
# define __THROW
# endif
# define __MALLOC_P(args) args __THROW
/* This macro will be used for functions which might take C++ callback
functions. */
# define __MALLOC_PMT(args) args
#else /* Not GCC. */
# define __THROW
# if (defined __STDC__ && __STDC__) || defined __cplusplus
# define __MALLOC_P(args) args
# define __MALLOC_PMT(args) args
# ifndef __const
# define __const const
# endif
# else /* Not ANSI C or C++. */
# define __MALLOC_P(args) () /* No prototypes. */
# define __MALLOC_PMT(args) ()
# ifndef __const
# define __const
# endif
# endif /* ANSI C or C++. */
#endif /* GCC. */
#ifndef NULL
# ifdef __cplusplus
# define NULL 0
# else
# define NULL ((__malloc_ptr_t) 0)
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Nonzero if the malloc is already initialized. */
#ifdef _LIBC
/* In the GNU libc we rename the global variable
`__malloc_initialized' to `__libc_malloc_initialized'. */
# define __malloc_initialized __libc_malloc_initialized
#endif
extern int __malloc_initialized;
/* Allocate SIZE bytes of memory. */
OPAL_DECLSPEC extern __malloc_ptr_t malloc __MALLOC_P ((size_t __size)) __attribute_malloc__;
/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
OPAL_DECLSPEC extern __malloc_ptr_t calloc __MALLOC_P ((size_t __nmemb, size_t __size))
__attribute_malloc__;
/* Re-allocate the previously allocated block in __ptr, making the new
block SIZE bytes long. */
OPAL_DECLSPEC extern __malloc_ptr_t realloc __MALLOC_P ((__malloc_ptr_t __ptr,
size_t __size))
__attribute_malloc__;
/* Free a block allocated by `malloc', `realloc' or `calloc'. */
OPAL_DECLSPEC extern void free __MALLOC_P ((__malloc_ptr_t __ptr));
/* Free a block allocated by `calloc'. */
OPAL_DECLSPEC extern void cfree __MALLOC_P ((__malloc_ptr_t __ptr));
/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */
OPAL_DECLSPEC extern __malloc_ptr_t memalign __MALLOC_P ((size_t __alignment, size_t __size));
/* Allocate SIZE bytes on a page boundary. */
OPAL_DECLSPEC extern __malloc_ptr_t valloc __MALLOC_P ((size_t __size)) __attribute_malloc__;
/* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up
__size to nearest pagesize. */
OPAL_DECLSPEC extern __malloc_ptr_t pvalloc __MALLOC_P ((size_t __size))
__attribute_malloc__;
/* Underlying allocation function; successive calls should return
contiguous pieces of memory. */
OPAL_DECLSPEC extern __malloc_ptr_t (*__morecore) __MALLOC_PMT ((ptrdiff_t __size));
/* Default value of `__morecore'. */
OPAL_DECLSPEC extern __malloc_ptr_t __default_morecore __MALLOC_P ((ptrdiff_t __size))
__attribute_malloc__;
/* SVID2/XPG mallinfo structure */
struct mallinfo {
int arena; /* non-mmapped space allocated from system */
int ordblks; /* number of free chunks */
int smblks; /* number of fastbin blocks */
int hblks; /* number of mmapped regions */
int hblkhd; /* space in mmapped regions */
int usmblks; /* maximum total allocated space */
int fsmblks; /* space available in freed fastbin blocks */
int uordblks; /* total allocated space */
int fordblks; /* total free space */
int keepcost; /* top-most, releasable (via malloc_trim) space */
};
/* Returns a copy of the updated current mallinfo. */
OPAL_DECLSPEC extern struct mallinfo mallinfo __MALLOC_P ((void));
/* SVID2/XPG mallopt options */
#ifndef M_MXFAST
# define M_MXFAST 1 /* maximum request size for "fastbins" */
#endif
#ifndef M_NLBLKS
# define M_NLBLKS 2 /* UNUSED in this malloc */
#endif
#ifndef M_GRAIN
# define M_GRAIN 3 /* UNUSED in this malloc */
#endif
#ifndef M_KEEP
# define M_KEEP 4 /* UNUSED in this malloc */
#endif
/* mallopt options that actually do something */
#define M_TRIM_THRESHOLD -1
#define M_TOP_PAD -2
#define M_MMAP_THRESHOLD -3
#define M_MMAP_MAX -4
#define M_CHECK_ACTION -5
/* General SVID/XPG interface to tunable parameters. */
OPAL_DECLSPEC extern int mallopt __MALLOC_P ((int __param, int __val));
/* Release all but __pad bytes of freed top-most memory back to the
system. Return 1 if successful, else 0. */
OPAL_DECLSPEC extern int malloc_trim __MALLOC_P ((size_t __pad));
/* Report the number of usable allocated bytes associated with allocated
chunk __ptr. */
OPAL_DECLSPEC extern size_t malloc_usable_size __MALLOC_P ((__malloc_ptr_t __ptr));
/* Prints brief summary statistics on stderr. */
OPAL_DECLSPEC extern void malloc_stats __MALLOC_P ((void));
/* Record the state of all malloc variables in an opaque data structure. */
OPAL_DECLSPEC extern __malloc_ptr_t malloc_get_state __MALLOC_P ((void));
/* Restore the state of all malloc variables from data obtained with
malloc_get_state(). */
OPAL_DECLSPEC extern int malloc_set_state __MALLOC_P ((__malloc_ptr_t __ptr));
/* Called once when malloc is initialized; redefining this variable in
the application provides the preferred way to set up the hook
pointers. */
OPAL_DECLSPEC extern void (*__malloc_initialize_hook) __MALLOC_PMT ((void));
/* Hooks for debugging and user-defined versions. */
OPAL_DECLSPEC extern void (*__free_hook) __MALLOC_PMT ((__malloc_ptr_t __ptr,
__const __malloc_ptr_t));
OPAL_DECLSPEC extern __malloc_ptr_t (*__malloc_hook) __MALLOC_PMT ((size_t __size,
__const __malloc_ptr_t));
OPAL_DECLSPEC extern __malloc_ptr_t (*__realloc_hook) __MALLOC_PMT ((__malloc_ptr_t __ptr,
size_t __size,
__const __malloc_ptr_t));
OPAL_DECLSPEC extern __malloc_ptr_t (*__memalign_hook) __MALLOC_PMT ((size_t __alignment,
size_t __size,
__const __malloc_ptr_t));
OPAL_DECLSPEC extern void (*__after_morecore_hook) __MALLOC_PMT ((void));
/* Activate a standard set of debugging hooks. */
OPAL_DECLSPEC extern void __malloc_check_init __MALLOC_P ((void));
/* Internal routines, operating on "arenas". */
struct malloc_state;
typedef struct malloc_state *mstate;
OPAL_DECLSPEC extern mstate _int_new_arena __MALLOC_P ((size_t __ini_size));
OPAL_DECLSPEC extern __malloc_ptr_t _int_malloc __MALLOC_P ((mstate __m, size_t __size));
OPAL_DECLSPEC extern void _int_free __MALLOC_P ((mstate __m, __malloc_ptr_t __ptr));
OPAL_DECLSPEC extern __malloc_ptr_t _int_realloc __MALLOC_P ((mstate __m,
__malloc_ptr_t __ptr,
size_t __size));
OPAL_DECLSPEC extern __malloc_ptr_t _int_memalign __MALLOC_P ((mstate __m, size_t __alignment,
size_t __size));
/* Return arena number __n, or 0 if out of bounds. Arena 0 is the
main arena. */
OPAL_DECLSPEC extern mstate _int_get_arena __MALLOC_P ((int __n));
/* Implementation-specific mallinfo. More detailed than mallinfo, and
also works for size_t wider than int. */
struct malloc_arena_info {
int nfastblocks; /* number of freed "fastchunks" */
int nbinblocks; /* number of available chunks in bins */
size_t fastavail; /* total space in freed "fastchunks" */
size_t binavail; /* total space in binned chunks */
size_t top_size; /* size of top chunk */
size_t system_mem; /* bytes allocated from system in this arena */
size_t max_system_mem; /* max. bytes allocated from system */
/* Statistics for locking. Only kept if THREAD_STATS is defined
at compile time. */
long stat_lock_direct, stat_lock_loop, stat_lock_wait;
};
struct malloc_global_info {
int n_mmaps; /* number of mmap'ed chunks */
int max_n_mmaps; /* max. number of mmap'ed chunks reached */
size_t mmapped_mem; /* total bytes allocated in mmap'ed chunks */
size_t max_mmapped_mem; /* max. bytes allocated in mmap'ed chunks */
size_t max_total_mem; /* only kept for NO_THREADS */
int stat_n_heaps; /* only kept if THREAD_STATS is defined */
};
OPAL_DECLSPEC extern void _int_get_arena_info __MALLOC_P ((mstate __m,
struct malloc_arena_info *__ma));
OPAL_DECLSPEC extern void _int_get_global_info __MALLOC_P ((struct malloc_global_info *__m));
OPAL_DECLSPEC extern int posix_memalign (void **memptr, size_t alignment, size_t size);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* malloc.h */

Просмотреть файл

@ -1,88 +0,0 @@
/*
* Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OPAL_MEMORY_LINUX_H
#define OPAL_MEMORY_LINUX_H
#include "opal_config.h"
#include "opal/mca/memory/memory.h"
BEGIN_C_DECLS
/* Component structure */
typedef struct opal_memory_linux_component_t {
opal_memory_base_component_2_0_0_t super;
/* Component data */
int verbose_level;
int enable_ummunotify;
int enable_ptmalloc2;
#if MEMORY_LINUX_UMMUNOTIFY
/* Ummunotify-specific data */
int ummunotify_fd;
#endif
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
int use_memalign;
size_t memalign_threshold;
#endif
#if MEMORY_LINUX_PTMALLOC2
/* Ptmalloc2-specific data. Note that these variables are all marked as volatile.
* This is needed because of what may be a buggy optimization in the GCC 4.9.2
* compilers and later. These variables are used in different code paths which the
* compiler is not aware of.
* Extra details located at these URLs:
* Open MPI User List: http://www.open-mpi.org/community/lists/users/2015/06/27039.php
* Bug Discussion: https://github.com/open-mpi/ompi/pull/625
* GCC Discussion: https://gcc.gnu.org/ml/gcc-bugs/2015-06/msg00757.html
*/
volatile bool free_invoked;
volatile bool malloc_invoked;
volatile bool realloc_invoked;
volatile bool memalign_invoked;
volatile bool munmap_invoked;
#endif
} opal_memory_linux_component_t;
/* memory_linux_component.c */
extern opal_memory_linux_component_t mca_memory_linux_component;
#if MEMORY_LINUX_UMMUNOTIFY
/* memory_linux_ummunotify.c */
int opal_memory_linux_ummunotify_open(void);
int opal_memory_linux_ummunotify_close(void);
#endif /* MEMORY_LINUX_UMMUNOTIFY */
#if MEMORY_LINUX_PTMALLOC2
/* memory_linux_ptmalloc2.c */
int opal_memory_linux_ptmalloc2_open(void);
int opal_memory_linux_ptmalloc2_close(void);
/* memory_linux_munmap.c */
OPAL_DECLSPEC int opal_memory_linux_free_ptmalloc2_munmap(void *start, size_t length, int from_alloc);
OPAL_DECLSPEC int munmap(void* addr, size_t len);
#endif /* !MEMORY_LINUX_PTMALLOC2 */
#if MEMORY_LINUX_HAVE_MALLOC_HOOK_SUPPORT
OPAL_DECLSPEC void opal_memory_linux_malloc_init_hook(void);
#endif /* MEMORY_LINUX_HAVE_MALLOC_HOOK_SUPPORT */
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
OPAL_DECLSPEC void opal_memory_linux_malloc_set_alignment(int use_memalign, size_t memalign_threshold);
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */
END_C_DECLS
#endif

Просмотреть файл

@ -1,386 +0,0 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2013-2015 Los Alamos National Security, LLC. All rights
* reserved.
* Copyright (c) 2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/* This component basically fronts two different memory management
schemes: the Linux "ummunotify" kernel module and hooking in a
substitute ptmalloc2 allocator. Both of these mechanisms are
unified under a single component because the "memory" framework
both only allows one component to be selected, and that one
component must be compile-time linked into libopen-pal. Hence, if
we want to try to use either one of these mechanisms, we have to
have them both in a single component.
When using ptmalloc2, the goal of this component is to wholly
replace the underlying allocator with our internal ptmalloc2
allocator. See the file README-open-mpi.txt for details of how it
works.
When using ummunotify, we can probe to find out when the MMU map
has been changed (i.e., memory has been released back to the OS). */
#include "opal_config.h"
#if HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "opal/constants.h"
#include "opal/mca/base/mca_base_var.h"
#include "opal/mca/memory/memory.h"
#include "opal/mca/memory/base/empty.h"
#include "opal/memoryhooks/memory.h"
#include "opal/util/output.h"
#include "opal/util/show_help.h"
#include "opal/mca/memory/linux/memory_linux.h"
#undef opal_memory_changed
#include "opal/mca/memory/linux/public.h"
static int linux_open(void);
static int linux_close(void);
static int linux_register(void);
#if MEMORY_LINUX_UMMUNOTIFY
static bool ummunotify_opened = false;
#endif
#if MEMORY_LINUX_PTMALLOC2
static bool ptmalloc2_opened = false;
#endif
bool opal_memory_linux_disable = false;
opal_memory_linux_component_t mca_memory_linux_component = {
/* First, the opal_memory_base_component_2_0_0_t */
{
/* First, the mca_component_t struct containing meta
information about the component itself */
.memoryc_version = {
OPAL_MEMORY_BASE_VERSION_2_0_0,
/* Component name and version */
.mca_component_name = "linux",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
/* Component open and close functions */
.mca_open_component = linux_open,
.mca_close_component = linux_close,
.mca_register_component_params = linux_register,
},
.memoryc_data = {
/* The component is checkpoint ready */
MCA_BASE_METADATA_PARAM_CHECKPOINT
},
/* Memory framework functions. These function pointer values
are replaced by memory_linux_ummunotify.c at run time if we
end up using ummunotify support. */
.memoryc_register = opal_memory_base_component_register_empty,
.memoryc_deregister = opal_memory_base_component_deregister_empty,
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
.memoryc_set_alignment = opal_memory_linux_malloc_set_alignment,
#else
.memoryc_set_alignment = opal_memory_base_component_set_alignment_empty,
#endif
},
/* Component-specific data, filled in later (compiler will 0/NULL
it out) */
};
static bool ptmalloc2_available = MEMORY_LINUX_PTMALLOC2;
static bool ummunotify_available = MEMORY_LINUX_UMMUNOTIFY;
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
static void *(*prev_malloc_hook)(size_t, const void *);
/* This is a memory allocator hook. The purpose of this is to make
* every malloc aligned.
* There two basic cases here:
*
* 1. Memory manager for Open MPI is enabled. Then memalign below will
* be overridden by __memalign_hook which is set to
* opal_memory_linux_memalign_hook. Thus, _malloc_hook is going to
* use opal_memory_linux_memalign_hook.
*
* 2. No memory manager support. The memalign below is just regular glibc
* memalign which will be called through __malloc_hook instead of malloc.
*/
static void *_opal_memory_linux_malloc_align_hook(size_t sz, const void* caller);
static mca_base_var_enum_value_t align_values[] = {
{-1, "disabled"},
{0, "0"},
{32, "32"},
{64, "64"},
{0, NULL}
};
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */
/*
* Register MCA params
*/
static int linux_register(void)
{
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
mca_base_var_enum_t *new_enum;
#endif
int ret;
/* Information only */
ret = mca_base_component_var_register (&mca_memory_linux_component.super.memoryc_version,
"ptmalloc2_available",
"Whether ptmalloc2 support is included in Open MPI or not (1 = yes, 0 = no)",
MCA_BASE_VAR_TYPE_BOOL, NULL, 0, 0,
OPAL_INFO_LVL_3,
MCA_BASE_VAR_SCOPE_CONSTANT,
&ptmalloc2_available);
if (0 > ret) {
return ret;
}
ret = mca_base_component_var_register (&mca_memory_linux_component.super.memoryc_version,
"ummunotify_available",
"Whether ummunotify support is included in Open MPI or not (1 = yes, 0 = no)",
MCA_BASE_VAR_TYPE_BOOL, NULL, 0, 0,
OPAL_INFO_LVL_3,
MCA_BASE_VAR_SCOPE_CONSTANT,
&ummunotify_available);
if (0 > ret) {
return ret;
}
/* Allow user to manually enable/disable */
mca_memory_linux_component.enable_ptmalloc2 = -1;
ret = mca_base_component_var_register (&mca_memory_linux_component.super.memoryc_version,
"ptmalloc2_enable",
"Whether to enable ptmalloc2 support or not (negative = try to enable, but continue even if support is not available, 0 = do not enable support, positive = try to enable and fail if support is not available)",
MCA_BASE_VAR_TYPE_INT, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE,
OPAL_INFO_LVL_3,
MCA_BASE_VAR_SCOPE_ALL_EQ,
&mca_memory_linux_component.enable_ptmalloc2);
if (0 > ret) {
return ret;
}
mca_memory_linux_component.enable_ummunotify = -1;
ret = mca_base_component_var_register (&mca_memory_linux_component.super.memoryc_version,
"ummunotify_enable",
"Whether to enable ummunotify support or not (negative = try to enable, but continue even if support is not available, 0 = do not enable support, positive = try to enable and fail if support is not available)",
MCA_BASE_VAR_TYPE_INT, NULL, 0, MCA_BASE_VAR_FLAG_SETTABLE,
OPAL_INFO_LVL_3,
MCA_BASE_VAR_SCOPE_ALL_EQ,
&mca_memory_linux_component.enable_ummunotify);
if (0 > ret) {
return ret;
}
opal_memory_linux_disable = false;
(void) mca_base_component_var_register (&mca_memory_linux_component.super.memoryc_version,
"disable",
"If this MCA parameter is set to 1 **VIA ENVIRONMENT VARIABLE ONLY*** (this MCA parameter *CANNOT* be set in a file or on the mpirun command line!), this component will be disabled and will not attempt to use either ummunotify or memory hook support",
MCA_BASE_VAR_TYPE_BOOL, NULL, 0, MCA_BASE_VAR_FLAG_ENVIRONMENT_ONLY,
OPAL_INFO_LVL_3,
MCA_BASE_VAR_SCOPE_READONLY,
&opal_memory_linux_disable);
if (0 > ret) {
return ret;
}
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
(void)mca_base_var_enum_create("memory_linux_memalign", align_values, &new_enum);
mca_memory_linux_component.use_memalign = -1;
ret = mca_base_component_var_register(&mca_memory_linux_component.super.memoryc_version,
"memalign",
"[64 | 32 | 0] - Enable memory alignment for all malloc calls.",
MCA_BASE_VAR_TYPE_INT,
new_enum,
0,
0,
OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_READONLY,
&mca_memory_linux_component.use_memalign);
OBJ_RELEASE(new_enum);
if (0 > ret) {
return ret;
}
mca_memory_linux_component.memalign_threshold = 12288;
ret = mca_base_component_var_register(&mca_memory_linux_component.super.memoryc_version,
"memalign_threshold",
"Allocating memory more than memory_linux_memalign_threshold"
"bytes will automatically be aligned to the value of memory_linux_memalign bytes."
"(default: 12288)",
MCA_BASE_VAR_TYPE_SIZE_T,
NULL,
0,
0,
OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_READONLY,
&mca_memory_linux_component.memalign_threshold);
if (0 > ret) {
return ret;
}
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */
return (0 > ret) ? ret : OPAL_SUCCESS;
}
static int linux_open(void)
{
const int *verbose = NULL;
int i;
i = mca_base_var_find("opal", "memory", NULL, "base_verbose");
mca_base_var_get_value(i, &verbose, NULL, NULL);
mca_memory_linux_component.verbose_level = verbose ? verbose[0] : 0;
/* Try initializing ummunotify first; if that fails, try
ptmalloc2. */
#if MEMORY_LINUX_UMMUNOTIFY
if (mca_memory_linux_component.enable_ummunotify) {
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: attempting to initialize ummunotify support");
}
if (OPAL_SUCCESS == opal_memory_linux_ummunotify_open()) {
ummunotify_opened = true;
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: ummunotify successfully initialized; we'll use that");
}
goto done;
}
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: ummunotify failed to initialize");
}
}
#endif
#if MEMORY_LINUX_PTMALLOC2
if (mca_memory_linux_component.enable_ptmalloc2) {
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: attempting to initialize ptmalloc2 support");
}
if (OPAL_SUCCESS == opal_memory_linux_ptmalloc2_open()) {
ptmalloc2_opened = true;
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: ptmalloc2 successfully initialized; we'll use that");
}
goto done;
}
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: ptmalloc2 failed to initialize");
}
}
#endif
/* We can return OPAL_ERR_NOT_AVAILABLE if nothing is
available; that will make the MCA base silently disregard this
component. */
if (mca_memory_linux_component.verbose_level >= 10) {
opal_output(0, "memory:linux: no memory hooks available in this process");
}
return OPAL_ERR_NOT_AVAILABLE;
done:
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
/* save original call */
prev_malloc_hook = NULL;
if (mca_memory_linux_component.use_memalign > 0 &&
(opal_mem_hooks_support_level() &
(OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_CHUNK_SUPPORT)) != 0) {
prev_malloc_hook = __malloc_hook;
__malloc_hook = _opal_memory_linux_malloc_align_hook;
}
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */
return OPAL_SUCCESS;
}
static int linux_close(void)
{
int v = mca_memory_linux_component.verbose_level;
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
/* restore original call */
if (prev_malloc_hook) {
__malloc_hook = prev_malloc_hook;
prev_malloc_hook = NULL;
}
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */
#if MEMORY_LINUX_UMMUNOTIFY
if (ummunotify_opened) {
if (v >= 10) {
opal_output(0, "memory:linux: shutting down ummunotify support");
}
opal_memory_linux_ummunotify_close();
ummunotify_opened = false;
}
#endif
#if MEMORY_LINUX_PTMALLOC2
if (ptmalloc2_opened) {
if (v >= 10) {
opal_output(0, "memory:linux: shutting down ptmalloc2 support");
}
opal_memory_linux_ptmalloc2_close();
ptmalloc2_opened = false;
}
#endif
return OPAL_SUCCESS;
}
#if MEMORY_LINUX_MALLOC_ALIGN_ENABLED
void opal_memory_linux_malloc_set_alignment(int use_memalign, size_t memalign_threshold)
{
/* ignore cases when this capability is enabled explicitly using
* mca variables
*/
if ((NULL == prev_malloc_hook) && (-1 == mca_memory_linux_component.use_memalign)) {
if (use_memalign == 0 || use_memalign == 32 || use_memalign == 64) {
mca_memory_linux_component.use_memalign = use_memalign;
mca_memory_linux_component.memalign_threshold = memalign_threshold;
if ((opal_mem_hooks_support_level() &
(OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_CHUNK_SUPPORT)) != 0) {
prev_malloc_hook = __malloc_hook;
__malloc_hook = _opal_memory_linux_malloc_align_hook;
}
}
}
}
static void *_opal_memory_linux_malloc_align_hook(size_t sz, const void* caller)
{
if (sz < mca_memory_linux_component.memalign_threshold) {
return prev_malloc_hook(sz, caller);
} else {
return memalign(mca_memory_linux_component.use_memalign, sz);
}
}
#endif /* MEMORY_LINUX_MALLOC_ALIGN_ENABLED */

Просмотреть файл

@ -1,92 +0,0 @@
/*
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <sys/mman.h>
#if defined(HAVE___MUNMAP)
/* here so we only include others if we absolutely have to */
#elif defined(HAVE_SYSCALL)
#include <syscall.h>
#include <unistd.h>
#endif
#if defined(HAVE_DLSYM)
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <dlfcn.h>
#endif
#include "opal/memoryhooks/memory_internal.h"
#include "memory_linux.h"
/*
* munmap is always intercepted
*/
#if defined(HAVE___MUNMAP)
int __munmap(void* addr, size_t len);
#endif
/* intercept munmap, as the user can give back memory that way as well. */
OPAL_DECLSPEC int munmap(void* addr, size_t len)
{
return opal_memory_linux_free_ptmalloc2_munmap(addr, len, 0);
}
/* three ways to call munmap. Prefered is to just call syscall, so
that we can intercept both munmap and __munmap. If that isn't
possible, try calling __munmap from munmap and let __munmap go. If
that doesn't work, try dlsym */
int opal_memory_linux_free_ptmalloc2_munmap(void *start, size_t length,
int from_alloc)
{
#if !defined(HAVE___MUNMAP) && \
!(defined(HAVE_SYSCALL) && defined(__NR_munmap)) && defined(HAVE_DLSYM)
static int (*realmunmap)(void*, size_t);
#endif
mca_memory_linux_component.munmap_invoked = true;
opal_mem_hooks_release_hook(start, length, from_alloc);
#if defined(HAVE___MUNMAP)
return __munmap(start, length);
#elif defined(HAVE_SYSCALL) && defined(__NR_munmap)
return syscall(__NR_munmap, start, length);
#elif defined(HAVE_DLSYM)
if (NULL == realmunmap) {
union {
int (*munmap_fp)(void*, size_t);
void *munmap_p;
} tmp;
tmp.munmap_p = dlsym(RTLD_NEXT, "munmap");
realmunmap = tmp.munmap_fp;
}
return realmunmap(start, length);
#else
#error "Can not determine how to call munmap"
#endif
}

Просмотреть файл

@ -1,136 +0,0 @@
/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <sys/mman.h>
#include <stdlib.h>
#include <malloc.h>
#include "opal/constants.h"
#include "opal/util/output.h"
#include "opal/memoryhooks/memory.h"
#include "opal/memoryhooks/memory_internal.h"
#include "opal/mca/memory/linux/memory_linux.h"
/* Need to call a function in hooks.c to ensure that all those symbols
get pulled in at link time (e.g., when building libmpi.a, so that
those symbols end up in the final executable -- especially if we
use --disable-dlopen and therefore -Wl,--export-dynamic isn't used
when we build OMPI). */
extern void opal_memory_linux_hook_pull(bool *want_hooks);
/*
* Try to initialize ptmalloc2
*/
int opal_memory_linux_ptmalloc2_open(void)
{
int val = 0;
void *p;
bool want_hooks = true;
/* Call a [somewhat] dummy function in hooks.c. ***Do not remove
this call!*** See comment at the beginning of this file
explaining why it is here. It will also check to see if an
environment variable has been set to disable this component
(note that OPAL_ERR_NOT_AVAILABLE is a special return value
that will silently fail the open component call; all others
will issue an error). */
opal_memory_linux_hook_pull(&want_hooks);
if (!want_hooks) {
return OPAL_ERR_NOT_AVAILABLE;
}
/* We will also provide malloc/free support if we've been
activated. We don't exclusively rely on the
__malloc_initialize_hook() previously being called because it's
possible that our hook was called, but then someone else reset
the hooks to point to something else (i.e., before MPI_INIT).
So explicitly test here if our hooks are still in place. If
they are, then enable FREE|CHUNK_SUPPORT. If not, then don't
enable that support -- just leave it at MUNMAP_SUPPORT.
(Look in hooks.c for the __malloc_initialize_hook setup) */
/* Do a simple set of tests to see if our hooks are still the ones
installed. Explicitly reset the flags indicating that our
functions were invoked */
p = malloc(1024 * 1024 * 4);
if (NULL == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
p = realloc(p, 1024 * 1024 * 4 + 32);
if (NULL == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
free(p);
p = memalign(4, 1024 * 1024);
if (NULL == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
free(p);
#if HAVE_POSIX_MEMALIGN
/* Double check for posix_memalign, too */
if (mca_memory_linux_component.memalign_invoked) {
mca_memory_linux_component.memalign_invoked = false;
if (0 != posix_memalign(&p, sizeof(void*), 1024 * 1024)) {
return OPAL_ERR_IN_ERRNO;
}
free(p);
}
#endif
if (mca_memory_linux_component.malloc_invoked &&
mca_memory_linux_component.realloc_invoked &&
mca_memory_linux_component.memalign_invoked &&
mca_memory_linux_component.free_invoked) {
/* Happiness; our functions were invoked */
val |= OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_CHUNK_SUPPORT;
}
/* Check if our mmap layering is working */
p = mmap(NULL, 4096, PROT_READ, (MAP_ANONYMOUS | MAP_PRIVATE), -1, 0);
if (MAP_FAILED == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
munmap(p, 4096);
if (mca_memory_linux_component.munmap_invoked) {
val |= OPAL_MEMORY_MUNMAP_SUPPORT;
}
/* All done */
if (val > 0) {
opal_mem_hooks_set_support(val);
return OPAL_SUCCESS;
}
return OPAL_ERR_NOT_AVAILABLE;
}
int opal_memory_linux_ptmalloc2_close(void)
{
/* Nothing to do, really. This function exists just for
symmetry. */
return OPAL_SUCCESS;
}

Просмотреть файл

@ -1,235 +0,0 @@
/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/ummunotify.h>
#include "opal_stdint.h"
#include "opal/constants.h"
#include "opal/util/output.h"
#include "opal/util/show_help.h"
#include "opal/mca/memory/memory.h"
#include "opal/memoryhooks/memory.h"
#include "opal/memoryhooks/memory_internal.h"
#include "opal/mca/memory/linux/memory_linux.h"
#include "opal/mca/memory/linux/public.h"
#define DEV_UMMUNOTIFY "/dev/ummunotify"
/*
* Local functions
*/
static int ummunotify_process(void);
static int ummunotify_register(void *start, size_t len, uint64_t cookie);
static int ummunotify_deregister(void *start, size_t len, uint64_t cookie);
/*
* Local variables
*/
static bool initialized = false;
/*
* Global variables (these need to be global variables rather than in
* the component struct because they are accessed in the
* opal_memory_changed() macro defined in public.h, and we don't want
* to have to include the component structure definition in public.h).
*/
uint64_t opal_memory_linux_ummunotify_counter_last_value = 0;
volatile uint64_t *opal_memory_linux_ummunotify_counter =
&opal_memory_linux_ummunotify_counter_last_value;
int opal_memory_linux_ummunotify_open(void)
{
uint64_t *p;
/* Just to be safe... */
opal_memory_linux_ummunotify_counter_last_value = 0;
opal_memory_linux_ummunotify_counter =
&opal_memory_linux_ummunotify_counter_last_value;
/* Open the device. Try to give a meaningful error message if
we're unable to open it. */
mca_memory_linux_component.ummunotify_fd =
open(DEV_UMMUNOTIFY, O_RDONLY | O_NONBLOCK);
if (mca_memory_linux_component.ummunotify_fd < 0) {
char hostname[HOST_NAME_MAX];
gethostname(hostname, sizeof(hostname));
if (EACCES == errno) {
/* This will get a proper show_help when merged into the
linux component */
opal_show_help("help-opal-memory-linux.txt",
"ummunotify eaccess", true,
hostname, DEV_UMMUNOTIFY);
} else if (ENOENT != errno) {
/* Don't print an error if DEV_UMMUNOTIFY simply doesn't exist */
opal_show_help("help-opal-memory-linux.txt",
"ummunotify open error", true,
hostname, DEV_UMMUNOTIFY,
strerror(errno), errno);
}
return OPAL_ERR_NOT_SUPPORTED;
}
p = mmap(NULL, sizeof(*opal_memory_linux_ummunotify_counter),
PROT_READ, MAP_SHARED,
mca_memory_linux_component.ummunotify_fd, 0);
if (MAP_FAILED == opal_memory_linux_ummunotify_counter) {
close(mca_memory_linux_component.ummunotify_fd);
mca_memory_linux_component.ummunotify_fd = -1;
return OPAL_ERR_NOT_SUPPORTED;
}
opal_memory_linux_ummunotify_counter = p;
/* If everything went well, tell OMPI that we have full support
for the memory hooks and fill in the component function
pointers */
opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT |
OPAL_MEMORY_CHUNK_SUPPORT |
OPAL_MEMORY_MUNMAP_SUPPORT);
mca_memory_linux_component.super.memoryc_process = ummunotify_process;
mca_memory_linux_component.super.memoryc_register = ummunotify_register;
mca_memory_linux_component.super.memoryc_deregister = ummunotify_deregister;
initialized = true;
return OPAL_SUCCESS;
}
/*
* Called during opal_finalize (usually during MPI_FINALIZE) to tear
* down anything that can/should be torn down to disable this
* component. The application may continue for a while after
* MPI_FINALIZE, so we should do as much as possible to disable
* anything we enabled during ummunotify_open().
*/
int opal_memory_linux_ummunotify_close(void)
{
if (initialized && mca_memory_linux_component.ummunotify_fd >= 0) {
munmap((void*) opal_memory_linux_ummunotify_counter,
sizeof(*opal_memory_linux_ummunotify_counter));
close(mca_memory_linux_component.ummunotify_fd);
mca_memory_linux_component.ummunotify_fd = -1;
opal_memory_linux_ummunotify_counter =
&opal_memory_linux_ummunotify_counter_last_value;
initialized = false;
}
return OPAL_SUCCESS;
}
/*
* Called when opal_memory_changed() returns 1
*/
static int ummunotify_process(void)
{
int n;
unsigned int i;
struct ummunotify_event events[128];
/* Loop reading from the ummunot fd until there's nothing left to
read. If we get a LAST event, re-record the counter. */
while (initialized) {
n = read(mca_memory_linux_component.ummunotify_fd,
&events, sizeof(events));
if (n <= 0) {
return (EAGAIN == errno) ? OPAL_SUCCESS : OPAL_ERR_IN_ERRNO;
}
for (i = 0; i < n / sizeof(events[0]); ++i) {
switch (events[i].type) {
case UMMUNOTIFY_EVENT_TYPE_INVAL:
/* 0 => this callback did not come from malloc */
OPAL_OUTPUT((-1, "ummunot: invalidate start %p, end %p",
(void*) events[i].hint_start,
(void*) events[i].hint_end));
opal_mem_hooks_release_hook((void *) (uintptr_t) events[i].hint_start,
events[i].hint_end - events[i].hint_start,
0);
break;
case UMMUNOTIFY_EVENT_TYPE_LAST:
opal_memory_linux_ummunotify_counter_last_value =
events[i].user_cookie_counter;
/* Are there more events to read? */
if (opal_memory_linux_ummunotify_counter_last_value ==
*opal_memory_linux_ummunotify_counter) {
OPAL_OUTPUT((-1, "ummunot: LAST; done"));
return OPAL_SUCCESS;
}
OPAL_OUTPUT((-1, "ummunot: LAST; but looping around"));
break;
}
}
}
/* Will only get here if this component has not been
initialized */
return OPAL_SUCCESS;
}
static int ummunotify_register(void *start, size_t len, uint64_t cookie)
{
struct ummunotify_register_ioctl r;
r.reserved = 0;
r.start = (unsigned long) start;
r.end = (unsigned long) start + len;
r.user_cookie = cookie;
OPAL_OUTPUT((-1, "ummunot: register %p - %p",
start, ((char*) start) + len));
if (initialized && ioctl(mca_memory_linux_component.ummunotify_fd,
UMMUNOTIFY_REGISTER_REGION, &r)) {
OPAL_OUTPUT((-1, "Error in ioctl register!"));
return OPAL_ERR_IN_ERRNO;
}
return OPAL_SUCCESS;
}
static int ummunotify_deregister(void *start, size_t len, uint64_t cookie)
{
OPAL_OUTPUT((-1, "ummunot: deregister %p - %p",
start, ((char*) start) + len));
if (initialized && ioctl(mca_memory_linux_component.ummunotify_fd,
UMMUNOTIFY_UNREGISTER_REGION, &cookie)) {
OPAL_OUTPUT((-1, "Error in ioctl unregister!"));
return OPAL_ERR_IN_ERRNO;
}
return OPAL_SUCCESS;
}

Просмотреть файл

@ -1,7 +0,0 @@
#
# owner/status file
# owner: institution that is responsible for this package
# status: e.g. active, maintenance, unmaintained
#
owner: MELLANOX,CISCO
status: maintenance

Просмотреть файл

@ -1,24 +0,0 @@
/*
* Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OPAL_MEMORY_LINUX_PUBLIC_H
#define OPAL_MEMORY_LINUX_PUBLIC_H
#include "opal_config.h"
#include <sys/types.h>
OPAL_DECLSPEC extern volatile uint64_t *opal_memory_linux_ummunotify_counter;
OPAL_DECLSPEC extern uint64_t opal_memory_linux_ummunotify_counter_last_value;
#define opal_memory_changed() \
(opal_memory_linux_ummunotify_counter_last_value != \
*opal_memory_linux_ummunotify_counter)
#endif

Просмотреть файл

@ -1,52 +0,0 @@
/*
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/* Name-shift all the internal ptmalloc22 symbols to guarantee to not
conflict / confuse / override the internal glibc symbols. */
#define __default_morecore opal_memory_ptmalloc2_default_morecore
#define _int_malloc opal_memory_ptmalloc2_int_malloc
#define _int_free opal_memory_ptmalloc2_int_free
#define _int_realloc opal_memory_ptmalloc2_int_realloc
#define _int_memalign opal_memory_ptmalloc2_int_memalign
#define _int_valloc opal_memory_ptmalloc2_int_valloc
#define _int_pvalloc opal_memory_ptmalloc2_int_pvalloc
#define _int_icalloc opal_memory_ptmalloc2_int_icalloc
#define _int_icomalloc opal_memory_ptmalloc2_int_icomalloc
#define mTRIm opal_memory_ptmalloc2_mTRIm
#define mUSABLe opal_memory_ptmalloc2_mUSABLe
#define mALLOPt opal_memory_ptmalloc2_mALLOPt
#define mem2mem_check opal_memory_ptmalloc2_mem2mem_check
#define top_check opal_memory_ptmalloc2_top_check
#define munmap_chunk opal_memory_ptmalloc2_munmap_chunk
#define mremap_chunk opal_memory_ptmalloc2_mremap_chunk
#define malloc_check opal_memory_ptmalloc2_malloc_check
#define free_check opal_memory_ptmalloc2_free_check
#define realloc_check opal_memory_ptmalloc2_realloc_check
#define memalign_check opal_memory_ptmalloc2_memalign_check
#define malloc_starter opal_memory_ptmalloc2_malloc_starter
#define memalign_starter opal_memory_ptmalloc2_memalign_starter
#define free_starter opal_memory_ptmalloc2_free_starter
#define malloc_atfork opal_memory_ptmalloc2_malloc_atfork
#define free_atfork opal_memory_ptmalloc2_free_atfork
#define _int_get_arena opal_memory_ptmalloc2_int_get_arena
#define _int_get_arena_info opal_memory_ptmalloc2_int_get_arena_info
#define _int_get_global_info opal_memory_ptmalloc2_int_get_global_info
#define _int_new_arena opal_memory_ptmalloc2_int_new_arena
#define __malloc_check_init opal_memory_ptmalloc2_malloc_check_init
#define malloc_stats opal_memory_ptmalloc2_malloc_stats
#define posix_memalign opal_memory_ptmalloc2_posix_memalign

Просмотреть файл

@ -1 +0,0 @@
/* Empty placeholder */

Просмотреть файл

@ -1,68 +0,0 @@
/* Basic platform-independent macro definitions for mutexes,
thread-specific data and parameters for malloc.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _GENERIC_MALLOC_MACHINE_H
#define _GENERIC_MALLOC_MACHINE_H
#include <atomic.h>
#ifndef mutex_init /* No threads, provide dummy macros */
# define NO_THREADS
/* The mutex functions used to do absolutely nothing, i.e. lock,
trylock and unlock would always just return 0. However, even
without any concurrently active threads, a mutex can be used
legitimately as an `in use' flag. To make the code that is
protected by a mutex async-signal safe, these macros would have to
be based on atomic test-and-set operations, for example. */
typedef int mutex_t;
# define mutex_init(m) (*(m) = 0)
# define mutex_lock(m) ((*(m) = 1), 0)
# define mutex_trylock(m) (*(m) ? 1 : ((*(m) = 1), 0))
# define mutex_unlock(m) (*(m) = 0)
typedef void *tsd_key_t;
# define tsd_key_create(key, destr) do {} while(0)
# define tsd_setspecific(key, data) ((key) = (data))
# define tsd_getspecific(key, vptr) (vptr = (key))
# define thread_atfork(prepare, parent, child) do {} while(0)
#endif /* !defined mutex_init */
#ifndef atomic_full_barrier
# define atomic_full_barrier() __asm ("" ::: "memory")
#endif
#ifndef atomic_read_barrier
# define atomic_read_barrier() atomic_full_barrier ()
#endif
#ifndef atomic_write_barrier
# define atomic_write_barrier() atomic_full_barrier ()
#endif
#ifndef DEFAULT_TOP_PAD
# define DEFAULT_TOP_PAD 131072
#endif
#endif /* !defined(_GENERIC_MALLOC_MACHINE_H) */

Просмотреть файл

@ -1,48 +0,0 @@
/*
* $Id:$
* Generic version: no threads.
* by Wolfram Gloger 2004
*/
#include <stdio.h>
struct thread_st {
char *sp; /* stack pointer, can be 0 */
void (*func)(struct thread_st* st); /* must be set by user */
int id;
int flags;
struct user_data u;
};
static void
thread_init(void)
{
printf("No threads.\n");
}
/* Create a thread. */
static int
thread_create(struct thread_st *st)
{
st->flags = 0;
st->id = 1;
st->func(st);
return 0;
}
/* Wait for one of several subthreads to finish. */
static void
wait_for_thread(struct thread_st st[], int n_thr,
int (*end_thr)(struct thread_st*))
{
int i;
for(i=0; i<n_thr; i++)
if(end_thr)
end_thr(&st[i]);
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,132 +0,0 @@
/* Basic platform-independent macro definitions for mutexes,
thread-specific data and parameters for malloc.
Posix threads (pthreads) version.
Copyright (C) 2004 Wolfram Gloger <wg@malloc.de>.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that (i) the above copyright notices and this permission
notice appear in all copies of the software and related documentation,
and (ii) the name of Wolfram Gloger may not be used in any advertising
or publicity relating to the software.
THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _PTHREAD_MALLOC_MACHINE_H
#define _PTHREAD_MALLOC_MACHINE_H
#include <pthread.h>
#undef thread_atfork_static
/* Use fast inline spinlocks with gcc. */
#if (defined __i386__ || defined __x86_64__) && defined __GNUC__ && \
!defined USE_NO_SPINLOCKS
#include <time.h>
#include <sched.h>
typedef struct {
volatile unsigned int lock;
int pad0_;
} mutex_t;
#define MUTEX_INITIALIZER { 0 }
#define mutex_init(m) ((m)->lock = 0)
static inline int mutex_lock(mutex_t *m) {
int cnt = 0, r;
struct timespec tm;
for(;;) {
__asm__ __volatile__
("xchgl %0, %1"
: "=r"(r), "=m"(m->lock)
: "0"(1), "m"(m->lock)
: "memory");
if(!r)
return 0;
if(cnt < 50) {
sched_yield();
cnt++;
} else {
tm.tv_sec = 0;
tm.tv_nsec = 2000001;
nanosleep(&tm, NULL);
cnt = 0;
}
}
}
static inline int mutex_trylock(mutex_t *m) {
int r;
__asm__ __volatile__
("xchgl %0, %1"
: "=r"(r), "=m"(m->lock)
: "0"(1), "m"(m->lock)
: "memory");
return r;
}
static inline int mutex_unlock(mutex_t *m) {
m->lock = 0;
__asm __volatile__ ("" : : : "memory");
return 0;
}
#else
/* Normal pthread mutex. */
typedef pthread_mutex_t mutex_t;
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#define mutex_init(m) pthread_mutex_init(m, NULL)
#define mutex_lock(m) pthread_mutex_lock(m)
#define mutex_trylock(m) pthread_mutex_trylock(m)
#define mutex_unlock(m) pthread_mutex_unlock(m)
#endif /* (__i386__ || __x86_64__) && __GNUC__ && !USE_NO_SPINLOCKS */
/* thread specific data */
#if defined(__sgi) || defined(USE_TSD_DATA_HACK)
/* Hack for thread-specific data, e.g. on Irix 6.x. We can't use
pthread_setspecific because that function calls malloc() itself.
The hack only works when pthread_t can be converted to an integral
type. */
typedef void *tsd_key_t[256];
#define tsd_key_create(key, destr) do { \
int i; \
for(i=0; i<256; i++) (*key)[i] = 0; \
} while(0)
#define tsd_setspecific(key, data) \
(key[(unsigned)pthread_self() % 256] = (data))
#define tsd_getspecific(key, vptr) \
(vptr = key[(unsigned)pthread_self() % 256])
#else
typedef pthread_key_t tsd_key_t;
#define tsd_key_create(key, destr) pthread_key_create(key, destr)
#define tsd_setspecific(key, data) pthread_setspecific(key, data)
#define tsd_getspecific(key, vptr) (vptr = pthread_getspecific(key))
#endif
/* at fork */
#define thread_atfork(prepare, parent, child) \
pthread_atfork(prepare, parent, child)
#include <sysdeps/generic/malloc-machine.h>
#endif /* !defined(_MALLOC_MACHINE_H) */

Просмотреть файл

@ -1,111 +0,0 @@
/*
* $Id: thread-st.h$
* pthread version
* by Wolfram Gloger 2004
*/
#include <pthread.h>
#include <stdio.h>
pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;
#ifndef USE_PTHREADS_STACKS
#define USE_PTHREADS_STACKS 0
#endif
#ifndef STACKSIZE
#define STACKSIZE 32768
#endif
struct thread_st {
char *sp; /* stack pointer, can be 0 */
void (*func)(struct thread_st* st); /* must be set by user */
pthread_t id;
int flags;
struct user_data u;
};
static void
thread_init(void)
{
printf("Using posix threads.\n");
pthread_cond_init(&finish_cond, NULL);
pthread_mutex_init(&finish_mutex, NULL);
}
static void *
thread_wrapper(void *ptr)
{
struct thread_st *st = (struct thread_st*)ptr;
/*printf("begin %p\n", st->sp);*/
st->func(st);
pthread_mutex_lock(&finish_mutex);
st->flags = 1;
pthread_mutex_unlock(&finish_mutex);
pthread_cond_signal(&finish_cond);
/*printf("end %p\n", st->sp);*/
return NULL;
}
/* Create a thread. */
static int
thread_create(struct thread_st *st)
{
st->flags = 0;
{
pthread_attr_t* attr_p = 0;
#if USE_PTHREADS_STACKS
pthread_attr_t attr;
pthread_attr_init (&attr);
if(!st->sp)
st->sp = malloc(STACKSIZE+16);
if(!st->sp)
return -1;
if(pthread_attr_setstacksize(&attr, STACKSIZE))
fprintf(stderr, "error setting stacksize");
else
pthread_attr_setstackaddr(&attr, st->sp + STACKSIZE);
/*printf("create %p\n", st->sp);*/
attr_p = &attr;
#endif
return pthread_create(&st->id, attr_p, thread_wrapper, st);
}
return 0;
}
/* Wait for one of several subthreads to finish. */
static void
wait_for_thread(struct thread_st st[], int n_thr,
int (*end_thr)(struct thread_st*))
{
int i;
pthread_mutex_lock(&finish_mutex);
for(;;) {
int term = 0;
for(i=0; i<n_thr; i++)
if(st[i].flags) {
/*printf("joining %p\n", st[i].sp);*/
if(pthread_join(st[i].id, NULL) == 0) {
st[i].flags = 0;
if(end_thr)
end_thr(&st[i]);
} else
fprintf(stderr, "can't join\n");
++term;
}
if(term > 0)
break;
pthread_cond_wait(&finish_cond, &finish_mutex);
}
pthread_mutex_unlock(&finish_mutex);
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,51 +0,0 @@
/* Basic platform-independent macro definitions for mutexes,
thread-specific data and parameters for malloc.
Solaris threads version.
Copyright (C) 2004 Wolfram Gloger <wg@malloc.de>.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that (i) the above copyright notices and this permission
notice appear in all copies of the software and related documentation,
and (ii) the name of Wolfram Gloger may not be used in any advertising
or publicity relating to the software.
THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SOLARIS_MALLOC_MACHINE_H
#define _SOLARIS_MALLOC_MACHINE_H
#include <thread.h>
typedef thread_t thread_id;
#define MUTEX_INITIALIZER { 0 }
#define mutex_init(m) mutex_init(m, USYNC_THREAD, NULL)
/*
* Hack for thread-specific data on Solaris. We can't use thr_setspecific
* because that function calls malloc() itself.
*/
typedef void *tsd_key_t[256];
#define tsd_key_create(key, destr) do { \
int i; \
for(i=0; i<256; i++) (*key)[i] = 0; \
} while(0)
#define tsd_setspecific(key, data) (key[(unsigned)thr_self() % 256] = (data))
#define tsd_getspecific(key, vptr) (vptr = key[(unsigned)thr_self() % 256])
#define thread_atfork(prepare, parent, child) do {} while(0)
#include <sysdeps/generic/malloc-machine.h>
#endif /* !defined(_SOLARIS_MALLOC_MACHINE_H) */

Просмотреть файл

@ -1,72 +0,0 @@
/*
* $Id:$
* Solaris version
* by Wolfram Gloger 2004
*/
#include <thread.h>
#include <stdio.h>
#ifndef STACKSIZE
#define STACKSIZE 32768
#endif
struct thread_st {
char *sp; /* stack pointer, can be 0 */
void (*func)(struct thread_st* st); /* must be set by user */
thread_id id;
int flags;
struct user_data u;
};
static void
thread_init(void)
{
printf("Using Solaris threads.\n");
}
static void *
thread_wrapper(void *ptr)
{
struct thread_st *st = (struct thread_st*)ptr;
/*printf("begin %p\n", st->sp);*/
st->func(st);
/*printf("end %p\n", st->sp);*/
return NULL;
}
/* Create a thread. */
static int
thread_create(struct thread_st *st)
{
st->flags = 0;
if(!st->sp)
st->sp = malloc(STACKSIZE);
if(!st->sp) return -1;
thr_create(st->sp, STACKSIZE, thread_wrapper, st, THR_NEW_LWP, &st->id);
return 0;
}
/* Wait for one of several subthreads to finish. */
static void
wait_for_thread(struct thread_st st[], int n_thr,
int (*end_thr)(struct thread_st*))
{
int i;
thread_t id;
thr_join(0, &id, NULL);
for(i=0; i<n_thr; i++)
if(id == st[i].id) {
if(end_thr)
end_thr(&st[i]);
break;
}
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,51 +0,0 @@
/* Basic platform-independent macro definitions for mutexes,
thread-specific data and parameters for malloc.
SGI threads (sprocs) version.
Copyright (C) 2004 Wolfram Gloger <wg@malloc.de>.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that (i) the above copyright notices and this permission
notice appear in all copies of the software and related documentation,
and (ii) the name of Wolfram Gloger may not be used in any advertising
or publicity relating to the software.
THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SPROC_MALLOC_MACHINE_H
#define _SPROC_MALLOC_MACHINE_H
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <abi_mutex.h>
typedef abilock_t mutex_t;
#define MUTEX_INITIALIZER { 0 }
#define mutex_init(m) init_lock(m)
#define mutex_lock(m) (spin_lock(m), 0)
#define mutex_trylock(m) acquire_lock(m)
#define mutex_unlock(m) release_lock(m)
typedef int tsd_key_t;
int tsd_key_next;
#define tsd_key_create(key, destr) ((*key) = tsd_key_next++)
#define tsd_setspecific(key, data) (((void **)(&PRDA->usr_prda))[key] = data)
#define tsd_getspecific(key, vptr) (vptr = ((void **)(&PRDA->usr_prda))[key])
#define thread_atfork(prepare, parent, child) do {} while(0)
#include <sysdeps/generic/malloc-machine.h>
#endif /* !defined(_SPROC_MALLOC_MACHINE_H) */

Просмотреть файл

@ -1,84 +0,0 @@
/*
* $Id:$
* sproc version
* by Wolfram Gloger 2001, 2004
*/
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#ifndef STACKSIZE
#define STACKSIZE 32768
#endif
struct thread_st {
char *sp; /* stack pointer, can be 0 */
void (*func)(struct thread_st* st); /* must be set by user */
thread_id id;
int flags;
struct user_data u;
};
static void
thread_init(void)
{
printf("Using sproc() threads.\n");
}
static void
thread_wrapper(void *ptr, size_t stack_len)
{
struct thread_st *st = (struct thread_st*)ptr;
/*printf("begin %p\n", st->sp);*/
st->func(st);
/*printf("end %p\n", st->sp);*/
}
/* Create a thread. */
static int
thread_create(struct thread_st *st)
{
st->flags = 0;
if(!st->sp)
st->sp = malloc(STACKSIZE);
if(!st->sp) return -1;
st->id = sprocsp(thread_wrapper, PR_SALL, st, st->sp+STACKSIZE, STACKSIZE);
if(st->id < 0) {
return -1;
}
return 0;
}
/* Wait for one of several subthreads to finish. */
static void
wait_for_thread(struct thread_st st[], int n_thr,
int (*end_thr)(struct thread_st*))
{
int i;
int id;
int status = 0;
id = wait(&status);
if(status != 0) {
if(WIFSIGNALED(status))
printf("thread %id terminated by signal %d\n",
id, WTERMSIG(status));
else
printf("thread %id exited with status %d\n",
id, WEXITSTATUS(status));
}
for(i=0; i<n_thr; i++)
if(id == st[i].id) {
if(end_thr)
end_thr(&st[i]);
break;
}
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,143 +0,0 @@
/*
* $Id: t-test.h,v 1.1 2004/11/04 14:32:21 wg Exp $
* by Wolfram Gloger 1996.
* Common data structures and functions for testing malloc performance.
*/
/* Testing level */
#ifndef TEST
#define TEST 0
#endif
/* For large allocation sizes, the time required by copying in
realloc() can dwarf all other execution times. Avoid this with a
size threshold. */
#ifndef REALLOC_MAX
#define REALLOC_MAX 2000
#endif
struct bin {
unsigned char *ptr;
unsigned long size;
};
#if TEST > 0
static void
mem_init(unsigned char *ptr, unsigned long size)
{
unsigned long i, j;
if(size == 0) return;
for(i=0; i<size; i+=2047) {
j = (unsigned long)ptr ^ i;
ptr[i] = ((j ^ (j>>8)) & 0xFF);
}
j = (unsigned long)ptr ^ (size-1);
ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
}
static int
mem_check(unsigned char *ptr, unsigned long size)
{
unsigned long i, j;
if(size == 0) return 0;
for(i=0; i<size; i+=2047) {
j = (unsigned long)ptr ^ i;
if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 1;
}
j = (unsigned long)ptr ^ (size-1);
if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) return 2;
return 0;
}
static int
zero_check(unsigned* ptr, unsigned long size)
{
unsigned char* ptr2;
while(size >= sizeof(*ptr)) {
if(*ptr++ != 0)
return -1;
size -= sizeof(*ptr);
}
ptr2 = (unsigned char*)ptr;
while(size > 0) {
if(*ptr2++ != 0)
return -1;
--size;
}
return 0;
}
#endif /* TEST > 0 */
/* Allocate a bin with malloc(), realloc() or memalign(). r must be a
random number >= 1024. */
static void
bin_alloc(struct bin *m, unsigned long size, int r)
{
#if TEST > 0
if(mem_check(m->ptr, m->size)) {
printf("memory corrupt!\n");
exit(1);
}
#endif
r %= 1024;
/*printf("%d ", r);*/
if(r < 4) { /* memalign */
if(m->size > 0) free(m->ptr);
m->ptr = (unsigned char *)memalign(sizeof(int) << r, size);
} else if(r < 20) { /* calloc */
if(m->size > 0) free(m->ptr);
m->ptr = (unsigned char *)calloc(size, 1);
#if TEST > 0
if(zero_check((unsigned*)m->ptr, size)) {
long i;
for(i=0; i<size; i++)
if(m->ptr[i] != 0)
break;
printf("calloc'ed memory non-zero (ptr=%p, i=%ld)!\n", m->ptr, i);
exit(1);
}
#endif
} else if(r < 100 && m->size < REALLOC_MAX) { /* realloc */
if(m->size == 0) m->ptr = NULL;
m->ptr = realloc(m->ptr, size);
} else { /* plain malloc */
if(m->size > 0) free(m->ptr);
m->ptr = (unsigned char *)malloc(size);
}
if(!m->ptr) {
printf("out of memory (r=%d, size=%ld)!\n", r, (long)size);
exit(1);
}
m->size = size;
#if TEST > 0
mem_init(m->ptr, m->size);
#endif
}
/* Free a bin. */
static void
bin_free(struct bin *m)
{
if(m->size == 0) return;
#if TEST > 0
if(mem_check(m->ptr, m->size)) {
printf("memory corrupt!\n");
exit(1);
}
#endif
free(m->ptr);
m->size = 0;
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,285 +0,0 @@
/*
* $Id: t-test1.c,v 1.2 2004/11/04 14:58:45 wg Exp $
* by Wolfram Gloger 1996-1999, 2001, 2004
* A multi-thread test for malloc performance, maintaining one pool of
* allocated bins per thread.
*/
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# include <stdlib.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/mman.h>
#if !USE_MALLOC
#include <malloc.h>
#else
#include "malloc.h"
#endif
#include "lran2.h"
#include "t-test.h"
struct user_data {
int bins, max;
unsigned long size;
long seed;
};
#include "thread-st.h"
#define N_TOTAL 10
#ifndef N_THREADS
#define N_THREADS 2
#endif
#ifndef N_TOTAL_PRINT
#define N_TOTAL_PRINT 50
#endif
#ifndef MEMORY
#define MEMORY 8000000l
#endif
#define SIZE 10000
#define I_MAX 10000
#define ACTIONS_MAX 30
#ifndef TEST_FORK
#define TEST_FORK 0
#endif
#define RANDOM(d,s) (lran2(d) % (s))
struct bin_info {
struct bin *m;
unsigned long size, bins;
};
#if TEST > 0
void
bin_test(struct bin_info *p)
{
int b;
for(b=0; b<p->bins; b++) {
if(mem_check(p->m[b].ptr, p->m[b].size)) {
printf("memory corrupt!\n");
abort();
}
}
}
#endif
void
malloc_test(struct thread_st *st)
{
int b, i, j, actions, pid = 1;
struct bin_info p;
struct lran2_st ld; /* data for random number generator */
lran2_init(&ld, st->u.seed);
#if TEST_FORK>0
if(RANDOM(&ld, TEST_FORK) == 0) {
int status;
#if !USE_THR
pid = fork();
#else
pid = fork1();
#endif
if(pid > 0) {
/*printf("forked, waiting for %d...\n", pid);*/
waitpid(pid, &status, 0);
printf("done with %d...\n", pid);
if(!WIFEXITED(status)) {
printf("child term with signal %d\n", WTERMSIG(status));
exit(1);
}
return;
}
exit(0);
}
#endif
p.m = (struct bin *)malloc(st->u.bins*sizeof(*p.m));
p.bins = st->u.bins;
p.size = st->u.size;
for(b=0; b<p.bins; b++) {
p.m[b].size = 0;
p.m[b].ptr = NULL;
if(RANDOM(&ld, 2) == 0)
bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
}
for(i=0; i<=st->u.max;) {
#if TEST > 1
bin_test(&p);
#endif
actions = RANDOM(&ld, ACTIONS_MAX);
#if USE_MALLOC && MALLOC_DEBUG
if(actions < 2) { mallinfo(); }
#endif
for(j=0; j<actions; j++) {
b = RANDOM(&ld, p.bins);
bin_free(&p.m[b]);
}
i += actions;
actions = RANDOM(&ld, ACTIONS_MAX);
for(j=0; j<actions; j++) {
b = RANDOM(&ld, p.bins);
bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
#if TEST > 2
bin_test(&p);
#endif
}
#if 0 /* Test illegal free()s while setting MALLOC_CHECK_ */
for(j=0; j<8; j++) {
b = RANDOM(&ld, p.bins);
if(p.m[b].ptr) {
int offset = (RANDOM(&ld, 11) - 5)*8;
char *rogue = (char*)(p.m[b].ptr) + offset;
/*printf("p=%p rogue=%p\n", p.m[b].ptr, rogue);*/
free(rogue);
}
}
#endif
i += actions;
}
for(b=0; b<p.bins; b++)
bin_free(&p.m[b]);
free(p.m);
if(pid == 0)
exit(0);
}
int n_total=0, n_total_max=N_TOTAL, n_running;
int
my_end_thread(struct thread_st *st)
{
/* Thread st has finished. Start a new one. */
#if 0
printf("Thread %lx terminated.\n", (long)st->id);
#endif
if(n_total >= n_total_max) {
n_running--;
} else if(st->u.seed++, thread_create(st)) {
printf("Creating thread #%d failed.\n", n_total);
} else {
n_total++;
if(n_total%N_TOTAL_PRINT == 0)
printf("n_total = %d\n", n_total);
}
return 0;
}
#if 0
/* Protect address space for allocation of n threads by LinuxThreads. */
static void
protect_stack(int n)
{
char buf[2048*1024];
char* guard;
size_t guard_size = 2*2048*1024UL*(n+2);
buf[0] = '\0';
guard = (char*)(((unsigned long)buf - 4096)& ~4095UL) - guard_size;
printf("Setting up stack guard at %p\n", guard);
if(mmap(guard, guard_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
-1, 0)
!= guard)
printf("failed!\n");
}
#endif
int
main(int argc, char *argv[])
{
int i, bins;
int n_thr=N_THREADS;
int i_max=I_MAX;
unsigned long size=SIZE;
struct thread_st *st;
#if USE_MALLOC && USE_STARTER==2
ptmalloc_init();
printf("ptmalloc_init\n");
#endif
if(argc > 1) n_total_max = atoi(argv[1]);
if(n_total_max < 1) n_thr = 1;
if(argc > 2) n_thr = atoi(argv[2]);
if(n_thr < 1) n_thr = 1;
if(n_thr > 100) n_thr = 100;
if(argc > 3) i_max = atoi(argv[3]);
if(argc > 4) size = atol(argv[4]);
if(size < 2) size = 2;
bins = MEMORY/(size*n_thr);
if(argc > 5) bins = atoi(argv[5]);
if(bins < 4) bins = 4;
/*protect_stack(n_thr);*/
thread_init();
printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
n_total_max, n_thr, i_max, size, bins);
st = (struct thread_st *)malloc(n_thr*sizeof(*st));
if(!st) exit(-1);
#if !defined NO_THREADS && (defined __sun__ || defined sun)
/* I know of no other way to achieve proper concurrency with Solaris. */
thr_setconcurrency(n_thr);
#endif
/* Start all n_thr threads. */
for(i=0; i<n_thr; i++) {
st[i].u.bins = bins;
st[i].u.max = i_max;
st[i].u.size = size;
st[i].u.seed = ((long)i_max*size + i) ^ bins;
st[i].sp = 0;
st[i].func = malloc_test;
if(thread_create(&st[i])) {
printf("Creating thread #%d failed.\n", i);
n_thr = i;
break;
}
printf("Created thread %lx.\n", (long)st[i].id);
}
/* Start an extra thread so we don't run out of stacks. */
if(0) {
struct thread_st lst;
lst.u.bins = 10; lst.u.max = 20; lst.u.size = 8000; lst.u.seed = 8999;
lst.sp = 0;
lst.func = malloc_test;
if(thread_create(&lst)) {
printf("Creating thread #%d failed.\n", i);
} else {
wait_for_thread(&lst, 1, NULL);
}
}
for(n_running=n_total=n_thr; n_running>0;) {
wait_for_thread(st, n_thr, my_end_thread);
}
for(i=0; i<n_thr; i++) {
free(st[i].sp);
}
free(st);
#if USE_MALLOC
malloc_stats();
#endif
printf("Done.\n");
return 0;
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,231 +0,0 @@
/*
* $Id: t-test2.c,v 1.3 2004/11/04 15:01:05 wg Exp $
* by Wolfram Gloger 1996-1999, 2001, 2004
* A multi-thread test for malloc performance, maintaining a single
* global pool of allocated bins.
*/
#if (defined __STDC__ && __STDC__) || defined __cplusplus
# include <stdlib.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#if !USE_MALLOC
#include <malloc.h>
#else
#include "malloc.h"
#endif
#include "lran2.h"
#include "t-test.h"
struct user_data {
int max;
unsigned long size;
long seed;
};
#include "thread-st.h"
#include "malloc-machine.h" /* for mutex */
#define N_TOTAL 10
#ifndef N_THREADS
#define N_THREADS 2
#endif
#ifndef N_TOTAL_PRINT
#define N_TOTAL_PRINT 50
#endif
#define STACKSIZE 32768
#ifndef MEMORY
#define MEMORY 8000000l
#endif
#define SIZE 10000
#define I_MAX 10000
#define BINS_PER_BLOCK 20
#define RANDOM(d,s) (lran2(d) % (s))
struct block {
struct bin b[BINS_PER_BLOCK];
mutex_t mutex;
} *blocks;
int n_blocks;
#if TEST > 0
void
bin_test(void)
{
int b, i;
for(b=0; b<n_blocks; b++) {
mutex_lock(&blocks[b].mutex);
for(i=0; i<BINS_PER_BLOCK; i++) {
if(mem_check(blocks[b].b[i].ptr, blocks[b].b[i].size)) {
printf("memory corrupt!\n");
exit(1);
}
}
mutex_unlock(&blocks[b].mutex);
}
}
#endif
void
malloc_test(struct thread_st *st)
{
struct block *bl;
int i, b, r;
struct lran2_st ld; /* data for random number generator */
unsigned long rsize[BINS_PER_BLOCK];
int rnum[BINS_PER_BLOCK];
lran2_init(&ld, st->u.seed);
for(i=0; i<=st->u.max;) {
#if TEST > 1
bin_test();
#endif
bl = &blocks[RANDOM(&ld, n_blocks)];
r = RANDOM(&ld, 1024);
if(r < 200) { /* free only */
mutex_lock(&bl->mutex);
for(b=0; b<BINS_PER_BLOCK; b++)
bin_free(&bl->b[b]);
mutex_unlock(&bl->mutex);
i += BINS_PER_BLOCK;
} else { /* alloc/realloc */
/* Generate random numbers in advance. */
for(b=0; b<BINS_PER_BLOCK; b++) {
rsize[b] = RANDOM(&ld, st->u.size) + 1;
rnum[b] = lran2(&ld);
}
mutex_lock(&bl->mutex);
for(b=0; b<BINS_PER_BLOCK; b++)
bin_alloc(&bl->b[b], rsize[b], rnum[b]);
mutex_unlock(&bl->mutex);
i += BINS_PER_BLOCK;
}
#if TEST > 2
bin_test();
#endif
}
}
int n_total=0, n_total_max=N_TOTAL, n_running;
int
my_end_thread(struct thread_st *st)
{
/* Thread st has finished. Start a new one. */
#if 0
printf("Thread %lx terminated.\n", (long)st->id);
#endif
if(n_total >= n_total_max) {
n_running--;
} else if(st->u.seed++, thread_create(st)) {
printf("Creating thread #%d failed.\n", n_total);
} else {
n_total++;
if(n_total%N_TOTAL_PRINT == 0)
printf("n_total = %d\n", n_total);
}
return 0;
}
int
main(int argc, char *argv[])
{
int i, j, bins;
int n_thr=N_THREADS;
int i_max=I_MAX;
unsigned long size=SIZE;
struct thread_st *st;
#if USE_MALLOC && USE_STARTER==2
ptmalloc_init();
printf("ptmalloc_init\n");
#endif
if(argc > 1) n_total_max = atoi(argv[1]);
if(n_total_max < 1) n_thr = 1;
if(argc > 2) n_thr = atoi(argv[2]);
if(n_thr < 1) n_thr = 1;
if(n_thr > 100) n_thr = 100;
if(argc > 3) i_max = atoi(argv[3]);
if(argc > 4) size = atol(argv[4]);
if(size < 2) size = 2;
bins = MEMORY/size;
if(argc > 5) bins = atoi(argv[5]);
if(bins < BINS_PER_BLOCK) bins = BINS_PER_BLOCK;
n_blocks = bins/BINS_PER_BLOCK;
blocks = (struct block *)malloc(n_blocks*sizeof(*blocks));
if(!blocks)
exit(1);
thread_init();
printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
n_total_max, n_thr, i_max, size, n_blocks*BINS_PER_BLOCK);
for(i=0; i<n_blocks; i++) {
mutex_init(&blocks[i].mutex);
for(j=0; j<BINS_PER_BLOCK; j++) blocks[i].b[j].size = 0;
}
st = (struct thread_st *)malloc(n_thr*sizeof(*st));
if(!st) exit(-1);
#if !defined NO_THREADS && (defined __sun__ || defined sun)
/* I know of no other way to achieve proper concurrency with Solaris. */
thr_setconcurrency(n_thr);
#endif
/* Start all n_thr threads. */
for(i=0; i<n_thr; i++) {
st[i].u.max = i_max;
st[i].u.size = size;
st[i].u.seed = ((long)i_max*size + i) ^ n_blocks;
st[i].sp = 0;
st[i].func = malloc_test;
if(thread_create(&st[i])) {
printf("Creating thread #%d failed.\n", i);
n_thr = i;
break;
}
printf("Created thread %lx.\n", (long)st[i].id);
}
for(n_running=n_total=n_thr; n_running>0;) {
wait_for_thread(st, n_thr, my_end_thread);
}
for(i=0; i<n_blocks; i++) {
for(j=0; j<BINS_PER_BLOCK; j++)
bin_free(&blocks[i].b[j]);
}
for(i=0; i<n_thr; i++) {
free(st[i].sp);
}
free(st);
free(blocks);
#if USE_MALLOC
malloc_stats();
#endif
printf("Done.\n");
return 0;
}
/*
* Local variables:
* tab-width: 4
* End:
*/

Просмотреть файл

@ -1,82 +0,0 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <stdio.h>
#include "malloc.h"
static int errors = 0;
static void
merror (const char *msg)
{
++errors;
printf ("Error: %s\n", msg);
}
int
main (void)
{
void *p1, *p2;
void *save_state;
long i;
errno = 0;
p1 = malloc (10);
if (p1 == NULL)
merror ("malloc (10) failed.");
p2 = malloc (20);
if (p2 == NULL)
merror ("malloc (20) failed.");
free (malloc (10));
for (i=0; i<100; ++i)
{
save_state = malloc_get_state ();
if (save_state == NULL)
{
merror ("malloc_get_state () failed.");
break;
}
/*free (malloc (10)); This could change the top chunk! */
malloc_set_state (save_state);
p1 = realloc (p1, i*4 + 4);
if (p1 == NULL)
merror ("realloc (i*4) failed.");
free (save_state);
}
p1 = realloc (p1, 40);
free (p2);
p2 = malloc (10);
if (p2 == NULL)
merror ("malloc (10) failed.");
free (p1);
return errors != 0;
}
/*
* Local variables:
* c-basic-offset: 2
* End:
*/

Просмотреть файл

@ -1,100 +0,0 @@
/* Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Wolfram Gloger <wg@malloc.de>, 2004.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <stdio.h>
#include "malloc.h"
static int errors = 0;
static void
merror (const char *msg)
{
++errors;
printf ("Error: %s\n", msg);
}
int
main (void)
{
void *p1, *p2;
long i;
mstate a;
struct malloc_arena_info mai;
int nfree;
unsigned long navail;
errno = 0;
malloc_stats(); /* check that it works even without initialization */
a = _int_get_arena(0);
if (!a) {
merror ("Can't get main arena.");
return 1;
}
free (malloc (10));
_int_get_arena_info(a, &mai);
printf("nfree = %d\navail = %lu\nfastavail = %lu\ntop_size = %lu\n",
mai.nbinblocks + mai.nfastblocks,
(unsigned long)mai.binavail,
(unsigned long)mai.fastavail,
(unsigned long)mai.top_size);
if (mai.nfastblocks+mai.nbinblocks < 1)
merror ("initial _int_get_arena_info() failed.");
nfree = mai.nbinblocks + mai.nfastblocks;
navail = mai.binavail + mai.fastavail;
p1 = malloc (10);
if (p1 == NULL)
merror ("malloc (10) failed.");
p2 = malloc (30);
if (p2 == NULL)
merror ("malloc (30) failed.");
free (malloc (10));
for (i=0; i<100; ++i)
{
p1 = realloc (p1, i*7 + 3);
if (p1 == NULL)
merror ("realloc (i*7 + 3) failed.");
}
free (p2);
_int_get_arena_info(a, &mai);
printf("nfree = %d\navail = %lu\nfastavail = %lu\ntop_size = %lu\n",
mai.nbinblocks + mai.nfastblocks,
(unsigned long)mai.binavail,
(unsigned long)mai.fastavail,
(unsigned long)mai.top_size);
/* Assume that no memory is returned to the system from these small
chunks. */
if (mai.nbinblocks+mai.nfastblocks < nfree ||
mai.binavail+mai.fastavail < navail)
merror ("final _int_get_arena_info() failed.");
malloc_stats();
return errors != 0;
}
/*
* Local variables:
* c-basic-offset: 2
* End:
*/

Просмотреть файл

@ -12,7 +12,7 @@
* All rights reserved. * All rights reserved.
* Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009-2011 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009-2011 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2015 Los Alamos National Security, LLC. All rights * Copyright (c) 2015-2016 Los Alamos National Security, LLC. All rights
* reserved. * reserved.
* Copyright (c) 2016 Research Organization for Information Science * Copyright (c) 2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved. * and Technology (RIST). All rights reserved.
@ -46,6 +46,7 @@ int __munmap(caddr_t addr, size_t len);
#endif #endif
static int opal_memory_malloc_open(void); static int opal_memory_malloc_open(void);
static int opal_memory_malloc_query(int *);
const opal_memory_base_component_2_0_0_t mca_memory_malloc_solaris_component = { const opal_memory_base_component_2_0_0_t mca_memory_malloc_solaris_component = {
/* First, the mca_component_t struct containing meta information /* First, the mca_component_t struct containing meta information
@ -68,6 +69,7 @@ const opal_memory_base_component_2_0_0_t mca_memory_malloc_solaris_component = {
/* This component doesn't need these functions, but need to /* This component doesn't need these functions, but need to
provide safe/empty register/deregister functions to call */ provide safe/empty register/deregister functions to call */
.memoryc_query = opal_memory_malloc_query,
.memoryc_register = opal_memory_base_component_register_empty, .memoryc_register = opal_memory_base_component_register_empty,
.memoryc_deregister = opal_memory_base_component_deregister_empty, .memoryc_deregister = opal_memory_base_component_deregister_empty,
.memoryc_set_alignment = opal_memory_base_component_set_alignment_empty, .memoryc_set_alignment = opal_memory_base_component_set_alignment_empty,
@ -93,6 +95,11 @@ opal_memory_malloc_open(void)
return OPAL_SUCCESS; return OPAL_SUCCESS;
} }
static int opal_memory_malloc_query (int *priority)
{
*priority = 79;
return OPAL_SUCCESS;
}
/* /*
* Three ways to call munmap. Prefered is to call __munmap, which * Three ways to call munmap. Prefered is to call __munmap, which

Просмотреть файл

@ -11,7 +11,7 @@
* Copyright (c) 2004-2005 The Regents of the University of California. * Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2015 Los Alamos National Security, LLC. All rights * Copyright (c) 2015-2016 Los Alamos National Security, LLC. All rights
* reserved. * reserved.
* Copyright (c) 2016 Research Organization for Information Science * Copyright (c) 2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved. * and Technology (RIST). All rights reserved.
@ -78,6 +78,12 @@ BEGIN_C_DECLS
*/ */
typedef int (*opal_memory_base_component_process_fn_t)(void); typedef int (*opal_memory_base_component_process_fn_t)(void);
/**
* Prototype for a function that is invoked when the memory base is
* trying to select a component. This funtionality is required.
*/
typedef int (*opal_memory_base_component_query_fn_t)(int *priority);
/** /**
* Prototype for a function that is invoked when Open MPI starts to * Prototype for a function that is invoked when Open MPI starts to
* "care" about a specific memory region. That is, Open MPI declares * "care" about a specific memory region. That is, Open MPI declares
@ -119,6 +125,11 @@ typedef int (*opal_memory_base_component_deregister_fn_t)(void *base,
typedef void (*opal_memory_base_component_set_alignment_fn_t)(int use_memalign, typedef void (*opal_memory_base_component_set_alignment_fn_t)(int use_memalign,
size_t memalign_threshold); size_t memalign_threshold);
/**
* Function to be called when initializing malloc hooks
*/
typedef void (*opal_memory_base_component_init_hook_fn_t)(void);
/** /**
* Structure for memory components. * Structure for memory components.
*/ */
@ -128,6 +139,12 @@ typedef struct opal_memory_base_component_2_0_0_t {
/** MCA base data */ /** MCA base data */
mca_base_component_data_t memoryc_data; mca_base_component_data_t memoryc_data;
opal_memory_base_component_query_fn_t memoryc_query;
/** This function will be called when the malloc hooks are
* initialized. It may be NULL if no hooks are needed. */
opal_memory_base_component_init_hook_fn_t memoryc_init_hook;
/** Function to call when something has changed, as indicated by /** Function to call when something has changed, as indicated by
opal_memory_changed(). Will be ignored if the component does opal_memory_changed(). Will be ignored if the component does
not provide an opal_memory_changed() macro that returns not provide an opal_memory_changed() macro that returns

32
opal/mca/memory/patcher/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,32 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# This component is only ever built statically (i.e., slurped into
# libopen-pal) -- it is never built as a DSO.
noinst_LTLIBRARIES = libmca_memory_patcher.la
libmca_memory_patcher_la_SOURCES = \
memory_patcher.h \
memory_patcher_component.c
libmca_memory_patcher_la_LDFLAGS = \
-module -avoid-version $(memory_patcher_LDFLAGS)
libmca_memory_patcher_la_LIBADD = $(memory_patcher_LIBS)

90
opal/mca/memory/patcher/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,90 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
AC_DEFUN([MCA_opal_memory_patcher_PRIORITY], [41])
AC_DEFUN([MCA_opal_memory_patcher_COMPILE_MODE], [
AC_MSG_CHECKING([for MCA component $2:$3 compile mode])
$4="static"
AC_MSG_RESULT([$$4])
])
# MCA_memory_patcher_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_memory_patcher_CONFIG],[
AC_CONFIG_FILES([opal/mca/memory/patcher/Makefile])
OPAL_VAR_SCOPE_PUSH([memory_patcher_have___curbrk memory_patcher_have___mmap memory_patcher_have___syscall memory_patcher_have___mmap_prototype memory_patcher_have___syscall_prototype])
memory_patcher_have___curbrk=0
memory_patcher_have___mmap=0
memory_patcher_have___mmap_prototype=0
memory_patcher_have___syscall=0
memory_patcher_have___syscall_prototype=0
AC_MSG_CHECKING([for __curbrk symbol])
AC_LINK_IFELSE([AC_LANG_PROGRAM([extern char *__curbrk;],[char *tmp = __curbrk;])],
[AC_MSG_RESULT([yes])
memory_patcher_have___curbrk=1],
[AC_MSG_RESULT([no])])
AC_DEFINE_UNQUOTED([OPAL_MEMORY_PATCHER_HAVE___CURBRK], [$memory_patcher_have___curbrk],
[Whether the glibc __curbrk exists])
AC_MSG_CHECKING([whether __mmap prototype exists])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <sys/mman.h>],[char *tmp = __mmap (NULL, 0, 0, 0, 0, 0);])],
[AC_MSG_RESULT([yes])
memory_patcher_have___mmap_prototype=1],
[AC_MSG_RESULT([no])])
AC_DEFINE_UNQUOTED([OPAL_MEMORY_PATCHER_HAVE___MMAP_PROTO], [$memory_patcher_have___mmap_prototype],
[Whether the internal __mmap call has a prototype])
AC_MSG_CHECKING([whether __mmap symbol exists])
AC_LINK_IFELSE([AC_LANG_PROGRAM([void *__mmap ();],[char *tmp = __mmap ();])],
[AC_MSG_RESULT([yes])
memory_patcher_have___mmap=1],
[AC_MSG_RESULT([no])])
AC_DEFINE_UNQUOTED([OPAL_MEMORY_PATCHER_HAVE___MMAP], [$memory_patcher_have___mmap],
[Whether the internal __mmap call exists])
AC_MSG_CHECKING([whether __syscall prototype exists])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <sys/syscall.h>],[char *tmp = __syscall (SYS_mmap, NULL);])],
[AC_MSG_RESULT([yes])
memory_patcher_have___syscall_prototype=1],
[AC_MSG_RESULT([no])])
AC_DEFINE_UNQUOTED([OPAL_MEMORY_PATCHER_HAVE___SYSCALL_PROTO], [$memory_patcher_have___syscall_prototype],
[Whether the internal __syscall call has a prototype])
AC_MSG_CHECKING([whether __syscall symbol exists])
AC_LINK_IFELSE([AC_LANG_PROGRAM([void *__syscall ();],[char *tmp = __syscall ();])],
[AC_MSG_RESULT([yes])
memory_patcher_have___syscall=1],
[AC_MSG_RESULT([no])])
AC_DEFINE_UNQUOTED([OPAL_MEMORY_PATCHER_HAVE___SYSCALL], [$memory_patcher_have___syscall],
[Whether the internal __syscall call exists])
[$1]
OPAL_VAR_SCOPE_POP
])

27
opal/mca/memory/patcher/memory_patcher.h Обычный файл
Просмотреть файл

@ -0,0 +1,27 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* ******** ADD IBM COPYRIGHT HERE ******
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#if !defined(OPAL_MEMORY_PATCHER_H)
#define OPAL_MEMORY_PATCHER_H
#include "opal_config.h"
#include "opal/mca/memory/memory.h"
#include "opal/mca/patcher/patcher.h"
typedef struct opal_memory_patcher_component_t {
opal_memory_base_component_2_0_0_t super;
} opal_memory_patcher_component_t;
extern opal_memory_patcher_component_t mca_memory_patcher_component;
#endif /* !defined(OPAL_MEMORY_PATCHER_H) */

Просмотреть файл

@ -0,0 +1,423 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2013-2016 Los Alamos National Security, LLC. All rights
* reserved.
* Copyright (c) 2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved.
* ******** Add IBM COPYRIGHT HERE ***********
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "memory_patcher.h"
#include "opal/util/output.h"
#include "opal/util/show_help.h"
#include "opal/mca/memory/base/empty.h"
#include "opal/mca/memory/base/base.h"
#include "opal/memoryhooks/memory.h"
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include "memory_patcher.h"
#undef opal_memory_changed
static int patcher_open(void);
static int patcher_close(void);
static int patcher_register(void);
static int patcher_query (int *);
static int mca_memory_patcher_priority;
opal_memory_patcher_component_t mca_memory_patcher_component = {
.super = {
.memoryc_version = {
OPAL_MEMORY_BASE_VERSION_2_0_0,
/* Component name and version */
.mca_component_name = "patcher",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
/* Component open and close functions */
.mca_open_component = patcher_open,
.mca_close_component = patcher_close,
.mca_register_component_params = patcher_register,
},
.memoryc_data = {
/* The component is checkpoint ready */
MCA_BASE_METADATA_PARAM_CHECKPOINT
},
/* Memory framework functions. */
.memoryc_query = patcher_query,
.memoryc_register = opal_memory_base_component_register_empty,
.memoryc_deregister = opal_memory_base_component_deregister_empty,
.memoryc_set_alignment = opal_memory_base_component_set_alignment_empty,
},
/* Component-specific data, filled in later (compiler will 0/NULL
it out) */
};
#if OPAL_MEMORY_PATCHER_HAVE___SYSCALL_PROTO && OPAL_MEMORY_PATCHER_HAVE___SYSCALL
/* calling __syscall is preferred on some systems when some arguments may be 64-bit. it also
* has the benefit of having an off_t return type */
#define memory_patcher_syscall __syscall
#else
#define memory_patcher_syscall syscall
#endif
#if 0
#if OPAL_MEMORY_PATCHER_HAVE___MMAP && !OPAL_MEMORY_PATCHER_HAVE___MMAP_PROTO
/* prototype for Apple's internal mmap function */
void *__mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
#endif
static void *(*original_mmap)(void *, size_t, int, int, int, off_t);
static void *intercept_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
OPAL_PATCHER_BEGIN;
void *result = 0;
if (prot == PROT_NONE) {
opal_mem_hooks_release_hook (start, length, true);
}
if (!original_mmap) {
#if OPAL_MEMORY_PATCHER_HAVE___MMAP
/* the darwin syscall returns an int not a long so call the underlying __mmap function */
result = __mmap (start, length, prot, flags, fd, offset);
#else
result = (void*)(intptr_t) memory_patcher_syscall(SYS_mmap, start, length, prot, flags, fd, offset);
#endif
// I thought we had some issue in the past with the above line for IA32,
// like maybe syscall() wouldn't handle that many arguments. But just now
// I used gcc -m32 and it worked on a recent system. But there's a possibility
// that older ia32 systems may need some other code to make the above syscall.
} else {
result = original_mmap (start, length, prot, flags, fd, offset);
}
OPAL_PATCHER_END;
return result;
}
#endif
static int (*original_munmap) (void *, size_t);
static int intercept_munmap(void *start, size_t length)
{
OPAL_PATCHER_BEGIN;
int result = 0;
opal_mem_hooks_release_hook (start, length, false);
if (!original_munmap) {
result = memory_patcher_syscall(SYS_munmap, start, length);
} else {
result = original_munmap (start, length);
}
OPAL_PATCHER_END;
return result;
}
#if defined (SYS_mremap)
/* on linux this function has an optional extra argument but ... can not be used here because it
* causes issues when intercepting a 4-argument mremap call */
static void *(*original_mremap) (void *, size_t, size_t, int, void *);
static void *intercept_mremap (void *start, size_t oldlen, size_t newlen, int flags, void *new_address)
{
OPAL_PATCHER_BEGIN;
void *result = MAP_FAILED;
if (MAP_FAILED != start && oldlen > 0) {
opal_mem_hooks_release_hook (start, oldlen, true);
}
if (!(flags & MREMAP_FIXED)) {
new_address = NULL;
}
if (!original_mremap) {
result = (void *)(intptr_t) memory_patcher_syscall (SYS_mremap, start, oldlen, newlen, flags, new_address);
} else {
result = original_mremap (start, oldlen, newlen, flags, new_address);
}
OPAL_PATCHER_END;
return result;
}
#endif
static int (*original_madvise) (void *, size_t, int);
static int intercept_madvise (void *start, size_t length, int advice)
{
OPAL_PATCHER_BEGIN;
int result = 0;
if (advice == MADV_DONTNEED ||
#ifdef MADV_REMOVE
advice == MADV_REMOVE ||
#endif
advice == POSIX_MADV_DONTNEED)
{
opal_mem_hooks_release_hook (start, length, false);
}
if (!original_madvise) {
result = memory_patcher_syscall(SYS_madvise, start, length, advice);
} else {
result = original_madvise (start, length, advice);
}
OPAL_PATCHER_END;
return result;
}
#if defined SYS_brk
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
void *__curbrk; /* in libc */
#endif
static int (*original_brk) (void *);
static int intercept_brk (void *addr)
{
OPAL_PATCHER_BEGIN;
int result = 0;
void *old_addr, *new_addr;
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
old_addr = __curbrk;
#else
old_addr = sbrk (0);
#endif
if (!original_brk) {
/* get the current_addr */
new_addr = (void *) (intptr_t) memory_patcher_syscall(SYS_brk, addr);
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
/*
* Note: if we were using glibc brk/sbrk, their __curbrk would get
* updated, but since we're going straight to the syscall, we have
* to update __curbrk or else glibc won't see it.
*/
__curbrk = new_addr;
#endif
} else {
result = original_brk (addr);
#if OPAL_MEMORY_PATCHER_HAVE___CURBRK
new_addr = __curbrk;
#else
new_addr = sbrk (0);
#endif
}
if (new_addr < addr) {
errno = ENOMEM;
result = -1;
} else if (new_addr < old_addr) {
opal_mem_hooks_release_hook (new_addr, (intptr_t) old_addr - (intptr_t) new_addr, true);
}
OPAL_PATCHER_END;
return result;
}
#endif
#if defined(SYS_shmdt) && defined(__linux__)
#include <stdio.h>
#include <fcntl.h>
#include <sys/shm.h>
static size_t memory_patcher_get_shm_seg_size (const void *shmaddr)
{
unsigned long start_addr, end_addr;
char *ptr, *newline;
char buffer[1024];
size_t seg_size = 0;
int fd;
seg_size = 0;
fd = open ("/proc/self/maps", O_RDONLY);
assert (fd >= 0);
for (size_t read_offset = 0 ; ; ) {
ssize_t nread = read(fd, buffer + read_offset, sizeof(buffer) - 1 - read_offset);
if (nread <= 0) {
if (errno == EINTR) {
continue;
}
break;
} else {
buffer[nread + read_offset] = '\0';
}
ptr = buffer;
while ( (newline = strchr(ptr, '\n')) != NULL ) {
/* 00400000-0040b000 r-xp ... \n */
int ret = sscanf(ptr, "%lx-%lx ", &start_addr, &end_addr);
if (ret != 2) {
continue;
}
if (start_addr == (uintptr_t)shmaddr) {
seg_size = end_addr - start_addr;
goto out_close;
}
newline = strchr(ptr, '\n');
if (newline == NULL) {
break;
}
ptr = newline + 1;
}
read_offset = strlen(ptr);
memmove(buffer, ptr, read_offset);
}
out_close:
close(fd);
return seg_size;
}
static int (*original_shmdt) (const void *);
static int intercept_shmdt (const void *shmaddr)
{
OPAL_PATCHER_BEGIN;
int result;
opal_mem_hooks_release_hook (shmaddr, memory_patcher_get_shm_seg_size (shmaddr), false);
if (original_shmdt) {
result = original_shmdt (shmaddr);
} else {
result = memory_patcher_syscall (SYS_shmdt, shmaddr);
}
OPAL_PATCHER_END;
return result;
}
#endif
static int patcher_register (void)
{
mca_memory_patcher_priority = 80;
mca_base_component_var_register (&mca_memory_patcher_component.super.memoryc_version,
"priority", "Priority of the patcher memory hook component",
MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_CONSTANT, &mca_memory_patcher_priority);
return OPAL_SUCCESS;
}
static int patcher_query (int *priority)
{
if (opal_patcher->patch_symbol) {
*priority = mca_memory_patcher_priority;
} else {
*priority = -1;
}
return OPAL_SUCCESS;
}
static int patcher_open (void)
{
static int was_executed_already = 0;
int rc;
if (was_executed_already) {
return OPAL_SUCCESS;
}
was_executed_already = 1;
/* set memory hooks support level */
opal_mem_hooks_set_support (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT);
#if 0
/* NTH: the only reason to hook mmap would be to detect memory protection. this does not invalidate
* any cache entries in the region. */
rc = opal_patcher->patch_symbol ("mmap", (uintptr_t) intercept_mmap, (uintptr_t *) &original_mmap);
if (OPAL_SUCCESS != rc) {
return rc;
}
#endif
rc = opal_patcher->patch_symbol ("munmap", (uintptr_t)intercept_munmap, (uintptr_t *) &original_munmap);
if (OPAL_SUCCESS != rc) {
return rc;
}
#if defined (SYS_mremap)
rc = opal_patcher->patch_symbol ("mremap",(uintptr_t)intercept_mremap, (uintptr_t *) &original_mremap);
if (OPAL_SUCCESS != rc) {
return rc;
}
#endif
rc = opal_patcher->patch_symbol ("madvise", (uintptr_t)intercept_madvise, (uintptr_t *) &original_madvise);
if (OPAL_SUCCESS != rc) {
return rc;
}
#if defined(SYS_shmdt) && defined(__linux__)
rc = opal_patcher->patch_symbol ("shmdt", (uintptr_t) intercept_shmdt, (uintptr_t *) &original_shmdt);
if (OPAL_SUCCESS != rc) {
return rc;
}
#endif
#if defined (SYS_brk)
rc = opal_patcher->patch_symbol ("brk", (uintptr_t)intercept_brk, (uintptr_t *) &original_brk);
#endif
return rc;
}
static int patcher_close(void)
{
/* NTH: is it possible to unpatch the symbols? */
return OPAL_SUCCESS;
}

39
opal/mca/patcher/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,39 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# main library setup
noinst_LTLIBRARIES = libmca_patcher.la
libmca_patcher_la_SOURCES =
# local files
headers = patcher.h
libmca_patcher_la_SOURCES += $(headers)
# Conditionally install the header files
if WANT_INSTALL_HEADERS
opaldir = $(opalincludedir)/$(subdir)
nobase_opal_HEADERS = $(headers)
endif
include base/Makefile.am
distclean-local:
rm -f base/static-components.h

25
opal/mca/patcher/base/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,25 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
headers += base/base.h
libmca_patcher_la_SOURCES += base/patcher_base_frame.c \
base/patcher_base_patch.c

83
opal/mca/patcher/base/base.h Обычный файл
Просмотреть файл

@ -0,0 +1,83 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2006 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*
*/
#ifndef OPAL_PATCHER_BASE_H
#define OPAL_PATCHER_BASE_H
#include "opal_config.h"
#include "opal/mca/base/mca_base_framework.h"
#include "opal/mca/patcher/patcher.h"
BEGIN_C_DECLS
#define MCA_BASE_PATCHER_MAX_PATCH 32
struct mca_patcher_base_patch_t;
typedef void (*mca_patcher_base_restore_fn_t) (struct mca_patcher_base_patch_t *);
struct mca_patcher_base_patch_t {
/** patches are list items */
opal_list_item_t super;
/** name symbol to patch */
char *patch_symbol;
/** address of function to call instead */
uintptr_t patch_value;
/** original address of function */
uintptr_t patch_orig;
/** patch data */
unsigned char patch_data[MCA_BASE_PATCHER_MAX_PATCH];
/** original data */
unsigned char patch_orig_data[MCA_BASE_PATCHER_MAX_PATCH];
/** size of patch data */
unsigned patch_data_size;
/** function to undo the patch */
mca_patcher_base_restore_fn_t patch_restore;
};
typedef struct mca_patcher_base_patch_t mca_patcher_base_patch_t;
OBJ_CLASS_DECLARATION(mca_patcher_base_patch_t);
/**
* Framework struct declaration for this framework
*/
OPAL_DECLSPEC extern mca_base_framework_t opal_patcher_base_framework;
OPAL_DECLSPEC int opal_patcher_base_select (void);
OPAL_DECLSPEC int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook);
OPAL_DECLSPEC void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch);
static inline uintptr_t mca_patcher_base_addr_text (uintptr_t addr) {
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && _CALL_ELF != 2
struct odp_t {
uintptr_t text;
uintptr_t toc;
} *odp = (struct odp_t *) addr;
return (odp)?odp->text:0;
#else
return addr;
#endif
}
END_C_DECLS
#endif /* OPAL_BASE_PATCHER_H */

81
opal/mca/patcher/base/patcher_base_frame.c Обычный файл
Просмотреть файл

@ -0,0 +1,81 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/patcher/base/static-components.h"
/*
* Local variables
*/
static mca_patcher_base_module_t empty_module;
/*
* Globals
*/
mca_patcher_base_module_t *opal_patcher = &empty_module;
int opal_patcher_base_select (void)
{
mca_patcher_base_module_t *best_module;
mca_patcher_base_component_t *best_component;
int rc, priority;
rc = mca_base_select ("patcher", opal_patcher_base_framework.framework_output,
&opal_patcher_base_framework.framework_components,
(mca_base_module_t **) &best_module, (mca_base_component_t **) &best_component,
&priority);
if (OPAL_SUCCESS != rc) {
return rc;
}
OBJ_CONSTRUCT(&best_module->patch_list, opal_list_t);
OBJ_CONSTRUCT(&best_module->patch_list_mutex, opal_mutex_t);
if (best_module->patch_init) {
rc = best_module->patch_init ();
if (OPAL_SUCCESS != rc) {
return rc;
}
}
opal_patcher = best_module;
return OPAL_SUCCESS;
}
static int opal_patcher_base_close (void)
{
if (opal_patcher == &empty_module) {
return OPAL_SUCCESS;
}
mca_patcher_base_patch_t *patch;
OPAL_LIST_FOREACH_REV(patch, &opal_patcher->patch_list, mca_patcher_base_patch_t) {
patch->patch_restore (patch);
}
OPAL_LIST_DESTRUCT(&opal_patcher->patch_list);
OBJ_DESTRUCT(&opal_patcher->patch_list_mutex);
if (opal_patcher->patch_fini) {
return opal_patcher->patch_fini ();
}
return OPAL_SUCCESS;
}
/* Use default register/open functions */
MCA_BASE_FRAMEWORK_DECLARE(opal, patcher, "runtime code patching", NULL, NULL,
opal_patcher_base_close, mca_patcher_base_static_components,
0);

175
opal/mca/patcher/base/patcher_base_patch.c Обычный файл
Просмотреть файл

@ -0,0 +1,175 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/util/sys_limits.h"
#include "opal/prefetch.h"
#include <sys/mman.h>
static void mca_patcher_base_patch_construct (mca_patcher_base_patch_t *patch)
{
patch->patch_symbol = NULL;
patch->patch_data_size = 0;
}
static void mca_patcher_base_patch_destruct (mca_patcher_base_patch_t *patch)
{
free (patch->patch_symbol);
}
OBJ_CLASS_INSTANCE(mca_patcher_base_patch_t, opal_list_item_t,
mca_patcher_base_patch_construct,
mca_patcher_base_patch_destruct);
#if defined(__PPC__)
// PowerPC instructions used in patching
// Reference: "PowerPC User Instruction Set Architecture"
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
}
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
}
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
}
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
{
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
}
static int PatchLoadImm (uintptr_t addr, unsigned int reg, size_t value)
{
#if defined(__PPC64__)
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 48));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 32));
*(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31);
*(unsigned int *) (addr +12) = oris ( reg, reg, (value >> 16));
*(unsigned int *) (addr +16) = ori ( reg, reg, (value >> 0));
return 20;
#else
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 16));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 0));
return 8;
#endif
}
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
static void flush_and_invalidate_cache (unsigned long a)
{
#if defined(__i386__)
/* does not work with AMD processors */
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__x86_64__)
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a));
#elif defined(__ia64__)
__asm__ volatile ("fc %0;; sync.i;; srlz.i;;" : : "r"(a) : "memory");
#endif
}
#endif
// modify protection of memory range
static void ModifyMemoryProtection (uintptr_t addr, size_t length, int prot)
{
long page_size = opal_getpagesize ();
uintptr_t base = (addr & ~(page_size-1));
uintptr_t bound = ((addr + length + page_size-1) & ~(page_size-1));
length = bound - base;
#if defined(__PPC__)
/* NTH: is a loop necessary here? */
do {
if (mprotect((void *)base, page_size, prot))
perror("MemHook: mprotect failed");
base += page_size;
} while (base < addr + length);
#else
if (mprotect((void *) base, length, prot)) {
perror("MemHook: mprotect failed");
}
#endif
}
static inline void apply_patch (unsigned char *patch_data, uintptr_t address, size_t data_size)
{
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ|PROT_WRITE);
memcpy ((void *) address, patch_data, data_size);
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
for (size_t i = 0 ; i < data_size ; i += 16) {
flush_and_invalidate_cache (address + i);
}
#endif
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ);
}
static void mca_base_patcher_patch_unapply_binary (mca_patcher_base_patch_t *patch)
{
apply_patch (patch->patch_orig_data, patch->patch_orig, patch->patch_data_size);
}
void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch)
{
memcpy (patch->patch_orig_data, (void *) patch->patch_orig, patch->patch_data_size);
apply_patch (patch->patch_data, patch->patch_orig, patch->patch_data_size);
patch->patch_restore = mca_base_patcher_patch_unapply_binary;
}
int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook_addr)
{
#if defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)
mca_patcher_base_patch_t *hook_patch;
const unsigned int nop = 0x60000000;
unsigned int *nop_addr;
fprintf (stderr, "Patching hook @ 0x%lx\n", hook_addr);
hook_patch = OBJ_NEW(mca_patcher_base_patch_t);
if (OPAL_UNLIKELY(NULL == hook_patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
// locate reserved code space in hook function
for (nop_addr = (unsigned int *)hook_addr ; ; nop_addr++) {
if (nop_addr[0] == nop && nop_addr[1] == nop && nop_addr[2] == nop
&& nop_addr[3] == nop && nop_addr[4] == nop) {
break;
}
}
// generate code to restore TOC
register unsigned long toc asm("r2");
hook_patch->patch_orig = (uintptr_t) nop_addr;
hook_patch->patch_data_size = PatchLoadImm((uintptr_t)hook_patch->patch_data, 2, toc);
/* put the hook patch on the patch list so it will be undone on finalize */
opal_list_append (&module->patch_list, &hook_patch->super);
mca_base_patcher_patch_apply_binary (hook_patch);
#endif
return OPAL_SUCCESS;
}

47
opal/mca/patcher/linux/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,47 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
if MCA_BUILD_opal_patcher_linux_DSO
component_noinst =
component_install = mca_patcher_linux.la
else
component_noinst = libmca_patcher_linux.la
component_install =
endif
linux_SOURCES = \
patcher_linux.h \
patcher_linux_module.c \
patcher_linux_component.c
mcacomponentdir = $(opallibdir)
mcacomponent_LTLIBRARIES = $(component_install)
mca_patcher_linux_la_SOURCES = $(linux_SOURCES)
nodist_mca_patcher_linux_la_SOURCES = $(linux_nodist_SOURCES)
mca_patcher_linux_la_LDFLAGS = -module -avoid-version
noinst_LTLIBRARIES = $(component_noinst)
libmca_patcher_linux_la_SOURCES = $(linux_SOURCES)
nodist_libmca_patcher_linux_la_SOURCES = $(linux_nodist_SOURCES)
libmca_patcher_linux_la_LIBADD = $(patcher_linux_LIBS)
libmca_patcher_linux_la_LDFLAGS = -module -avoid-version

43
opal/mca/patcher/linux/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,43 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# MCA_patcher_linux_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_patcher_linux_CONFIG],[
AC_CONFIG_FILES([opal/mca/patcher/linux/Makefile])
OPAL_VAR_SCOPE_PUSH([opal_patcher_linux_CPPFLAGS_save])
opal_patcher_linux_happy=no
if test $OPAL_ENABLE_DLOPEN_SUPPORT = 1; then
OPAL_CHECK_PACKAGE([patcher_linux], [dlfcn.h], [dl], [dl_iterate_phdr], [], [], [],
[opal_patcher_linux_happy=yes],[])
AC_CHECK_HEADERS([elf.h],[],[opal_patcher_linux_happy=no])
AC_CHECK_HEADERS([sys/auxv.h])
fi
AS_IF([test $opal_patcher_linux_happy = yes], [$1], [$2])
OPAL_VAR_SCOPE_POP
])

45
opal/mca/patcher/linux/patcher_linux.h Обычный файл
Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#if !defined(OPAL_PATCHER_LINUX_H)
#define OPAL_PATCHER_LINUX_H
#include "opal_config.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/class/opal_list.h"
#include "opal/threads/mutex.h"
struct mca_patcher_linux_patch_got_t {
opal_list_item_t super;
void **got_entry;
void *got_orig;
};
typedef struct mca_patcher_linux_patch_got_t mca_patcher_linux_patch_got_t;
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_got_t);
struct mca_patcher_linux_patch_t {
mca_patcher_base_patch_t super;
opal_list_t patch_got_list;
};
typedef struct mca_patcher_linux_patch_t mca_patcher_linux_patch_t;
OBJ_CLASS_DECLARATION(mca_patcher_linux_patch_t);
extern mca_patcher_base_module_t mca_patcher_linux_module;
extern mca_patcher_base_component_t mca_patcher_linux_component;
#endif /* !defined(OPAL_PATCHER_LINUX_H) */

Просмотреть файл

@ -0,0 +1,43 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "patcher_linux.h"
static int mca_patcher_linux_priority;
static int mca_patcher_linux_register (void)
{
mca_patcher_linux_priority = 13;
mca_base_component_var_register (&mca_patcher_linux_component.patcherc_version,
"priority", "Priority of the linux binary patcher component",
MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_CONSTANT, &mca_patcher_linux_priority);
return OPAL_SUCCESS;
}
static int mca_patcher_linux_query (mca_base_module_t **module, int *priority)
{
*module = &mca_patcher_linux_module.super;
*priority = mca_patcher_linux_priority;
return OPAL_SUCCESS;
}
mca_patcher_base_component_t mca_patcher_linux_component = {
.patcherc_version = {
OPAL_PATCHER_BASE_VERSION_1_0_0,
.mca_component_name = "linux",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
.mca_query_component = mca_patcher_linux_query,
.mca_register_component_params = mca_patcher_linux_register,
},
};

460
opal/mca/patcher/linux/patcher_linux_module.c Обычный файл
Просмотреть файл

@ -0,0 +1,460 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (C) Mellanox Technologies Ltd. 2001-2015. ALL RIGHTS RESERVED.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/*
* Copied from OpenUCX
*/
#include "patcher_linux.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/constants.h"
#include "opal/util/sys_limits.h"
#include "opal/util/output.h"
#include "opal/prefetch.h"
#if defined(HAVE_SYS_AUXV_H)
#include <sys/auxv.h>
#endif
#include <elf.h>
#include <sys/mman.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
static void *mca_patcher_linux_dlopen(const char *filename, int flag);
typedef struct mca_patcher_linux_elf_strtab {
char *tab;
ElfW(Xword) size;
} mca_patcher_linux_elf_strtab_t;
typedef struct mca_patcher_linux_elf_jmpreltab {
ElfW(Rela) *tab;
ElfW(Xword) size;
} mca_patcher_linux_elf_jmprel_t;
typedef struct mca_patcher_linux_elf_symtab {
ElfW(Sym) *tab;
ElfW(Xword) entsz;
} mca_patcher_linux_elf_symtab_t;
typedef struct mca_patcher_linux_dl_iter_context {
mca_patcher_linux_patch_t *patch;
bool remove;
int status;
} mca_patcher_linux_dl_iter_context_t;
OBJ_CLASS_INSTANCE(mca_patcher_linux_patch_got_t, opal_list_item_t, NULL, NULL);
static void mca_patcher_linux_patch_construct (mca_patcher_linux_patch_t *patch)
{
OBJ_CONSTRUCT(&patch->patch_got_list, opal_list_t);
}
static void mca_patcher_linux_patch_destruct (mca_patcher_linux_patch_t *patch)
{
OPAL_LIST_DESTRUCT(&patch->patch_got_list);
}
OBJ_CLASS_INSTANCE(mca_patcher_linux_patch_t, mca_patcher_base_patch_t, mca_patcher_linux_patch_construct,
mca_patcher_linux_patch_destruct);
/* List of patches to be applied to additional libraries */
static void *(*orig_dlopen) (const char *, int);
static const ElfW(Phdr) *
mca_patcher_linux_get_phdr_dynamic(const ElfW(Phdr) *phdr, uint16_t phnum, int phent)
{
for (uint16_t i = 0; i < phnum; ++i) {
if (phdr->p_type == PT_DYNAMIC) {
return phdr;
}
phdr = (ElfW(Phdr)*)((char*)phdr + phent);
}
return NULL;
}
static const ElfW(Dyn)*
mca_patcher_linux_get_dynentry(ElfW(Addr) base, const ElfW(Phdr) *pdyn, uint32_t type)
{
for (ElfW(Dyn) *dyn = (ElfW(Dyn)*)(base + pdyn->p_vaddr); dyn->d_tag; ++dyn) {
if (dyn->d_tag == type) {
return dyn;
}
}
return NULL;
}
static void mca_patcher_linux_get_jmprel(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_jmprel_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_JMPREL);
table->tab = (dyn == NULL) ? NULL : (ElfW(Rela)*)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_PLTRELSZ);
table->size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void mca_patcher_linux_get_symtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_symtab_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_SYMTAB);
table->tab = (dyn == NULL) ? NULL : (ElfW(Sym)*)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_SYMENT);
table->entsz = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void mca_patcher_linux_get_strtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
mca_patcher_linux_elf_strtab_t *table)
{
const ElfW(Dyn) *dyn;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_STRTAB);
table->tab = (dyn == NULL) ? NULL : (char *)dyn->d_un.d_ptr;
dyn = mca_patcher_linux_get_dynentry(base, pdyn, DT_STRSZ);
table->size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
}
static void * mca_patcher_linux_get_got_entry (ElfW(Addr) base, const ElfW(Phdr) *phdr, int16_t phnum,
int phent, const char *symbol)
{
mca_patcher_linux_elf_jmprel_t jmprel;
mca_patcher_linux_elf_symtab_t symtab;
mca_patcher_linux_elf_strtab_t strtab;
ElfW(Rela) *rela, *relaend;
const ElfW(Phdr) *dphdr;
const char *relsymname;
uint32_t relsymidx;
dphdr = mca_patcher_linux_get_phdr_dynamic (phdr, phnum, phent);
mca_patcher_linux_get_jmprel (base, dphdr, &jmprel);
mca_patcher_linux_get_symtab (base, dphdr, &symtab);
mca_patcher_linux_get_strtab (base, dphdr, &strtab);
relaend = (ElfW(Rela) *)((char *)jmprel.tab + jmprel.size);
for (rela = jmprel.tab; rela < relaend; ++rela) {
#if SIZEOF_VOID_P == 8
relsymidx = ELF64_R_SYM(rela->r_info);
#else
relsymidx = ELF32_R_SYM(rela->r_info);
#endif
relsymname = strtab.tab + symtab.tab[relsymidx].st_name;
if (!strcmp(symbol, relsymname)) {
return (void *)(base + rela->r_offset);
}
}
return NULL;
}
static int mca_patcher_linux_get_aux_phent (void)
{
#if !defined(HAVE_SYS_AUXV_H)
#define MCA_PATCHER_LINUX_AUXV_BUF_LEN 16
static const char *proc_auxv_filename = "/proc/self/auxv";
static int phent = 0;
#if SIZEOF_VOID_P == 8
Elf64_auxv_t buffer[MCA_PATCHER_LINUX_AUXV_BUF_LEN];
#else
Elf32_auxv_t buffer[MCA_PATCHER_LINUX_AUXV_BUF_LEN];
#endif
unsigned count;
ssize_t nread;
int fd;
/* Can avoid lock here - worst case we'll read the file more than once */
if (phent == 0) {
fd = open(proc_auxv_filename, O_RDONLY);
if (fd < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to open '%s' for reading: %s", proc_auxv_filename,
strerror (errno));
return OPAL_ERROR;
}
/* Use small buffer on the stack, avoid using malloc() */
do {
nread = read(fd, buffer, sizeof(buffer));
if (nread < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to read %lu bytes from %s (ret=%ld): %s", sizeof (buffer),
proc_auxv_filename, nread, strerror (errno));
break;
}
count = nread / sizeof(buffer[0]);
for (unsigned i = 0 ; i < count && AT_NULL != buffer[i].a_type ; ++i) {
if (AT_PHENT == buffer[i].a_type) {
phent = buffer[i].a_un.a_val;
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"read phent from %s: %d", proc_auxv_filename, phent);
break;
}
}
} while ((count > 0) && (phent == 0));
close(fd);
}
return phent;
#else
return getauxval (AT_PHENT);
#endif
}
static int
mca_patcher_linux_modify_got (ElfW(Addr) base, const ElfW(Phdr) *phdr, const char *phname,
int16_t phnum, int phent, mca_patcher_linux_dl_iter_context_t *ctx)
{
long page_size = opal_getpagesize ();
void **entry;
void *page;
int ret;
entry = mca_patcher_linux_get_got_entry (base, phdr, phnum, phent, ctx->patch->super.patch_symbol);
if (entry == NULL) {
return OPAL_SUCCESS;
}
page = (void *)((intptr_t)entry & ~(page_size - 1));
ret = mprotect(page, page_size, PROT_READ|PROT_WRITE);
if (ret < 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to modify GOT page %p to rw: %s", page, strerror (errno));
return OPAL_ERR_NOT_SUPPORTED;
}
if (!ctx->remove) {
if (*entry != (void *) ctx->patch->super.patch_value) {
mca_patcher_linux_patch_got_t *patch_got = OBJ_NEW(mca_patcher_linux_patch_got_t);
if (NULL == patch_got) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
opal_output_verbose (MCA_BASE_VERBOSE_TRACE, opal_patcher_base_framework.framework_output,
"patch %p (%s): modifying got entry %p. original value %p. new value %p\n", ctx->patch,
ctx->patch->super.patch_symbol, (void *) entry, *entry, (void *) ctx->patch->super.patch_value);
patch_got->got_entry = entry;
patch_got->got_orig = *entry;
opal_list_append (&ctx->patch->patch_got_list, &patch_got->super);
*entry = (void *) ctx->patch->super.patch_value;
}
} else {
if (*entry == (void *) ctx->patch->super.patch_value) {
/* find the appropriate entry and restore the original value */
mca_patcher_linux_patch_got_t *patch_got;
OPAL_LIST_FOREACH_REV(patch_got, &ctx->patch->patch_got_list, mca_patcher_linux_patch_got_t) {
if (patch_got->got_entry == entry) {
opal_output_verbose (MCA_BASE_VERBOSE_TRACE, opal_patcher_base_framework.framework_output,
"restoring got entry %p with original value %p\n", (void *) entry, patch_got->got_orig);
*entry = patch_got->got_orig;
opal_list_remove_item (&ctx->patch->patch_got_list, &patch_got->super);
OBJ_RELEASE(patch_got);
break;
}
}
}
}
return OPAL_SUCCESS;
}
static int mca_patcher_linux_phdr_iterator(struct dl_phdr_info *info, size_t size, void *data)
{
mca_patcher_linux_dl_iter_context_t *ctx = data;
int phent;
phent = mca_patcher_linux_get_aux_phent();
if (phent <= 0) {
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"failed to read phent size");
ctx->status = OPAL_ERR_NOT_SUPPORTED;
return -1;
}
ctx->status = mca_patcher_linux_modify_got (info->dlpi_addr, info->dlpi_phdr,
info->dlpi_name, info->dlpi_phnum,
phent, ctx);
if (ctx->status == OPAL_SUCCESS) {
return 0; /* continue iteration and patch all objects */
} else {
return -1; /* stop iteration if got a real error */
}
}
/* called with lock held */
static int mca_patcher_linux_apply_patch (mca_patcher_linux_patch_t *patch)
{
mca_patcher_linux_dl_iter_context_t ctx = {
.patch = patch,
.remove = false,
.status = OPAL_SUCCESS,
};
/* Avoid locks here because we don't modify ELF data structures.
* Worst case the same symbol will be written more than once.
*/
(void)dl_iterate_phdr(mca_patcher_linux_phdr_iterator, &ctx);
if (ctx.status == OPAL_SUCCESS) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"modified '%s' to 0x%lx", ctx.patch->super.patch_symbol, ctx.patch->super.patch_value);
}
return ctx.status;
}
static int mca_patcher_linux_remove_patch (mca_patcher_linux_patch_t *patch)
{
mca_patcher_linux_dl_iter_context_t ctx = {
.patch = patch,
.remove = true,
.status = OPAL_SUCCESS,
};
/* Avoid locks here because we don't modify ELF data structures.
* Worst case the same symbol will be written more than once.
*/
(void)dl_iterate_phdr(mca_patcher_linux_phdr_iterator, &ctx);
if (ctx.status == OPAL_SUCCESS) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"modified '%s' to 0x%lx", ctx.patch->super.patch_symbol, ctx.patch->super.patch_value);
}
return ctx.status;
}
static void *mca_patcher_linux_dlopen(const char *filename, int flag)
{
OPAL_PATCHER_BEGIN;
mca_patcher_linux_patch_t *patch;
void *handle;
assert (orig_dlopen);
handle = orig_dlopen (filename, flag);
if (handle != NULL) {
/*
* Every time a new object is loaded, we must update its relocations
* with our list of patches (including dlopen itself). This code is less
* efficient and will modify all existing objects every time, but good
* enough.
*/
opal_mutex_lock (&mca_patcher_linux_module.patch_list_mutex);
OPAL_LIST_FOREACH(patch, &mca_patcher_linux_module.patch_list, mca_patcher_linux_patch_t) {
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"in dlopen(), re-applying '%s' to %p", patch->super.patch_symbol, (void *) patch->super.patch_value);
/* ignore hook binary patches */
if (!patch->super.patch_data_size) {
mca_patcher_linux_apply_patch (patch);
}
}
opal_mutex_unlock (&mca_patcher_linux_module.patch_list_mutex);
}
OPAL_PATCHER_END;
return handle;
}
static intptr_t mca_patcher_linux_get_orig (const char *symbol, void *replacement)
{
const char *error;
void *func_ptr;
func_ptr = dlsym(RTLD_DEFAULT, symbol);
if (func_ptr == replacement) {
(void)dlerror();
func_ptr = dlsym(RTLD_NEXT, symbol);
if (func_ptr == NULL) {
error = dlerror();
opal_output_verbose (MCA_BASE_VERBOSE_ERROR, opal_patcher_base_framework.framework_output,
"could not find address of original %s(): %s", symbol, error ? error : "Unknown error");
}
}
opal_output_verbose (MCA_BASE_VERBOSE_INFO, opal_patcher_base_framework.framework_output,
"original %s() is at %p", symbol, func_ptr);
return (intptr_t) func_ptr;
}
static int mca_patcher_linux_patch_symbol (const char *symbol_name, uintptr_t replacement, uintptr_t *orig)
{
mca_patcher_linux_patch_t *patch = OBJ_NEW(mca_patcher_linux_patch_t);
int rc;
if (OPAL_UNLIKELY(NULL == patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->super.patch_symbol = strdup (symbol_name);
if (NULL == patch->super.patch_symbol) {
OBJ_RELEASE(patch);
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->super.patch_value = mca_patcher_base_addr_text (replacement);
patch->super.patch_restore = (mca_patcher_base_restore_fn_t) mca_patcher_linux_remove_patch;
/* Take lock first to handle a possible race where dlopen() is called
* from another thread and we may end up not patching it.
*/
opal_mutex_lock (&mca_patcher_linux_module.patch_list_mutex);
do {
rc = mca_patcher_base_patch_hook (&mca_patcher_linux_module, patch->super.patch_value);
if (OPAL_SUCCESS != rc) {
OBJ_RELEASE(patch);
break;
}
rc = mca_patcher_linux_apply_patch (patch);
if (OPAL_SUCCESS != rc) {
OBJ_RELEASE(patch);
break;
}
*orig = mca_patcher_linux_get_orig (patch->super.patch_symbol, (void *) replacement);
opal_list_append (&mca_patcher_linux_module.patch_list, &patch->super.super);
} while (0);
opal_mutex_unlock (&mca_patcher_linux_module.patch_list_mutex);
return rc;
}
/* called with lock held */
static int mca_patcher_linux_install_dlopen (void)
{
return mca_patcher_linux_patch_symbol ("dlopen", (uintptr_t) mca_patcher_linux_dlopen,
(uintptr_t *) &orig_dlopen);
}
static int mca_patcher_linux_init (void)
{
return mca_patcher_linux_install_dlopen ();
}
mca_patcher_base_module_t mca_patcher_linux_module = {
.patch_init = mca_patcher_linux_init,
.patch_symbol = mca_patcher_linux_patch_symbol,
};

47
opal/mca/patcher/overwrite/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,47 @@
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
if MCA_BUILD_opal_patcher_overwrite_DSO
component_noinst =
component_install = mca_patcher_overwrite.la
else
component_noinst = libmca_patcher_overwrite.la
component_install =
endif
overwrite_SOURCES = \
patcher_overwrite.h \
patcher_overwrite_module.c \
patcher_overwrite_component.c
mcacomponentdir = $(opallibdir)
mcacomponent_LTLIBRARIES = $(component_install)
mca_patcher_overwrite_la_SOURCES = $(overwrite_SOURCES)
nodist_mca_patcher_overwrite_la_SOURCES = $(overwrite_nodist_SOURCES)
mca_patcher_overwrite_la_LDFLAGS = -module -avoid-version
noinst_LTLIBRARIES = $(component_noinst)
libmca_patcher_overwrite_la_SOURCES = $(overwrite_SOURCES)
nodist_libmca_patcher_overwrite_la_SOURCES = $(overwrite_nodist_SOURCES)
libmca_patcher_overwrite_la_LIBADD = $(patcher_overwrite_LIBS)
libmca_patcher_overwrite_la_LDFLAGS = -module -avoid-version

41
opal/mca/patcher/overwrite/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,41 @@
# -*- shell-script -*-
#
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
# University Research and Technology
# Corporation. All rights reserved.
# Copyright (c) 2004-2005 The University of Tennessee and The University
# of Tennessee Research Foundation. All rights
# reserved.
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
# MCA_patcher_overwrite_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_patcher_overwrite_CONFIG],[
AC_CONFIG_FILES([opal/mca/patcher/overwrite/Makefile])
opal_patcher_overwrite_happy=no
if test $OPAL_ENABLE_DLOPEN_SUPPORT = 1; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__ia64__) && !defined(__PPC__)
#error "platform not supported"
#endif
]],[])],[opal_patcher_overwrite_happy=yes],[])
fi
AS_IF([test $opal_patcher_overwrite_happy = yes], [$1], [$2])
])

Просмотреть файл

@ -0,0 +1,32 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/**
* @file pather_overwrite.h
*
* This component works by overwritting the first couple instructions in
* the target function with a jump instruction to the hook function. The
* hook function will be expected to implement the functionality of the
* hooked function when using this module.
*
* Note: This component only supports x86, x86_64, ia64, and powerpc/power.
*/
#if !defined(OPAL_PATCHER_OVERWRITE_H)
#define OPAL_PATCHER_OVERWRITE_H
#include "opal_config.h"
#include "opal/mca/patcher/patcher.h"
#include "opal/class/opal_list.h"
extern mca_patcher_base_module_t mca_patcher_overwrite_module;
extern mca_patcher_base_component_t mca_patcher_overwrite_component;
#endif /* !defined(OPAL_PATCHER_OVERWRITE_H) */

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "patcher_overwrite.h"
#include "opal/mca/mca.h"
#include "opal/mca/base/base.h"
static int mca_patcher_overwrite_priority;
static int mca_patcher_overwrite_register (void)
{
mca_patcher_overwrite_priority = 37;
mca_base_component_var_register (&mca_patcher_overwrite_component.patcherc_version,
"priority", "Priority of the overwrite binary patcher component",
MCA_BASE_VAR_TYPE_INT, NULL, 0, 0, OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_CONSTANT, &mca_patcher_overwrite_priority);
return OPAL_SUCCESS;
}
static int mca_patcher_overwrite_query (mca_base_module_t **module, int *priority)
{
*module = &mca_patcher_overwrite_module.super;
*priority = mca_patcher_overwrite_priority;
return OPAL_SUCCESS;
}
mca_patcher_base_component_t mca_patcher_overwrite_component = {
.patcherc_version = {
OPAL_PATCHER_BASE_VERSION_1_0_0,
.mca_component_name = "overwrite",
MCA_BASE_MAKE_VERSION(component, OPAL_MAJOR_VERSION, OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION),
.mca_query_component = mca_patcher_overwrite_query,
.mca_register_component_params = mca_patcher_overwrite_register,
},
};

Просмотреть файл

@ -0,0 +1,307 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* ******** ADD IBM COPYRIGHT HERE ******
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "patcher_overwrite.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/constants.h"
#include "opal/util/sys_limits.h"
#include "opal/util/output.h"
#include "opal/prefetch.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <assert.h>
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
#if defined(__ia64__)
#define INSERT_BIT(d,p,v) do { \
unsigned char c=*(d); \
assert(((p) < 8) && ((p) >= 0)); \
c&= ~(1<<(p)); \
c|= ((v)<<(p)); \
*(d) = c; \
} while (0)
static inline void
copy_instr_slot(unsigned char **dst, int *dst_bitpos, unsigned long instr_slot)
{
for (int i = 40 ; i >= 0 ; --i) {
INSERT_BIT(*dst, *dst_bitpos, (instr_slot>>i)&1);
if (*dst_bitpos == 0) {
++*dst;
*dst_bitpos = 7;
} else {
--*dst_bitpos;
}
}
}
static void make_ia64_bundle (unsigned char *dst,
unsigned long i2,
unsigned long i1,
unsigned long i0,
unsigned template)
{
/*
* each instr is 41 bits, template is 5 bits
*
* generate the bit concatenation of i2:i1:i0:t, all in all 128 bits
*
*/
int dst_bitpos = 7;
copy_instr_slot(&dst, &dst_bitpos, i2);
copy_instr_slot(&dst, &dst_bitpos, i1);
copy_instr_slot(&dst, &dst_bitpos, i0);
assert(dst_bitpos == 4);
for (int i = 4 ; i >= 0 ; --i) {
INSERT_BIT(dst, dst_bitpos, (template>>i)&1);
--dst_bitpos;
}
}
#endif /* defined(__ia64__) */
static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
{
uintptr_t func_new_addr = patch->patch_value;
{
#if defined(__i386__)
patch->patch_data_size = 5;
*(unsigned char *)(patch->patch_data+0) = 0xe9;
*(unsigned int *) (patch->patch_data+1) = (unsigned int)(func_new_addr - func_old_addr - 5);
#elif defined(__x86_64__)
patch->patch_data_size = 13;
*(unsigned short*)(patch->patch_data + 0) = 0xbb49;
*(unsigned long* )(patch->patch_data + 2) = (unsigned long) func_new_addr;
*(unsigned char*) (patch->patch_data +10) = 0x41;
*(unsigned char*) (patch->patch_data +11) = 0xff;
*(unsigned char*) (patch->patch_data +12) = 0xe3;
#elif defined(__ia64__)
{
/*
* target64 = IP + ((i << 59 | imm39 << 20 | imm20) << 4)
* imm64 = i << 63 | imm41 << 22 | ic << 21 | imm5c << 16 | imm9d << 7 | imm7b
*/
unsigned char buf[16];
unsigned long long imm64 = func_new_addr - func_old_addr - 16;
register unsigned long long glb_ptr __asm__("r1");
unsigned long long nop =
(0x0ULL<<37) | /* O */
(0x0ULL<<36) | /* i */
(0x0ULL<<33) | /* x3 */
(0x1ULL<<27) | /* x6 */
(0x0ULL<< 6) | /* imm20 */
(0x0ULL<< 0); /* qp */
unsigned long long brl =
(0xcULL << 37) |
(((imm64>>63)&0x1ULL) << 36) |
(0x0ULL << 35) |
(0x0ULL << 33) |
(((imm64>>4)&0xFFFFFULL) << 13) |
(0x0ULL << 6) |
(0x0ULL << 0);
unsigned long long movl =
(0x6ULL << 37) |
(((glb_ptr>>63)&0x1ULL) << 36) |
(((glb_ptr>> 7)&0x1FFULL) << 27) |
(((glb_ptr>>16)&0x1FULL) << 22) |
(((glb_ptr>>21)&0x1ULL) << 21) |
(0ULL << 20) |
(((glb_ptr>> 0)&0x7FULL) << 13) |
(1ULL << 6) |
(0x0ULL << 0);
patch->data_size = 32;
make_ia64_bundle(buf, movl, (glb_ptr>>22)&0x1FFFFFFFFFFULL, nop, 5);
for (int i = 0 ; i < 16 ; ++i) {
patch->patch_data[16-i-1] = buf[i];
}
make_ia64_bundle(buf, brl, ((imm64>>24)&0x7FFFFFFFFFULL)<<2, nop, 5);
for (int i = 0 ; i < 16 ; ++i) {
patch->patch_data[32-i-1] = buf[i];
}
}
#endif
}
mca_base_patcher_patch_apply_binary (patch);
return OPAL_SUCCESS;
}
/* end of #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) */
// ------------------------------------------------- PPC equivalent:
#elif defined(__PPC__)
// PowerPC instructions used in patching
// Reference: "PowerPC User Instruction Set Architecture"
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) {
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff);
}
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) {
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) {
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff);
}
static unsigned int mtspr(unsigned int SPR, unsigned int RS) {
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1);
}
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) {
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1);
}
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB)
{
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1)
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2);
}
static int
PatchLoadImm(uintptr_t addr, unsigned int reg, size_t value)
{
#if defined(__PPC64__)
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 48));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 32));
*(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31);
*(unsigned int *) (addr +12) = oris ( reg, reg, (value >> 16));
*(unsigned int *) (addr +16) = ori ( reg, reg, (value >> 0));
return 20;
#else
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 16));
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 0));
return 8;
#endif
}
static int mca_patcher_overwrite_apply_patch (mca_patcher_base_patch_t *patch)
{
uintptr_t sys_addr, hook_addr;
int offset, rc;
// get system function address
sys_addr = mca_patcher_base_addr_text(patch->patch_orig);
hook_addr = mca_patcher_base_addr_text(patch->patch_value);
// Patch for hook function:
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__))
rc = mca_patcher_base_patch_hook (&mca_patcher_overwrite_module, hook_addr);
if (OPAL_SUCCESS != rc) {
return rc;
}
#if _CALL_ELF == 2
sys_addr += 8;
hook_addr += 8;
#endif /* _CALL_ELF == 2*/
#endif
// Patch for system function:
// generate patch code
// r11 is a volatile register according to PowerPC EABI
const unsigned int gr = 11;
offset = PatchLoadImm ((uintptr_t) patch->patch_data, gr, hook_addr);
*(unsigned int *) (patch->patch_data + offset + 0) = mtspr (9, gr); // 9 = CTR
*(unsigned int *) (patch->patch_data + offset + 4) = bcctr (20, 0, 0);// 20 = always
patch->patch_data_size = offset + 8;
patch->patch_orig = sys_addr;
mca_base_patcher_patch_apply_binary (patch);
return OPAL_SUCCESS;
}
#endif
static int mca_patcher_overwrite_patch_address (uintptr_t sys_addr, unsigned long hook_addr)
{
mca_patcher_base_patch_t *patch;
int rc;
patch = OBJ_NEW(mca_patcher_base_patch_t);
if (OPAL_UNLIKELY(NULL == patch)) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
patch->patch_orig = sys_addr;
patch->patch_value = hook_addr;
opal_mutex_lock (&mca_patcher_overwrite_module.patch_list_mutex);
do {
rc = mca_patcher_overwrite_apply_patch (patch);
if (OPAL_SUCCESS != rc) {
break;
}
opal_list_append (&mca_patcher_overwrite_module.patch_list, &patch->super);
} while (0);
opal_mutex_unlock (&mca_patcher_overwrite_module.patch_list_mutex);
return OPAL_SUCCESS;
}
static int mca_patcher_overwrite_patch_symbol (const char *func_symbol_name, uintptr_t func_new_addr,
uintptr_t *func_old_addr)
{
void *sym_addr;
char *error;
uintptr_t old_addr;
/* NTH: might want to update opal/mca/dl to handle lookups in the default
* handle. */
sym_addr = dlsym (RTLD_NEXT, func_symbol_name);
if (NULL == sym_addr) {
sym_addr = dlsym(RTLD_DEFAULT, func_symbol_name);
if ( (sym_addr == NULL) && ((error = dlerror()) != NULL) ) {
opal_output(0, "error locating symbol %s to patch. %s", func_symbol_name,
error);
return OPAL_ERR_NOT_FOUND;
}
}
old_addr = (unsigned long)sym_addr;
#if defined(__ia64__)
/* On IA64 addresses are all indirect */
func_new_addr = *(unsigned long *)func_new_addr;
old_addr = *(unsigned long *) old_addr;
#endif
if (func_old_addr) {
/* we will be overwritting part of the original function. do not return
* its address */
*func_old_addr = 0;
}
return mca_patcher_overwrite_patch_address (old_addr, func_new_addr);
}
mca_patcher_base_module_t mca_patcher_overwrite_module = {
.patch_symbol = mca_patcher_overwrite_patch_symbol,
.patch_address = mca_patcher_overwrite_patch_address,
};

121
opal/mca/patcher/patcher.h Обычный файл
Просмотреть файл

@ -0,0 +1,121 @@
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OPAL_MCA_PATCHER_PATCHER_H
#define OPAL_MCA_PATCHER_PATCHER_H
#include "opal_config.h"
#include "opal/mca/mca.h"
#include "opal/mca/base/base.h"
#include "opal/class/opal_list.h"
/* Any function being patched in as a hook must use SYMBOLPATCH_BEGIN at the top,
* and SYMBOLPATCH_END before it returns (this is just for PPC). */
#if (defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__)) && defined(OPAL_GCC_INLINE_ASSEMBLY)
/* special processing for ppc64 to save and restore TOC (r2)
* Reference: "64-bit PowerPC ELF Application Binary Interface Supplement 1.9" */
#define OPAL_PATCHER_BEGIN \
unsigned long toc_save; \
asm volatile ("std 2, %0" : "=m" (toc_save)); \
asm volatile ("nop; nop; nop; nop; nop");
#define OPAL_PATCHER_END \
asm volatile ("ld 2, %0" : : "m" (toc_save));
#else /* !__PPC64__ */
#define OPAL_PATCHER_BEGIN
#define OPAL_PATCHER_END
#endif
/**
* Make any calls to the named function redirect to a new function
*
* @param[in] func_symbol_name function to hook
* @param[in] func_new_addr function pointer of hook
* @param[out] func_old_addr address of func_symbol_name
*
* This function redirects all calls to the function func_symbol_name to
* the function pointer func_new_addr. If it is possible for the hook
* function to call the original function the patcher module will return
* the old function's address in func_old_addr.
*/
typedef int (*mca_patcher_base_patch_symbol_fn_t)(const char *func_symbol_name, uintptr_t func_new_addr,
uintptr_t *func_old_addr);
/**
* Make any calls to a function redirect to a new function
*
* @param[in] func_symbol_name function to hook
* @param[in] func_new_addr function pointer of hook
* @param[out] func_old_addr address of func_symbol_name
*
* This function redirects all calls to the function at func_addr to
* the function pointer func_new_addr.
*/
typedef int (*mca_patcher_base_patch_address_fn_t)(uintptr_t func_addr, uintptr_t func_new_addr);
/**
* Set up the patcher module
*/
typedef int (*mca_patcher_base_init_fn_t) (void);
/**
* Finalize the patcher module
*/
typedef int (*mca_patcher_base_fini_fn_t) (void);
/**
* Structure for patcher modules.
*/
typedef struct mca_patcher_base_module_t {
mca_base_module_t super;
/** list of patches */
opal_list_t patch_list;
/** lock for patch list */
opal_mutex_t patch_list_mutex;
/** function to call if the patcher module is used. can
* be NULL. */
mca_patcher_base_init_fn_t patch_init;
/** function to call when patcher is unloaded. this function
* MUST clean up all active patches. can be NULL. */
mca_patcher_base_fini_fn_t patch_fini;
/** hook a symbol. may be NULL */
mca_patcher_base_patch_symbol_fn_t patch_symbol;
/** hook a function pointer. may be NULL */
mca_patcher_base_patch_address_fn_t patch_address;
} mca_patcher_base_module_t;
OPAL_DECLSPEC extern mca_patcher_base_module_t *opal_patcher;
/**
* Structure for patcher components.
*/
typedef struct mca_patcher_base_component_1_0_0_t {
/** MCA base component */
mca_base_component_t patcherc_version;
/** MCA base data */
mca_base_component_data_t patcherc_data;
} mca_patcher_base_component_1_0_0_t;
typedef mca_patcher_base_component_1_0_0_t mca_patcher_base_component_t;
/*
* Macro for use in components that are of type patcher
*/
#define OPAL_PATCHER_BASE_VERSION_1_0_0 \
OPAL_MCA_BASE_VERSION_2_1_0("patcher", 1, 0, 0)
#endif /* OPAL_MCA_PATCHER_PATCHER_H */

Просмотреть файл

@ -29,6 +29,7 @@
#include "opal/class/opal_list.h" #include "opal/class/opal_list.h"
#include "opal/mca/mca.h" #include "opal/mca/mca.h"
#include "opal/mca/rcache/rcache.h" #include "opal/mca/rcache/rcache.h"
#include "opal/mca/memory/base/base.h"
BEGIN_C_DECLS BEGIN_C_DECLS

Просмотреть файл

@ -43,6 +43,45 @@ mca_rcache_base_module_t* mca_rcache_base_module_create (const char* name, void
mca_base_component_list_item_t *cli; mca_base_component_list_item_t *cli;
mca_rcache_base_selected_module_t *sm; mca_rcache_base_selected_module_t *sm;
/* on the very first creation of a module we init the memory
callback */
if (!mca_rcache_base_used_mem_hooks) {
/* Use the memory hooks if leave_pinned or
* leave_pinned_pipeline is enabled (note that either of these
* leave_pinned variables may have been set by a user MCA
* param or elsewhere in the code base). Yes, we could havexc
* coded this more succinctly, but this is more clear. Do not
* check memory hooks if the rcache does not provide an
* range invalidation function.. */
if (opal_leave_pinned != 0 || opal_leave_pinned_pipeline) {
/* open the memory manager components. Memory hooks may be
triggered before this (any time after mem_free_init(),
actually). This is a hook available for memory manager hooks
without good initialization routine support */
(void) mca_base_framework_open (&opal_memory_base_framework, 0);
}
if (opal_leave_pinned != 0 || opal_leave_pinned_pipeline) {
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) &
opal_mem_hooks_support_level())) {
if (-1 == opal_leave_pinned) {
opal_leave_pinned = !opal_leave_pinned_pipeline;
}
opal_mem_hooks_register_release(mca_rcache_base_mem_cb, NULL);
} else {
opal_show_help("help-rcache-base.txt", "leave pinned failed",
true, name, OPAL_NAME_PRINT(OPAL_PROC_MY_NAME),
opal_proc_local_get()->proc_hostname);
return NULL;
}
/* Set this to true so that rcache_base_close knows to
cleanup */
mca_rcache_base_used_mem_hooks = 1;
}
}
OPAL_LIST_FOREACH(cli, &opal_rcache_base_framework.framework_components, mca_base_component_list_item_t) { OPAL_LIST_FOREACH(cli, &opal_rcache_base_framework.framework_components, mca_base_component_list_item_t) {
component = (mca_rcache_base_component_t *) cli->cli_component; component = (mca_rcache_base_component_t *) cli->cli_component;
if(0 == strcmp(component->rcache_version.mca_component_name, name)) { if(0 == strcmp(component->rcache_version.mca_component_name, name)) {
@ -61,35 +100,6 @@ mca_rcache_base_module_t* mca_rcache_base_module_create (const char* name, void
sm->user_data = user_data; sm->user_data = user_data;
opal_list_append(&mca_rcache_base_modules, (opal_list_item_t*) sm); opal_list_append(&mca_rcache_base_modules, (opal_list_item_t*) sm);
/* on the very first creation of a module we init the memory
callback */
if (!mca_rcache_base_used_mem_hooks) {
/* Use the memory hooks if leave_pinned or
* leave_pinned_pipeline is enabled (note that either of these
* leave_pinned variables may have been set by a user MCA
* param or elsewhere in the code base). Yes, we could havexc
* coded this more succinctly, but this is more clear. Do not
* check memory hooks if the rcache does not provide an
* range invalidation function.. */
if ((opal_leave_pinned > 0 || opal_leave_pinned_pipeline) &&
module->rcache_invalidate_range) {
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) &
opal_mem_hooks_support_level())) {
opal_mem_hooks_register_release(mca_rcache_base_mem_cb, NULL);
} else {
opal_show_help("help-rcache-base.txt", "leave pinned failed",
true, name, OPAL_NAME_PRINT(OPAL_PROC_MY_NAME),
opal_proc_local_get()->proc_hostname);
return NULL;
}
/* Set this to true so that rcache_base_close knows to
cleanup */
mca_rcache_base_used_mem_hooks = 1;
}
}
return module; return module;
} }

Просмотреть файл

@ -10,7 +10,7 @@
* University of Stuttgart. All rights reserved. * University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California. * Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved. * All rights reserved.
* Copyright (c) 2012-2013 Los Alamos National Security, LLC. * Copyright (c) 2012-2016 Los Alamos National Security, LLC.
* All rights reserved * All rights reserved
* Copyright (c) 2015-2016 Research Organization for Information Science * Copyright (c) 2015-2016 Research Organization for Information Science
* and Technology (RIST). All rights reserved. * and Technology (RIST). All rights reserved.
@ -92,6 +92,13 @@ static int mca_rcache_base_close(void)
/* deregister memory free callback */ /* deregister memory free callback */
if (mca_rcache_base_used_mem_hooks) { if (mca_rcache_base_used_mem_hooks) {
opal_mem_hooks_unregister_release(mca_rcache_base_mem_cb); opal_mem_hooks_unregister_release(mca_rcache_base_mem_cb);
/* close the memory manager components. Registered hooks can
still be fired any time between now and the call to
opal_mem_free_finalize(), and callbacks from the memory manager
hooks to the bowels of the mem_free code can still occur any
time between now and end of application (even post main()!) */
(void) mca_base_framework_close (&opal_memory_base_framework);
} }
/* All done */ /* All done */

Просмотреть файл

@ -106,7 +106,7 @@ opal_mem_hooks_set_support(int support)
void void
opal_mem_hooks_release_hook(void *buf, size_t length, bool from_alloc) opal_mem_hooks_release_hook(void *buf, size_t length, bool from_alloc)
{ {
opal_list_item_t *item; callback_list_item_t *cbitem, *next;
if (!release_run_callbacks) return; if (!release_run_callbacks) return;
@ -121,12 +121,7 @@ opal_mem_hooks_release_hook(void *buf, size_t length, bool from_alloc)
*/ */
opal_atomic_lock(&release_lock); opal_atomic_lock(&release_lock);
item = opal_list_get_first(&release_cb_list); OPAL_LIST_FOREACH_SAFE(cbitem, next, &release_cb_list, callback_list_item_t) {
while(item != opal_list_get_end(&release_cb_list)) {
opal_list_item_t* next = opal_list_get_next(item);
callback_list_item_t *cbitem = (callback_list_item_t*) item;
item = next;
opal_atomic_unlock(&release_lock); opal_atomic_unlock(&release_lock);
cbitem->cbfunc(buf, length, cbitem->cbdata, (bool) from_alloc); cbitem->cbfunc(buf, length, cbitem->cbdata, (bool) from_alloc);
opal_atomic_lock(&release_lock); opal_atomic_lock(&release_lock);

Просмотреть файл

@ -40,7 +40,7 @@
#include "opal/mca/installdirs/base/base.h" #include "opal/mca/installdirs/base/base.h"
#include "opal/mca/memchecker/base/base.h" #include "opal/mca/memchecker/base/base.h"
#include "opal/mca/memcpy/base/base.h" #include "opal/mca/memcpy/base/base.h"
#include "opal/mca/memory/base/base.h" #include "opal/mca/patcher/base/base.h"
#include "opal/mca/backtrace/base/base.h" #include "opal/mca/backtrace/base/base.h"
#include "opal/mca/sec/base/base.h" #include "opal/mca/sec/base/base.h"
#include "opal/mca/timer/base/base.h" #include "opal/mca/timer/base/base.h"
@ -153,13 +153,7 @@ opal_finalize(void)
(void) mca_base_framework_close(&opal_backtrace_base_framework); (void) mca_base_framework_close(&opal_backtrace_base_framework);
(void) mca_base_framework_close(&opal_memchecker_base_framework); (void) mca_base_framework_close(&opal_memchecker_base_framework);
(void) mca_base_framework_close(&opal_patcher_base_framework);
/* close the memory manager components. Registered hooks can
still be fired any time between now and the call to
opal_mem_free_finalize(), and callbacks from the memory manager
hooks to the bowels of the mem_free code can still occur any
time between now and end of application (even post main()!) */
(void) mca_base_framework_close(&opal_memory_base_framework);
/* close the memcpy framework */ /* close the memcpy framework */
(void) mca_base_framework_close(&opal_memcpy_base_framework); (void) mca_base_framework_close(&opal_memcpy_base_framework);

Просмотреть файл

@ -45,6 +45,7 @@
#include "opal/datatype/opal_datatype.h" #include "opal/datatype/opal_datatype.h"
#include "opal/mca/installdirs/base/base.h" #include "opal/mca/installdirs/base/base.h"
#include "opal/mca/memory/base/base.h" #include "opal/mca/memory/base/base.h"
#include "opal/mca/patcher/base/base.h"
#include "opal/mca/memcpy/base/base.h" #include "opal/mca/memcpy/base/base.h"
#include "opal/mca/hwloc/base/base.h" #include "opal/mca/hwloc/base/base.h"
#include "opal/mca/sec/base/base.h" #include "opal/mca/sec/base/base.h"
@ -430,15 +431,14 @@ opal_init(int* pargc, char*** pargv)
goto return_error; goto return_error;
} }
/* open the memory manager components. Memory hooks may be if (OPAL_SUCCESS != (ret = mca_base_framework_open(&opal_patcher_base_framework, 0))) {
triggered before this (any time after mem_free_init(), error = "opal_patcher_base_open";
actually). This is a hook available for memory manager hooks
without good initialization routine support */
if (OPAL_SUCCESS != (ret = mca_base_framework_open(&opal_memory_base_framework, 0))) {
error = "opal_memory_base_open";
goto return_error; goto return_error;
} }
/* select a patcher module. if a patcher module can not be found it is not an error. */
(void) opal_patcher_base_select ();
/* initialize the memory manager / tracker */ /* initialize the memory manager / tracker */
if (OPAL_SUCCESS != (ret = opal_mem_hooks_init())) { if (OPAL_SUCCESS != (ret = opal_mem_hooks_init())) {
error = "opal_mem_hooks_init"; error = "opal_mem_hooks_init";

Просмотреть файл

@ -12,6 +12,8 @@
# Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2013 NVIDIA Corporation. All rights reserved. # Copyright (c) 2013 NVIDIA Corporation. All rights reserved.
# Copyright (c) 2013 Intel, Inc. All rights reserved # Copyright (c) 2013 Intel, Inc. All rights reserved
# Copyright (c) 2016 Los Alamos National Security, LLC. All rights
# reserved.
# $COPYRIGHT$ # $COPYRIGHT$
# #
# Additional copyrights may follow # Additional copyrights may follow