Skip to content

Commit 3e0bcb1

Browse files
Support c++ lambda callbacks
1 parent 44b3afe commit 3e0bcb1

File tree

8 files changed

+106
-82
lines changed

8 files changed

+106
-82
lines changed

include/fenix.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
#include <setjmp.h>
6262

6363
#if defined(c_plusplus) || defined(__cplusplus)
64+
#include "fenix.hpp"
65+
6466
extern "C" {
6567
#endif
6668

include/fenix.hpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
//@HEADER
3+
// ************************************************************************
4+
//
5+
//
6+
// _|_|_|_| _|_|_|_| _| _| _|_|_| _| _|
7+
// _| _| _|_| _| _| _| _|
8+
// _|_|_| _|_|_| _| _| _| _| _|
9+
// _| _| _| _|_| _| _| _|
10+
// _| _|_|_|_| _| _| _|_|_| _| _|
11+
//
12+
//
13+
//
14+
//
15+
// Copyright (C) 2016 Rutgers University and Sandia Corporation
16+
//
17+
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18+
// the U.S. Government retains certain rights in this software.
19+
//
20+
// Redistribution and use in source and binary forms, with or without
21+
// modification, are permitted provided that the following conditions are
22+
// met:
23+
//
24+
// 1. Redistributions of source code must retain the above copyright
25+
// notice, this list of conditions and the following disclaimer.
26+
//
27+
// 2. Redistributions in binary form must reproduce the above copyright
28+
// notice, this list of conditions and the following disclaimer in the
29+
// documentation and/or other materials provided with the distribution.
30+
//
31+
// 3. Neither the name of the Corporation nor the names of the
32+
// contributors may be used to endorse or promote products derived from
33+
// this software without specific prior written permission.
34+
//
35+
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
36+
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
39+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
40+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
41+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
42+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
43+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46+
//
47+
// Author Marc Gamell, Eric Valenzuela, Keita Teranishi, Manish Parashar,
48+
// Rob Van der Wijngaart, Michael Heroux, and Matthew Whitlock
49+
//
50+
// Questions? Contact Keita Teranishi (knteran@sandia.gov) and
51+
// Marc Gamell (mgamell@cac.rutgers.edu)
52+
//
53+
// ************************************************************************
54+
//@HEADER
55+
*/
56+
57+
58+
#ifndef __FENIX_HPP__
59+
#define __FENIX_HPP__
60+
61+
#include <mpi.h>
62+
#include <functional>
63+
#include "fenix.h"
64+
65+
/**
66+
* @brief As the C-style callback, but accepts an std::function and does not use the void* pointer.
67+
*
68+
* @param[in] callback The function to register.
69+
*
70+
* @returnstatus
71+
*/
72+
int Fenix_Callback_register(std::function<void(MPI_Comm, int)> callback);
73+
74+
#endif

include/fenix_ext.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#define __FENIX_EXT_H__
5959

6060
#include <mpi.h>
61+
#include <vector>
6162
#include "fenix.h"
6263
#include "fenix_opt.hpp"
6364
#include "fenix_data_group.hpp"
@@ -77,7 +78,7 @@ typedef struct {
7778

7879
//enum FenixRankRole role; // Role of rank: initial, survivor or repair
7980
int role; // Role of rank: initial, survivor or repair
80-
int fenix_init_flag;
81+
int fenix_init_flag = 0;
8182

8283
int fail_world_size;
8384
int* fail_world;
@@ -86,7 +87,7 @@ typedef struct {
8687
int *ret_role;
8788
int *ret_error;
8889

89-
fenix_callback_list_t* callback_list; // singly linked list for user-defined Fenix callback functions
90+
std::vector<fenix_callback_func> callbacks;
9091
fenix_debug_opt_t options; // This is reserved to store the user options
9192

9293
MPI_Comm *world; // Duplicate of the MPI communicator provided by user

include/fenix_process_recovery.hpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,12 @@
6767
#include <signal.h>
6868

6969
#include "fenix_init.h"
70+
#include <functional>
7071

7172
#define __FENIX_RESUME_AT_INIT 0
7273
#define __FENIX_RESUME_NO_JUMP 200
7374

74-
typedef void (*recover)( MPI_Comm, int, void *);
75-
76-
typedef struct fcouple {
77-
recover x;
78-
void *y;
79-
} fenix_callback_func;
80-
81-
typedef struct __fenix_callback_list {
82-
fenix_callback_func *callback;
83-
struct __fenix_callback_list *next;
84-
} fenix_callback_list_t;
75+
using fenix_callback_func = std::function<void(MPI_Comm, int)>;
8576

8677
typedef struct __fenix_comm_list_elm {
8778
struct __fenix_comm_list_elm *next;
@@ -98,16 +89,12 @@ int __fenix_create_new_world();
9889

9990
int __fenix_repair_ranks();
10091

101-
int __fenix_callback_register(void (*recover)(MPI_Comm, int, void *), void *);
92+
int __fenix_callback_register(fenix_callback_func& recover);
10293

10394
int __fenix_callback_pop();
10495

105-
void __fenix_callback_push(fenix_callback_list_t **, fenix_callback_func *);
106-
10796
void __fenix_callback_invoke_all(int error);
10897

109-
int __fenix_callback_destroy(fenix_callback_list_t *callback_list);
110-
11198
int* __fenix_get_fail_ranks(int *, int, int);
11299

113100
int __fenix_spare_rank();

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ globals.cpp
3131

3232
add_library( fenix STATIC ${Fenix_SOURCES})
3333

34+
target_compile_features(fenix PRIVATE cxx_std_17)
35+
3436
target_link_libraries(fenix PUBLIC MPI::MPI_CXX)
3537

3638
target_include_directories(fenix

src/fenix.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,19 @@
5858
#include "fenix_process_recovery.hpp"
5959
#include "fenix_util.hpp"
6060
#include "fenix_ext.hpp"
61-
#include "fenix.h"
61+
#include "fenix.hpp"
6262

6363
const Fenix_Data_subset FENIX_DATA_SUBSET_FULL = {0, NULL, NULL, NULL, 0, __FENIX_SUBSET_FULL};
6464
const Fenix_Data_subset FENIX_DATA_SUBSET_EMPTY = {0, NULL, NULL, NULL, 0, __FENIX_SUBSET_EMPTY};
6565

66+
int Fenix_Callback_register(std::function<void(MPI_Comm, int)> callback){
67+
return __fenix_callback_register(callback);
68+
}
69+
6670
int Fenix_Callback_register(void (*recover)(MPI_Comm, int, void *), void *callback_data) {
67-
return __fenix_callback_register(recover, callback_data);
71+
return Fenix_Callback_register([recover, callback_data](MPI_Comm comm, int fenix_error){
72+
recover(comm, fenix_error, callback_data);
73+
});
6874
}
6975

7076
int Fenix_Callback_pop() {

src/fenix_callbacks.cpp

Lines changed: 10 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -65,71 +65,27 @@
6565
#include <mpi.h>
6666

6767

68-
int __fenix_callback_register(void (*recover)(MPI_Comm, int, void *), void *callback_data)
68+
int __fenix_callback_register(fenix_callback_func& recover)
6969
{
70-
int error_code = FENIX_SUCCESS;
71-
if (fenix.fenix_init_flag) {
72-
fenix_callback_func *fp = (fenix_callback_func *) s_malloc(sizeof(fenix_callback_func));
73-
fp->x = recover;
74-
fp->y = callback_data;
75-
__fenix_callback_push( &fenix.callback_list, fp);
76-
} else {
77-
error_code = FENIX_ERROR_UNINITIALIZED;
78-
}
79-
return error_code;
70+
if(!fenix.fenix_init_flag) return FENIX_ERROR_UNINITIALIZED;
71+
72+
fenix.callbacks.push_back(recover);
73+
74+
return FENIX_SUCCESS;
8075
}
8176

8277
int __fenix_callback_pop(){
8378
if(!fenix.fenix_init_flag) return FENIX_ERROR_UNINITIALIZED;
84-
if(fenix.callback_list == NULL) return FENIX_ERROR_CALLBACK_NOT_REGISTERED;
85-
86-
fenix_callback_list_t* old_head = fenix.callback_list;
87-
fenix.callback_list = old_head->next;
79+
if(fenix.callbacks.empty()) return FENIX_ERROR_CALLBACK_NOT_REGISTERED;
8880

89-
free(old_head->callback);
90-
free(old_head);
81+
fenix.callbacks.pop_back();
9182

9283
return FENIX_SUCCESS;
9384
}
9485

9586
void __fenix_callback_invoke_all(int error)
9687
{
97-
fenix_callback_list_t *current = fenix.callback_list;
98-
while (current != NULL) {
99-
(current->callback->x)((MPI_Comm) fenix.new_world, error,
100-
(void *) current->callback->y);
101-
current = current->next;
102-
}
103-
}
104-
105-
void __fenix_callback_push(fenix_callback_list_t **head, fenix_callback_func *fp)
106-
{
107-
fenix_callback_list_t *callback = (fenix_callback_list_t *) malloc(sizeof(fenix_callback_list_t));
108-
callback->callback = fp;
109-
callback->next = *head;
110-
*head = callback;
111-
}
112-
113-
int __fenix_callback_destroy(fenix_callback_list_t *callback_list)
114-
{
115-
int error_code = FENIX_SUCCESS;
116-
117-
if ( fenix.fenix_init_flag ) {
118-
119-
fenix_callback_list_t *current = callback_list;
120-
121-
while (current != NULL) {
122-
fenix_callback_list_t *old;
123-
old = current;
124-
current = current->next;
125-
free( old->callback );
126-
free( old );
127-
}
128-
129-
} else {
130-
error_code = FENIX_ERROR_UNINITIALIZED;
88+
for(auto it = fenix.callbacks.rbegin(); it != fenix.callbacks.rend(); it++){
89+
(*it)(*fenix.user_world, error);
13190
}
132-
133-
return error_code;
13491
}
135-

src/fenix_process_recovery.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -785,13 +785,11 @@ void __fenix_finalize()
785785
free(fenix.fail_world);
786786
}
787787

788-
/* Free Callbacks */
789-
__fenix_callback_destroy( fenix.callback_list );
790-
791788
/* Free data recovery interface */
792789
__fenix_data_recovery_destroy( fenix.data_recovery );
793790

794-
fenix.fenix_init_flag = 0;
791+
/* Free up any C++ data structures, reset default variables */
792+
fenix = {};
795793
}
796794

797795
void __fenix_finalize_spare()
@@ -823,13 +821,11 @@ void __fenix_finalize_spare()
823821
MPI_Comm_set_errhandler(*fenix.world, MPI_ERRORS_ARE_FATAL);
824822
MPI_Comm_free(fenix.world);
825823

826-
/* Free callbacks */
827-
__fenix_callback_destroy( fenix.callback_list );
828-
829824
/* Free data recovery interface */
830825
__fenix_data_recovery_destroy( fenix.data_recovery );
831826

832-
fenix.fenix_init_flag = 0;
827+
/* Free up any C++ data structures, reset default variables */
828+
fenix = {};
833829

834830
/* Future version do not close MPI. Jump to where Fenix_Finalize is called. */
835831
MPI_Finalize();

0 commit comments

Comments
 (0)