1
1

* update memory hooks interface to allow for callbacks on both allocations

and dealllocations, per request from Galen and Tim

This commit was SVN r8303.
Этот коммит содержится в:
Brian Barrett 2005-11-29 04:46:14 +00:00
родитель 5e0c779974
Коммит 79bf8843d2
19 изменённых файлов: 528 добавлений и 147 удалений

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

@ -59,8 +59,9 @@ int mca_mpool_base_close(void)
&mca_mpool_base_components, NULL); &mca_mpool_base_components, NULL);
/* deregister memory free callback */ /* deregister memory free callback */
if(mca_mpool_base_use_mem_hooks && opal_mem_free_is_supported()) { if(mca_mpool_base_use_mem_hooks &&
opal_mem_free_unregister_handler(mca_mpool_base_mem_cb); 0 != (OPAL_MEMORY_FREE_SUPPORT & opal_mem_hooks_support_level())) {
opal_mem_hooks_unregister_release(mca_mpool_base_mem_cb);
} }
/* All done */ /* All done */

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

@ -84,8 +84,8 @@ mca_mpool_base_module_t* mca_mpool_base_module_create(
/* on the very first creation of a module we init the memory callback*/ /* on the very first creation of a module we init the memory callback*/
if(mca_mpool_base_use_mem_hooks && if(mca_mpool_base_use_mem_hooks &&
opal_list_get_size(&mca_mpool_base_modules) == 1 && opal_list_get_size(&mca_mpool_base_modules) == 1 &&
opal_mem_free_is_supported()) { 0 != (OPAL_MEMORY_FREE_SUPPORT & opal_mem_hooks_support_level())) {
opal_mem_free_register_handler(mca_mpool_base_mem_cb, NULL); opal_mem_hooks_register_release(mca_mpool_base_mem_cb, NULL);
} }
return module; return module;
} }

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

@ -65,6 +65,8 @@ AC_DEFUN([MCA_memory_darwin_CONFIG],[
[AC_MSG_ERROR([Darwin memory management requested but not available. Aborting.])]) [AC_MSG_ERROR([Darwin memory management requested but not available. Aborting.])])
AS_IF([test "$memory_darwin_happy" = "yes"], AS_IF([test "$memory_darwin_happy" = "yes"],
[memory_darwin_WRAPPER_EXTRA_LDFLAGS="-Wl,-u,_munmap -Wl,-multiply_defined,suppress" [# Yes, we really do want to screw with LDFLAGS here...
LDFLAGS="$LDFLAGS -Wl,-multiply_defined,suppress"
memory_darwin_WRAPPER_EXTRA_LDFLAGS="-Wl,-u,_munmap -Wl,-multiply_defined,suppress"
$1], [$2]) $1], [$2])
]) ])

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

@ -28,6 +28,11 @@
#include "opal/memoryhooks/memory_internal.h" #include "opal/memoryhooks/memory_internal.h"
static int opal_memory_darwin_open(void); static int opal_memory_darwin_open(void);
static void* opal_memory_darwin_malloc(struct _malloc_zone_t *zone, size_t size);
static void* opal_memory_darwin_calloc(struct _malloc_zone_t *zone, size_t num_items,
size_t size);
static void* opal_memory_darwin_valloc(struct _malloc_zone_t *zone, size_t size);
static void opal_memory_darwin_free(struct _malloc_zone_t *zone, void *ptr); static void opal_memory_darwin_free(struct _malloc_zone_t *zone, void *ptr);
static void* opal_memory_darwin_realloc(struct _malloc_zone_t *zone, static void* opal_memory_darwin_realloc(struct _malloc_zone_t *zone,
void *ptr, size_t size); void *ptr, size_t size);
@ -58,7 +63,9 @@ const opal_memory_base_component_1_0_0_t mca_memory_darwin_component = {
}, },
}; };
static void* (*next_malloc)(struct _malloc_zone_t *zone, size_t size);
static void* (*next_calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size);
static void* (*next_valloc)(struct _malloc_zone_t *zone, size_t size);
static void (*next_free)(struct _malloc_zone_t *zone, void *ptr); static void (*next_free)(struct _malloc_zone_t *zone, void *ptr);
static void* (*next_realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); static void* (*next_realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
@ -73,22 +80,55 @@ opal_memory_darwin_open(void)
/* save the pointers first, so that we can call them as soon as we /* save the pointers first, so that we can call them as soon as we
replace the hooks below (think threads) */ replace the hooks below (think threads) */
next_malloc = default_zone->malloc;
next_calloc = default_zone->calloc;
next_valloc = default_zone->valloc;
next_free = default_zone->free; next_free = default_zone->free;
next_realloc = default_zone->realloc; next_realloc = default_zone->realloc;
default_zone->malloc = opal_memory_darwin_malloc;
default_zone->calloc = opal_memory_darwin_calloc;
default_zone->valloc = opal_memory_darwin_valloc;
default_zone->free = opal_memory_darwin_free; default_zone->free = opal_memory_darwin_free;
default_zone->realloc = opal_memory_darwin_realloc; default_zone->realloc = opal_memory_darwin_realloc;
opal_mem_free_set_free_support(1); opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT);
return OPAL_SUCCESS; return OPAL_SUCCESS;
} }
static void *
opal_memory_darwin_malloc(struct _malloc_zone_t *zone, size_t size)
{
void *tmp = next_malloc(zone, size);
opal_mem_hooks_alloc_hook(tmp, malloc_size(tmp));
return tmp;
}
static void*
opal_memory_darwin_calloc(struct _malloc_zone_t *zone, size_t num_items,
size_t size)
{
void *tmp = next_calloc(zone, num_items, size);
opal_mem_hooks_alloc_hook(tmp, malloc_size(tmp));
return tmp;
}
static void*
opal_memory_darwin_valloc(struct _malloc_zone_t *zone, size_t size)
{
void *tmp = next_valloc(zone, size);
opal_mem_hooks_alloc_hook(tmp, malloc_size(tmp));
return tmp;
}
static void static void
opal_memory_darwin_free(struct _malloc_zone_t *zone, void *ptr) opal_memory_darwin_free(struct _malloc_zone_t *zone, void *ptr)
{ {
opal_mem_free_release_hook(ptr, malloc_size(ptr)); opal_mem_hooks_release_hook(ptr, malloc_size(ptr));
next_free(zone, ptr); next_free(zone, ptr);
} }
@ -97,24 +137,52 @@ static void *
opal_memory_darwin_realloc(struct _malloc_zone_t *zone, opal_memory_darwin_realloc(struct _malloc_zone_t *zone,
void *ptr, size_t size) void *ptr, size_t size)
{ {
opal_mem_free_release_hook(ptr, malloc_size(ptr)); char *tmp;
return next_realloc(zone, ptr, size);
opal_mem_hooks_release_hook(ptr, malloc_size(ptr));
tmp = next_realloc(zone, ptr, size);
opal_mem_hooks_alloc_hook(tmp, malloc_size(tmp));
return tmp;
} }
/* only need to catch munmap for user code, and we should be at the /* only need to catch mmap / munmap for user code, and we should be at the
far right of the library stack, so this should work. Darwin 7 and far right of the library stack, so this should work. Darwin 7 and
later include dlsym as part of libSystem, so no need to do anything later include dlsym as part of libSystem, so no need to do anything
special for it. Not sure what would happen if you tried to special for it. Not sure what would happen if you tried to
statically link your application (as in -Bstatic, not libmpi.a), statically link your application (as in -Bstatic, not libmpi.a),
but since Apple doesn't support that, neither do we. */ but since Apple doesn't support that, neither do we. */
void*
mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
static void* (*realmmap)(void *, size_t, int, int, int, off_t);
void *tmp;
if (NULL == realmmap) {
union {
void* (*mmap_fp)(void *, size_t, int, int, int, off_t);
void *mmap_p;
} tmp;
tmp.mmap_p = dlsym(RTLD_NEXT, "mmap");
realmmap = tmp.mmap_fp;
}
tmp = realmmap(addr, len, prot, flags, fd, offset);
opal_mem_hooks_alloc_hook(tmp, len);
return tmp;
}
int int
munmap(void* addr, size_t len) munmap(void* addr, size_t len)
{ {
static int (*realmunmap)(void*, size_t); static int (*realmunmap)(void*, size_t);
/* dispatch about the pending release */ /* dispatch about the pending release */
opal_mem_free_release_hook(addr, len); opal_mem_hooks_release_hook(addr, len);
if (NULL == realmunmap) { if (NULL == realmunmap) {
union { union {

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

@ -22,21 +22,25 @@
#define __USE_GNU #define __USE_GNU
#include <dlfcn.h> #include <dlfcn.h>
#include <malloc.h> #include <malloc.h>
#include <assert.h>
#include <stdlib.h>
#include "opal/memoryhooks/memory_internal.h" #include "opal/memoryhooks/memory_internal.h"
/* Prototypes for our hooks. */ /* Prototypes for our hooks. */
void opal_memory_malloc_hooks_init(void); void opal_memory_malloc_hooks_init(void);
static void opal_mem_free_free_hook (void*, const void *);
static void* opal_mem_free_realloc_hook (void*, size_t, const void *); static void local_free_hook(void*, const void*);
static void* local_malloc_hook(size_t, const void*);
static void* local_realloc_hook(void*, size_t, const void*);
/* Override initializing hook from the C library. */ /* Override initializing hook from the C library. */
void (*__malloc_initialize_hook) (void) = opal_memory_malloc_hooks_init; void (*__malloc_initialize_hook) (void) = opal_memory_malloc_hooks_init;
/* local variable - next in stack of free hooks */ /* local variable - next in stack of free hooks */
static void (*old_free_hook)(void*, const void*); static void (*old_free_hook)(void*, const void*);
static void* (*old_realloc_hook)(void*, size_t, const void*); static void* (*old_realloc_hook)(void*, size_t, const void*);
static void* (*old_malloc_hook)(size_t, const void*);
static int initialized = 0; static int initialized = 0;
@ -52,19 +56,26 @@ opal_memory_malloc_hooks_init(void)
} }
initialized = 1; initialized = 1;
old_free_hook = __free_hook; old_free_hook = __free_hook;
old_malloc_hook = __malloc_hook;
old_realloc_hook = __realloc_hook; old_realloc_hook = __realloc_hook;
__free_hook = opal_mem_free_free_hook;
__realloc_hook = opal_mem_free_realloc_hook; __free_hook = local_free_hook;
opal_mem_free_set_free_support(1); __malloc_hook = local_malloc_hook;
__realloc_hook = local_realloc_hook;
opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT);
assert(__malloc_hook == local_malloc_hook);
} }
static void static void
opal_mem_free_free_hook (void *ptr, const void *caller) local_free_hook(void *ptr, const void *caller)
{ {
if (__malloc_hook != local_malloc_hook) abort();
/* dispatch about the pending free */ /* dispatch about the pending free */
opal_mem_free_release_hook(ptr, malloc_usable_size(ptr)); opal_mem_hooks_release_hook(ptr, malloc_usable_size(ptr));
__free_hook = old_free_hook; __free_hook = old_free_hook;
@ -73,29 +84,91 @@ opal_mem_free_free_hook (void *ptr, const void *caller)
/* save the hooks again and restore our hook again */ /* save the hooks again and restore our hook again */
old_free_hook = __free_hook; old_free_hook = __free_hook;
__free_hook = opal_mem_free_free_hook; __free_hook = local_free_hook;
} }
static void*
local_malloc_hook(size_t size, const void *caller)
{
void *ret;
__malloc_hook = old_malloc_hook;
/* call the next chain down */
ret = malloc(size);
/* save the hooks again and restory our hack again */
old_malloc_hook = __malloc_hook;
__malloc_hook = local_malloc_hook;
opal_mem_hooks_alloc_hook(ret, malloc_usable_size(ret));
assert(__malloc_hook == local_malloc_hook);
return ret;
}
/* for better or worse, we must assume that the buffer being passed to /* for better or worse, we must assume that the buffer being passed to
realloc is not going to be expandable and therefore is going to be realloc is not going to be expandable and therefore is going to be
free()ed. */ free()ed. */
static void* static void*
opal_mem_free_realloc_hook (void *ptr, size_t size, const void *caller) local_realloc_hook(void *ptr, size_t size, const void *caller)
{ {
void *ret; void *ret;
assert(__malloc_hook == local_malloc_hook);
/* dispatch about the pending free */ /* dispatch about the pending free */
opal_mem_free_release_hook(ptr, malloc_usable_size(ptr)); opal_mem_hooks_release_hook(ptr, malloc_usable_size(ptr));
/* realloc can call malloc (but not free). Doing so with the
* memory hooks causes us some interesting problems and causes
* the malloc_hook to be left as NULL. Pop the stack now so
* that we don't see the memory registration twice.
*/
__realloc_hook = old_realloc_hook; __realloc_hook = old_realloc_hook;
__malloc_hook = old_malloc_hook;
/* call the next chain down */ /* call the next chain down */
ret = realloc(ptr, size); ret = realloc(ptr, size);
/* save the hooks again and restore our hook again */ /* save the hooks again and restore our hook again */
old_realloc_hook = __realloc_hook; old_realloc_hook = __realloc_hook;
__realloc_hook = opal_mem_free_realloc_hook; old_malloc_hook = __malloc_hook;
__realloc_hook = local_realloc_hook;
__malloc_hook = local_malloc_hook;
opal_mem_hooks_alloc_hook(ret, malloc_usable_size(ret));
assert(__malloc_hook == local_malloc_hook);
return ret;
}
/* mmap is a weak symbol on any platform that I know of that
supports malloc hooks, so we can just intercept it like this... */
void*
mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
{
void *ret;
static void* (*realmmap)(void*, size_t, int, int, int, off_t);
if (NULL == realmmap) {
union {
void* (*mmap_fp)(void*, size_t, int, int, int, off_t);
void *mmap_p;
} tmp;
tmp.mmap_p = dlsym(RTLD_NEXT, "mmap");
realmmap = tmp.mmap_fp;
}
ret = realmmap(addr, len, prot, flags, fd, offset);
opal_mem_hooks_alloc_hook(ret, len);
return ret; return ret;
} }
@ -108,7 +181,8 @@ munmap(void* addr, size_t len)
{ {
static int (*realmunmap)(void*, size_t); static int (*realmunmap)(void*, size_t);
/* dispatch about the pending release */ /* dispatch about the pending release */
opal_mem_free_release_hook(addr, len); opal_mem_hooks_release_hook(addr, len);
assert(__malloc_hook == local_malloc_hook);
if (NULL == realmunmap) { if (NULL == realmunmap) {
union { union {

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

@ -68,6 +68,30 @@ const opal_memory_base_component_1_0_0_t mca_memory_malloc_interpose_component =
} \ } \
} while (0); } while (0);
#define FIND_REALCALLOC() \
do { \
if (NULL == realcalloc) { \
union { \
void* (*calloc_fp)(size_t, size_t); \
void* calloc_p; \
} tmp; \
tmp.calloc_p = dlsym(RTLD_NEXT, "calloc"); \
realcalloc = tmp.calloc_fp; \
} \
} while (0);
#define FIND_REALMALLOC() \
do { \
if (NULL == realmalloc) { \
union { \
void* (*malloc_fp)(size_t); \
void* malloc_p; \
} tmp; \
tmp.malloc_p = dlsym(RTLD_NEXT, "malloc"); \
realmalloc = tmp.malloc_fp; \
} \
} while (0);
#define FIND_REALREALLOC() \ #define FIND_REALREALLOC() \
do { \ do { \
if (NULL == realrealloc) { \ if (NULL == realrealloc) { \
@ -80,6 +104,18 @@ const opal_memory_base_component_1_0_0_t mca_memory_malloc_interpose_component =
} \ } \
} while (0); } while (0);
#define FIND_REALMMAP() \
do { \
if (NULL == realmmap) { \
union { \
void* (*mmap_fp)(void*, size_t, int, int, int, off_t); \
void *mmap_p; \
} tmp; \
tmp.mmap_p = dlsym(RTLD_NEXT, "mmap"); \
realmmap = tmp.mmap_fp; \
} \
} while (0);
#define FIND_REALMUNMAP() \ #define FIND_REALMUNMAP() \
do { \ do { \
if (NULL == realmunmap) { \ if (NULL == realmunmap) { \
@ -93,19 +129,23 @@ const opal_memory_base_component_1_0_0_t mca_memory_malloc_interpose_component =
} while (0); } while (0);
static void (*realfree)(void*); static void (*realfree)(void*);
static void* (*realcalloc)(size_t, size_t);
static void* (*realmalloc)(size_t);
static void* (*realrealloc)(void*, size_t); static void* (*realrealloc)(void*, size_t);
static void* (*realmmap)(void*, size_t, int, int, int, off_t);
static int (*realmunmap)(void*, size_t); static int (*realmunmap)(void*, size_t);
static int static int
opal_memory_malloc_interpose_open(void) opal_memory_malloc_interpose_open(void)
{ {
opal_mem_free_set_free_support(1); opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT);
FIND_REALFREE(); FIND_REALFREE();
FIND_REALREALLOC(); FIND_REALREALLOC();
FIND_REALMUNMAP(); FIND_REALMUNMAP();
if (NULL == realfree || NULL == realrealloc || NULL == realmunmap) { if (NULL == realfree || NULL == realcalloc || NULL == realmalloc ||
NULL == realrealloc || NULL == realmmap || NULL == realmunmap) {
/* this shoudl really never happen */ /* this shoudl really never happen */
fprintf(stderr, fprintf(stderr,
"Could not find real memory functions. Aborting in dispair\n"); "Could not find real memory functions. Aborting in dispair\n");
@ -122,19 +162,57 @@ free(void *ptr)
FIND_REALFREE(); FIND_REALFREE();
/* dispatch about the pending release */ /* dispatch about the pending release */
opal_mem_free_release_hook(ptr, malloc_usable_size(ptr)); opal_mem_hooks_release_hook(ptr, malloc_usable_size(ptr));
realfree(ptr); realfree(ptr);
} }
void*
calloc(size_t nmemb, size_t size)
{
void *ret;
FIND_REALCALLOC();
ret = realcalloc(nmemb, size);
opal_mem_hooks_alloc_hook(ret, malloc_usable_size(ret));
return ret;
}
void*
malloc(size_t size)
{
void *ret;
FIND_REALMALLOC();
ret = realmalloc(size);
opal_mem_hooks_alloc_hook(ret, malloc_usable_size(ret));
return ret;
}
void* void*
realloc(void *ptr, size_t size) realloc(void *ptr, size_t size)
{ {
FIND_REALREALLOC(); void *ret;
/* dispatch about the pending release */ FIND_REALREALLOC();
opal_mem_free_release_hook(ptr, malloc_usable_size(ptr)); opal_mem_hooks_release_hook(ptr, malloc_usable_size(ptr));
return realrealloc(ptr, size); ret = realrealloc(ptr, size);
opal_mem_hooks_alloc_hook(ret, malloc_usable_size(ret));
return ret;
}
void*
mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
void *ret;
FIND_REALMMAP();
ret = realmmap(start, length, prot, flags, fd, offset);
opal_mem_hooks_alloc_hook(ret, length);
return ret;
} }
@ -144,6 +222,6 @@ munmap(void *start, size_t length)
FIND_REALMUNMAP(); FIND_REALMUNMAP();
/* dispatch about the pending release */ /* dispatch about the pending release */
opal_mem_free_release_hook(start, length); opal_mem_hooks_release_hook(start, length);
return realmunmap(start, length); return realmunmap(start, length);
} }

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

@ -45,8 +45,6 @@ libmca_memory_ptmalloc2_la_SOURCES = \
malloc.c \ malloc.c \
malloc-stats.c \ malloc-stats.c \
malloc.h malloc.h
libmca_memory_ptmalloc2_la_LIBADD = \
$(top_ompi_builddir)/opal/libopal.la
# these are included directly and shouldn't be built solo # these are included directly and shouldn't be built solo
EXTRA_libmca_memory_ptmalloc2_la_SOURCES = \ EXTRA_libmca_memory_ptmalloc2_la_SOURCES = \

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

@ -468,7 +468,7 @@ ptmalloc_init __MALLOC_P((void))
/********************** BEGIN OMPI CHANGES *****************************/ /********************** BEGIN OMPI CHANGES *****************************/
/* don't use __hook for this, as someone might want to use those /* don't use __hook for this, as someone might want to use those
features */ features */
opal_mem_free_set_free_support(1); opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_CHUNK_SUPPORT);
/********************* BEGIN OMPI CHANGES ******************************/ /********************* BEGIN OMPI CHANGES ******************************/
__malloc_initialized = 1; __malloc_initialized = 1;

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

@ -20,7 +20,7 @@ opal_mem_free_ptmalloc2_sbrk(int inc)
{ {
if (inc < 0) { if (inc < 0) {
long oldp = (long) sbrk(0); long oldp = (long) sbrk(0);
opal_mem_free_release_hook((void*) (oldp + inc), -inc); opal_mem_hooks_release_hook((void*) (oldp + inc), -inc);
} }
return sbrk(inc); return sbrk(inc);

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

@ -33,7 +33,7 @@ int
munmap(void* addr, size_t len) munmap(void* addr, size_t len)
{ {
/* dispatch about the pending release */ /* dispatch about the pending release */
opal_mem_free_release_hook(addr, len); opal_mem_hooks_release_hook(addr, len);
if (NULL == realmunmap) { if (NULL == realmunmap) {
realmunmap = (int (*)(void*, size_t)) dlsym(RTLD_NEXT, "munmap"); realmunmap = (int (*)(void*, size_t)) dlsym(RTLD_NEXT, "munmap");
@ -47,7 +47,7 @@ munmap(void* addr, size_t len)
int int
opal_mem_free_ptmalloc2_munmap(void *start, size_t length) opal_mem_free_ptmalloc2_munmap(void *start, size_t length)
{ {
opal_mem_free_release_hook(start, length); opal_mem_hooks_release_hook(start, length);
if (NULL == realmunmap) { if (NULL == realmunmap) {
realmunmap = (int (*)(void*, size_t)) dlsym(RTLD_NEXT, "munmap"); realmunmap = (int (*)(void*, size_t)) dlsym(RTLD_NEXT, "munmap");

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

@ -21,12 +21,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "opal/include/constants.h"
#include "opal/util/output.h" #include "opal/util/output.h"
#include "opal/memoryhooks/memory.h" #include "opal/memoryhooks/memory.h"
#include "opal/memoryhooks/memory_internal.h" #include "opal/memoryhooks/memory_internal.h"
#include "opal/class/opal_list.h" #include "opal/class/opal_list.h"
#include "opal/class/opal_object.h" #include "opal/class/opal_object.h"
#include "ompi/include/constants.h"
/* /*
@ -34,7 +34,7 @@
*/ */
struct callback_list_item_t { struct callback_list_item_t {
opal_list_item_t super; opal_list_item_t super;
opal_mem_free_unpin_fn_t *cbfunc; opal_mem_hooks_callback_fn_t *cbfunc;
void *cbdata; void *cbdata;
}; };
typedef struct callback_list_item_t callback_list_item_t; typedef struct callback_list_item_t callback_list_item_t;
@ -43,68 +43,84 @@ static OBJ_CLASS_INSTANCE(callback_list_item_t, opal_list_item_t, NULL, NULL);
/* /*
* local data * local data
*/ */
static opal_list_t callback_list; static int hooks_support = 0;
static opal_atomic_lock_t callback_lock;
static int have_free_support = false; static opal_list_t alloc_cb_list;
static int run_callbacks = false; static opal_atomic_lock_t alloc_lock;
static int have_been_called = 0; static int alloc_run_callbacks;
static opal_list_t release_cb_list;
static opal_atomic_lock_t release_lock;
static int release_run_callbacks;
int int
opal_mem_free_init(void) opal_mem_hooks_init(void)
{ {
OBJ_CONSTRUCT(&callback_list, opal_list_t); OBJ_CONSTRUCT(&alloc_cb_list, opal_list_t);
opal_atomic_init(&callback_lock, OPAL_ATOMIC_UNLOCKED); OBJ_CONSTRUCT(&release_cb_list, opal_list_t);
opal_atomic_init(&alloc_lock, OPAL_ATOMIC_UNLOCKED);
opal_atomic_init(&release_lock, OPAL_ATOMIC_UNLOCKED);
/* delay running callbacks until there is something in the /* delay running callbacks until there is something in the
registration */ registration */
run_callbacks = false; alloc_run_callbacks = false;
release_run_callbacks = false;
opal_atomic_mb(); opal_atomic_mb();
return OMPI_SUCCESS; return OPAL_SUCCESS;
} }
int int
opal_mem_free_finalize(void) opal_mem_hooks_finalize(void)
{ {
opal_list_item_t *item; opal_list_item_t *item;
run_callbacks = false; /* don't try to run callbacks any more */
alloc_run_callbacks = false;
release_run_callbacks = false;
opal_atomic_mb(); opal_atomic_mb();
/* aquire the lock, just to make sure no one is currently /* aquire the lock, just to make sure no one is currently
twiddling with the list. We know this won't last long, since twiddling with the list. We know this won't last long, since
no new calls will come in after we set run_callbacks to false */ no new calls will come in after we set run_callbacks to false */
opal_atomic_lock(&callback_lock); opal_atomic_lock(&alloc_lock);
opal_atomic_lock(&release_lock);
while (NULL != (item = opal_list_remove_first(&callback_list))) { /* clean out the lists */
while (NULL != (item = opal_list_remove_first(&alloc_cb_list))) {
OBJ_RELEASE(item); OBJ_RELEASE(item);
} }
OBJ_DESTRUCT(&callback_list); OBJ_DESTRUCT(&alloc_cb_list);
opal_atomic_unlock(&callback_lock); while (NULL != (item = opal_list_remove_first(&release_cb_list))) {
OBJ_RELEASE(item);
}
OBJ_DESTRUCT(&release_cb_list);
return OMPI_SUCCESS; opal_atomic_unlock(&alloc_lock);
opal_atomic_unlock(&release_lock);
return OPAL_SUCCESS;
} }
/* called from memory manager / memory-manager specific hooks */ /* called from memory manager / memory-manager specific hooks */
void void
opal_mem_free_set_free_support(int support) opal_mem_hooks_set_support(int support)
{ {
have_free_support = support; hooks_support = support;
} }
/* called from the memory manager / memory-manager specific hooks */ /* called from the memory manager / memory-manager specific hooks */
void void
opal_mem_free_release_hook(void *buf, size_t length) opal_mem_hooks_alloc_hook(void *buf, size_t length)
{ {
opal_list_item_t *item; opal_list_item_t *item;
have_been_called = 1; if (!alloc_run_callbacks) return;
if (!run_callbacks) return;
/* /*
* This is not really thread safe - but we can't hold the lock * This is not really thread safe - but we can't hold the lock
@ -116,62 +132,96 @@ opal_mem_free_release_hook(void *buf, size_t length)
* the initial callback to dispatch this * the initial callback to dispatch this
*/ */
opal_atomic_lock(&callback_lock); opal_atomic_lock(&alloc_lock);
item = opal_list_get_first(&callback_list); item = opal_list_get_first(&alloc_cb_list);
while(item != opal_list_get_end(&callback_list)) { while(item != opal_list_get_end(&alloc_cb_list)) {
opal_list_item_t* next = opal_list_get_next(item); opal_list_item_t* next = opal_list_get_next(item);
callback_list_item_t cbitem = *(callback_list_item_t*) item; callback_list_item_t cbitem = *(callback_list_item_t*) item;
item = next; item = next;
opal_atomic_unlock(&callback_lock); opal_atomic_unlock(&alloc_lock);
cbitem.cbfunc(buf, length, cbitem.cbdata); cbitem.cbfunc(buf, length, cbitem.cbdata);
opal_atomic_lock(&callback_lock); opal_atomic_lock(&alloc_lock);
} }
opal_atomic_unlock(&callback_lock); opal_atomic_unlock(&alloc_lock);
} }
bool /* called from the memory manager / memory-manager specific hooks */
opal_mem_free_is_supported(void) void
opal_mem_hooks_release_hook(void *buf, size_t length)
{ {
return (bool) have_free_support; opal_list_item_t *item;
if (!release_run_callbacks) return;
/*
* This is not really thread safe - but we can't hold the lock
* while calling the callback function as this routine can
* be called recursively.
*
* Instead, we could set a flag if we are already in the callback,
* and if called recursively queue the new address/length and allow
* the initial callback to dispatch this
*/
opal_atomic_lock(&release_lock);
item = opal_list_get_first(&release_cb_list);
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);
cbitem.cbfunc(buf, length, cbitem.cbdata);
opal_atomic_lock(&release_lock);
}
opal_atomic_unlock(&release_lock);
} }
int int
opal_mem_free_register_handler(opal_mem_free_unpin_fn_t *func, void *cbdata) opal_mem_hooks_support_level(void)
{
return hooks_support;
}
int
opal_mem_hooks_register_alloc(opal_mem_hooks_callback_fn_t *func, void *cbdata)
{ {
opal_list_item_t *item; opal_list_item_t *item;
callback_list_item_t *cbitem, *new_cbitem; callback_list_item_t *cbitem, *new_cbitem;
int ret = OMPI_SUCCESS; int ret = OPAL_SUCCESS;
if (!have_free_support) return OMPI_ERR_NOT_SUPPORTED; if (0 == (OPAL_MEMORY_FREE_SUPPORT & hooks_support)) {
return OPAL_ERR_NOT_SUPPORTED;
/* we either have or are about to have a registration that needs }
calling back. Let the system know it needs to run callbacks
now */
run_callbacks = true;
opal_atomic_mb();
/* pre-allocate a callback item on the assumption it won't be /* pre-allocate a callback item on the assumption it won't be
found. We can't call OBJ_NEW inside the lock because it might found. We can't call OBJ_NEW inside the lock because it might
call realloc */ call alloc / realloc */
new_cbitem = OBJ_NEW(callback_list_item_t); new_cbitem = OBJ_NEW(callback_list_item_t);
if (NULL == new_cbitem) { if (NULL == new_cbitem) {
ret = OMPI_ERR_OUT_OF_RESOURCE; ret = OPAL_ERR_OUT_OF_RESOURCE;
goto done; goto done;
} }
opal_atomic_lock(&callback_lock); opal_atomic_lock(&alloc_lock);
/* we either have or are about to have a registration that needs
calling back. Let the system know it needs to run callbacks
now */
alloc_run_callbacks = true;
opal_atomic_mb();
/* make sure the callback isn't already in the list */ /* make sure the callback isn't already in the list */
for (item = opal_list_get_first(&callback_list) ; for (item = opal_list_get_first(&alloc_cb_list) ;
item != opal_list_get_end(&callback_list) ; item != opal_list_get_end(&alloc_cb_list) ;
item = opal_list_get_next(item)) { item = opal_list_get_next(item)) {
cbitem = (callback_list_item_t*) item; cbitem = (callback_list_item_t*) item;
if (cbitem->cbfunc == func) { if (cbitem->cbfunc == func) {
ret = OMPI_EXISTS; ret = OPAL_EXISTS;
goto done; goto done;
} }
} }
@ -179,12 +229,12 @@ opal_mem_free_register_handler(opal_mem_free_unpin_fn_t *func, void *cbdata)
new_cbitem->cbfunc = func; new_cbitem->cbfunc = func;
new_cbitem->cbdata = cbdata; new_cbitem->cbdata = cbdata;
opal_list_append(&callback_list, (opal_list_item_t*) new_cbitem); opal_list_append(&alloc_cb_list, (opal_list_item_t*) new_cbitem);
done: done:
opal_atomic_unlock(&callback_lock); opal_atomic_unlock(&alloc_lock);
if (OMPI_EXISTS == ret && NULL != new_cbitem) { if (OPAL_EXISTS == ret && NULL != new_cbitem) {
OBJ_RELEASE(new_cbitem); OBJ_RELEASE(new_cbitem);
} }
@ -193,30 +243,121 @@ opal_mem_free_register_handler(opal_mem_free_unpin_fn_t *func, void *cbdata)
int int
opal_mem_free_unregister_handler(opal_mem_free_unpin_fn_t *func) opal_mem_hooks_register_release(opal_mem_hooks_callback_fn_t *func, void *cbdata)
{ {
opal_list_item_t *item; opal_list_item_t *item;
opal_list_item_t *found_item = NULL; callback_list_item_t *cbitem, *new_cbitem;
callback_list_item_t *cbitem; int ret = OPAL_SUCCESS;
int ret = OMPI_ERR_NOT_FOUND;
opal_atomic_lock(&callback_lock); if (0 == (OPAL_MEMORY_FREE_SUPPORT & hooks_support)) {
return OPAL_ERR_NOT_SUPPORTED;
}
/* pre-allocate a callback item on the assumption it won't be
found. We can't call OBJ_NEW inside the lock because it might
call alloc / realloc */
new_cbitem = OBJ_NEW(callback_list_item_t);
if (NULL == new_cbitem) {
ret = OPAL_ERR_OUT_OF_RESOURCE;
goto done;
}
opal_atomic_lock(&release_lock);
/* we either have or are about to have a registration that needs
calling back. Let the system know it needs to run callbacks
now */
release_run_callbacks = true;
opal_atomic_mb();
/* make sure the callback isn't already in the list */ /* make sure the callback isn't already in the list */
for (item = opal_list_get_first(&callback_list) ; for (item = opal_list_get_first(&release_cb_list) ;
item != opal_list_get_end(&callback_list) ; item != opal_list_get_end(&release_cb_list) ;
item = opal_list_get_next(item)) { item = opal_list_get_next(item)) {
cbitem = (callback_list_item_t*) item; cbitem = (callback_list_item_t*) item;
if (cbitem->cbfunc == func) { if (cbitem->cbfunc == func) {
opal_list_remove_item(&callback_list, item); ret = OPAL_EXISTS;
goto done;
}
}
new_cbitem->cbfunc = func;
new_cbitem->cbdata = cbdata;
opal_list_append(&release_cb_list, (opal_list_item_t*) new_cbitem);
done:
opal_atomic_unlock(&release_lock);
if (OPAL_EXISTS == ret && NULL != new_cbitem) {
OBJ_RELEASE(new_cbitem);
}
return ret;
}
int
opal_mem_hooks_unregister_alloc(opal_mem_hooks_callback_fn_t* func)
{
opal_list_item_t *item;
opal_list_item_t *found_item = NULL;
callback_list_item_t *cbitem;
int ret = OPAL_ERR_NOT_FOUND;
opal_atomic_lock(&alloc_lock);
/* make sure the callback isn't already in the list */
for (item = opal_list_get_first(&alloc_cb_list) ;
item != opal_list_get_end(&alloc_cb_list) ;
item = opal_list_get_next(item)) {
cbitem = (callback_list_item_t*) item;
if (cbitem->cbfunc == func) {
opal_list_remove_item(&alloc_cb_list, item);
found_item = item; found_item = item;
ret = OMPI_SUCCESS; ret = OPAL_SUCCESS;
break; break;
} }
} }
opal_atomic_unlock(&callback_lock); opal_atomic_unlock(&alloc_lock);
/* OBJ_ALLOC calls free, so we can't alloc until we get out of
the lock */
if (NULL != found_item) {
OBJ_RELEASE(item);
}
return ret;
}
int
opal_mem_hooks_unregister_release(opal_mem_hooks_callback_fn_t* func)
{
opal_list_item_t *item;
opal_list_item_t *found_item = NULL;
callback_list_item_t *cbitem;
int ret = OPAL_ERR_NOT_FOUND;
opal_atomic_lock(&release_lock);
/* make sure the callback isn't already in the list */
for (item = opal_list_get_first(&release_cb_list) ;
item != opal_list_get_end(&release_cb_list) ;
item = opal_list_get_next(item)) {
cbitem = (callback_list_item_t*) item;
if (cbitem->cbfunc == func) {
opal_list_remove_item(&release_cb_list, item);
found_item = item;
ret = OPAL_SUCCESS;
break;
}
}
opal_atomic_unlock(&release_lock);
/* OBJ_RELEASE calls free, so we can't release until we get out of /* OBJ_RELEASE calls free, so we can't release until we get out of
the lock */ the lock */

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

@ -30,14 +30,16 @@
#ifndef OPAL_MEMORY_MEMORY_H #ifndef OPAL_MEMORY_MEMORY_H
#define OPAl_MEMORY_MEMORY_H #define OPAl_MEMORY_MEMORY_H
#include "memory_internal.h"
#if defined(c_plusplus) || defined(__cplusplus) #if defined(c_plusplus) || defined(__cplusplus)
extern "C" { extern "C" {
#endif #endif
int opal_mem_free_init(void); int opal_mem_hooks_init(void);
int opal_mem_free_finalize(void); int opal_mem_hooks_finalize(void);
/** /**
@ -56,26 +58,10 @@ int opal_mem_free_finalize(void);
* @param cbdata Pointer-length of information passed to * @param cbdata Pointer-length of information passed to
* the handler registration function. * the handler registration function.
*/ */
typedef void (opal_mem_free_unpin_fn_t)(void *buf, size_t length, void *cbdata); typedef void (opal_mem_hooks_callback_fn_t)(void *buf, size_t length, void *cbdata);
/** int opal_mem_hooks_support_level(void);
* Query functionality of memory callbacks
*
* Query whether the system is capable of providing callbacks when
* memory is about to be released by a process.
*
* @retval true opal_mem_free_register_handler() will not return
* \c OMPI_ERR_NOT_SUPPORTED.
* @retval false opal_mem_free_register_handler() will always return
* \c OMPI_ERR_NOT_SUPPORTED.
*
* \note There is no reason you have to call this function before
* calling opal_mem_free_register_handler(). It exists for component
* selection logic that may want to see what the status of the memory
* hook support is without actually registering anything.
*/
bool opal_mem_free_is_supported(void);
/** /**
@ -94,7 +80,9 @@ bool opal_mem_free_is_supported(void);
* @retval OMPI_ERR_NOT_SUPPORTED There are no hooks available for * @retval OMPI_ERR_NOT_SUPPORTED There are no hooks available for
* receiving callbacks when memory is to be released * receiving callbacks when memory is to be released
*/ */
int opal_mem_free_register_handler(opal_mem_free_unpin_fn_t *func, void *cbdata); int opal_mem_hooks_register_release(opal_mem_hooks_callback_fn_t *func, void *cbdata);
int opal_mem_hooks_register_alloc(opal_mem_hooks_callback_fn_t *func, void *cbdata);
/** /**
@ -107,7 +95,8 @@ int opal_mem_free_register_handler(opal_mem_free_unpin_fn_t *func, void *cbdata)
* @retval OMPI_SUCCESS The function was successfully deregistered * @retval OMPI_SUCCESS The function was successfully deregistered
* @retval OMPI_ERR_NOT_FOUND The function was not previously registered * @retval OMPI_ERR_NOT_FOUND The function was not previously registered
*/ */
int opal_mem_free_unregister_handler(opal_mem_free_unpin_fn_t *func); int opal_mem_hooks_unregister_release(opal_mem_hooks_callback_fn_t *func);
int opal_mem_hooks_unregister_alloc(opal_mem_hooks_callback_fn_t *func);
#if defined(c_plusplus) || defined(__cplusplus) #if defined(c_plusplus) || defined(__cplusplus)
} }

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

@ -19,7 +19,22 @@
#ifndef OPAL_MEMORY_MEMORY_INTERNAL_H #ifndef OPAL_MEMORY_MEMORY_INTERNAL_H
#define OPAL_MEMORY_MEMORY_INTERNAL_H #define OPAL_MEMORY_MEMORY_INTERNAL_H
void opal_mem_free_set_free_support(int support); #define OPAL_MEMORY_FREE_SUPPORT 0x0001
void opal_mem_free_release_hook(void *buf, size_t length); #define OPAL_MEMORY_MALLOC_SUPPORT 0x0002
#define OPAL_MEMORY_CHUNK_SUPPORT 0x0004
#if defined(c_plusplus) || defined(__cplusplus)
extern "C" {
#endif
void opal_mem_hooks_set_support(int support);
void opal_mem_hooks_release_hook(void *buf, size_t length);
void opal_mem_hooks_alloc_hook(void *buf, size_t length);
#if defined(c_plusplus) || defined(__cplusplus)
}
#endif
#endif /* OPAL_MEMORY_MEMORY_INTERNAL_H */ #endif /* OPAL_MEMORY_MEMORY_INTERNAL_H */

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

@ -64,7 +64,7 @@ int opal_finalize(void)
mca_base_close(); mca_base_close();
/* finalize the memory manager / tracker */ /* finalize the memory manager / tracker */
opal_mem_free_finalize(); opal_mem_hooks_finalize();
/* finalize the memory allocator */ /* finalize the memory allocator */
opal_malloc_finalize(); opal_malloc_finalize();

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

@ -112,7 +112,7 @@ int opal_init(void)
} }
/* initialize the memory manager / tracker */ /* initialize the memory manager / tracker */
if (OPAL_SUCCESS != opal_mem_free_init()) { if (OPAL_SUCCESS != opal_mem_hooks_init()) {
error = "opal_mem_free_init"; error = "opal_mem_free_init";
goto return_error; goto return_error;
} }

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

@ -191,7 +191,7 @@ int main(int argc, char *argv[])
opal_malloc_init(); opal_malloc_init();
/* initialize the memory manager / tracker */ /* initialize the memory manager / tracker */
opal_mem_free_init(); opal_mem_hooks_init();
opal_memory_base_open(); opal_memory_base_open();

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

@ -26,13 +26,20 @@
#include "opal/runtime/opal.h" #include "opal/runtime/opal.h"
#include "opal/memoryhooks/memory.h" #include "opal/memoryhooks/memory.h"
int ret = 2; int ret = 1; /* because of the munmap */
int size = 10 * 1024 * 1024; int size = 10 * 1024 * 1024;
static void static void
callback(void *buf, size_t length, void *cbdata) alloc_callback(void *buf, size_t length, void *cbdata)
{ {
printf("\tcallback with %lx, %d\n", (unsigned long) buf, (int) length); printf("\talloc callback with %lx, %d\n", (unsigned long) buf, (int) length);
ret++;
}
static void
release_callback(void *buf, size_t length, void *cbdata)
{
printf("\trelease callback with %lx, %d\n", (unsigned long) buf, (int) length);
ret--; ret--;
} }
@ -41,13 +48,16 @@ main(int argc, char *argv[])
{ {
void * foo, *bar; void * foo, *bar;
int retval; int retval;
return 77;
opal_init(); opal_init();
if (!opal_mem_free_is_supported()) { if (0 == ((OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT) &
opal_mem_hooks_support_level())) {
printf("no memory registration supported. skipping\n"); printf("no memory registration supported. skipping\n");
return 77; return 77;
} }
retval = opal_mem_free_register_handler(callback, NULL); retval = opal_mem_hooks_register_release(release_callback, NULL);
retval |= opal_mem_hooks_register_alloc(alloc_callback, NULL);
if (retval != OMPI_SUCCESS) { if (retval != OMPI_SUCCESS) {
printf("handler registration failed\n"); printf("handler registration failed\n");
return retval; return retval;
@ -66,26 +76,29 @@ main(int argc, char *argv[])
from a small block to a big one will fail), so don't make this from a small block to a big one will fail), so don't make this
an error */ an error */
if (ret == 0) { if (ret == 0) {
ret = 2; ret = 0;
printf(" - realloc\n"); printf(" - realloc\n");
foo = malloc(size); foo = malloc(size);
bar = malloc(10); bar = malloc(10);
foo = realloc(foo, size * 2); foo = realloc(foo, size * 2);
free(bar); free(bar);
free(foo); free(foo);
if (ret > 0) { if (ret != 0) {
printf("WARNING - It appears that realloc does not trigger a callback\n"); printf("WARNING - It appears that realloc does not trigger a callback\n");
printf("WARNING - this may be a problem or it may be a sign that your\n"); printf("WARNING - this may be a problem or it may be a sign that your\n");
printf("WARNING - memory manager is better than mine\n"); printf("WARNING - memory manager is better than mine\n");
printf("ret: %d\n", ret); printf("ret: %d\n", ret);
} }
ret = 0; ret = 0;
printf("here\n");
} }
retval = opal_mem_free_unregister_handler(callback); retval = opal_mem_hooks_unregister_release(release_callback);
retval |= opal_mem_hooks_unregister_alloc(alloc_callback);
if (retval != OMPI_SUCCESS) return retval; if (retval != OMPI_SUCCESS) return retval;
opal_finalize(); opal_finalize();
printf("ret: %d\n", ret);
return ret; return ret;
} }

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

@ -46,12 +46,13 @@ main(int argc, char *argv[])
opal_init(); opal_init();
if (0 == (int) opal_mem_free_is_supported()) { if (0 == ((OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT) &
opal_mem_hooks_support_level())) {
printf("no memory registration supported. skipping\n"); printf("no memory registration supported. skipping\n");
return 77; return 77;
} }
retval = opal_mem_free_register_handler(callback, NULL); retval = opal_mem_hooks_register_release(callback, NULL);
if (retval != OMPI_SUCCESS) return retval; if (retval != OMPI_SUCCESS) return retval;
vector<int> *big_vec; vector<int> *big_vec;
@ -71,7 +72,7 @@ main(int argc, char *argv[])
printf(" - all done\n"); printf(" - all done\n");
retval = opal_mem_free_unregister_handler(callback); retval = opal_mem_hooks_unregister_release(callback);
if (retval != OMPI_SUCCESS) return retval; if (retval != OMPI_SUCCESS) return retval;
opal_finalize(); opal_finalize();

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

@ -44,7 +44,8 @@ main(int argc, char *argv[])
long time; long time;
opal_init(); opal_init();
if (!opal_mem_free_is_supported()) { if (0 == ((OPAL_MEMORY_FREE_SUPPORT|OPAL_MEMORY_MALLOC_SUPPORT) &
opal_mem_hooks_support_level())) {
printf("no memory registration supported. skipping\n"); printf("no memory registration supported. skipping\n");
return 77; return 77;
} }
@ -72,7 +73,7 @@ main(int argc, char *argv[])
iters, time, (double) time / iters); iters, time, (double) time / iters);
printf("speed with empty handler:\n"); printf("speed with empty handler:\n");
retval = opal_mem_free_register_handler(callback, NULL); retval = opal_mem_hooks_register_release(callback, NULL);
if (retval != OMPI_SUCCESS) { if (retval != OMPI_SUCCESS) {
printf("handler registration failed\n"); printf("handler registration failed\n");
return retval; return retval;
@ -97,7 +98,7 @@ main(int argc, char *argv[])
(end.tv_usec - start.tv_usec); (end.tv_usec - start.tv_usec);
printf(" free: %d calls in %ld microseconds. %lf microseconds/call\n", printf(" free: %d calls in %ld microseconds. %lf microseconds/call\n",
iters, time, (double) time / iters); iters, time, (double) time / iters);
opal_mem_free_unregister_handler(callback); opal_mem_hooks_unregister_release(callback);
printf("speed without a handler:\n"); printf("speed without a handler:\n");
@ -122,7 +123,7 @@ main(int argc, char *argv[])
iters, time, (double) time / iters); iters, time, (double) time / iters);
printf("speed with empty handler:\n"); printf("speed with empty handler:\n");
retval = opal_mem_free_register_handler(callback, NULL); retval = opal_mem_hooks_register_release(callback, NULL);
if (retval != OMPI_SUCCESS) { if (retval != OMPI_SUCCESS) {
printf("handler registration failed\n"); printf("handler registration failed\n");
return retval; return retval;
@ -147,7 +148,7 @@ main(int argc, char *argv[])
(end.tv_usec - start.tv_usec); (end.tv_usec - start.tv_usec);
printf(" free: %d calls in %ld microseconds. %lf microseconds/call\n", printf(" free: %d calls in %ld microseconds. %lf microseconds/call\n",
iters, time, (double) time / iters); iters, time, (double) time / iters);
opal_mem_free_unregister_handler(callback); opal_mem_hooks_unregister_release(callback);
opal_finalize(); opal_finalize();