1 #ifndef PyMPI_COMPAT_OPENMPI_H
2 #define PyMPI_COMPAT_OPENMPI_H
3 
4 /* ------------------------------------------------------------------------- */
5 /* ------------------------------------------------------------------------- */
6 
7 /*
8  * The hackery below redefines the actuall calls to 'MPI_Init()' and
9  * 'MPI_Init_thread()' in order to preload the main MPI dynamic
10  * library with appropriate flags to 'dlopen()' ensuring global
11  * availability of library symbols.
12  */
13 
14 #ifndef OPENMPI_DLOPEN_LIBMPI
15 #define OPENMPI_DLOPEN_LIBMPI 1
16 #endif
17 
18 #if OPENMPI_DLOPEN_LIBMPI
19 #if HAVE_DLOPEN
20 
21 #include "../dynload.h"
22 
23 /*
24 static void * my_dlopen(const char *name, int mode) {
25   void *handle;
26   static int called = 0;
27   if (!called) {
28     called = 1;
29     #if HAVE_DLFCN_H
30     printf("HAVE_DLFCN_H: yes\n");
31     #else
32     printf("HAVE_DLFCN_H: no\n");
33     #endif
34     printf("\n");
35     printf("RTLD_LAZY:    0x%X\n", RTLD_LAZY   );
36     printf("RTLD_NOW:     0x%X\n", RTLD_NOW    );
37     printf("RTLD_LOCAL:   0x%X\n", RTLD_LOCAL  );
38     printf("RTLD_GLOBAL:  0x%X\n", RTLD_GLOBAL );
39     #ifdef RTLD_NOLOAD
40     printf("RTLD_NOLOAD:  0x%X\n", RTLD_NOLOAD );
41     #endif
42     printf("\n");
43   }
44   handle = dlopen(name, mode);
45   printf("dlopen(\"%s\",0x%X) -> %p\n", name, mode, handle);
46   printf("dlerror() -> %s\n\n", dlerror());
47   return handle;
48 }
49 #define dlopen my_dlopen
50 */
51 
OPENMPI_dlopen_libmpi(void)52 static void OPENMPI_dlopen_libmpi(void)
53 {
54   void *handle = 0;
55   int mode = RTLD_NOW | RTLD_GLOBAL;
56   #ifdef RTLD_NOLOAD
57   mode |= RTLD_NOLOAD;
58   #endif
59 #if defined(__CYGWIN__)
60   if (!handle) handle = dlopen("cygmpi.dll", mode);
61   if (!handle) handle = dlopen("mpi.dll",    mode);
62 #elif defined(__APPLE__)
63   /* Mac OS X */
64   if (!handle) handle = dlopen("libmpi.3.dylib", mode);
65   if (!handle) handle = dlopen("libmpi.2.dylib", mode);
66   if (!handle) handle = dlopen("libmpi.1.dylib", mode);
67   if (!handle) handle = dlopen("libmpi.0.dylib", mode);
68   if (!handle) handle = dlopen("libmpi.dylib",   mode);
69 #else
70   /* GNU/Linux and others*/
71   if (!handle) handle = dlopen("libmpi.so.3", mode);
72   if (!handle) handle = dlopen("libmpi.so.2", mode);
73   if (!handle) handle = dlopen("libmpi.so.1", mode);
74   if (!handle) handle = dlopen("libmpi.so.0", mode);
75   if (!handle) handle = dlopen("libmpi.so",   mode);
76 #endif
77 }
78 
PyMPI_OPENMPI_MPI_Init(int * argc,char *** argv)79 static int PyMPI_OPENMPI_MPI_Init(int *argc, char ***argv)
80 {
81   OPENMPI_dlopen_libmpi();
82   return MPI_Init(argc, argv);
83 }
84 #undef  MPI_Init
85 #define MPI_Init PyMPI_OPENMPI_MPI_Init
86 
PyMPI_OPENMPI_MPI_Init_thread(int * argc,char *** argv,int required,int * provided)87 static int PyMPI_OPENMPI_MPI_Init_thread(int *argc, char ***argv,
88                                          int required, int *provided)
89 {
90   OPENMPI_dlopen_libmpi();
91   return MPI_Init_thread(argc, argv, required, provided);
92 }
93 #undef  MPI_Init_thread
94 #define MPI_Init_thread PyMPI_OPENMPI_MPI_Init_thread
95 
96 #endif /* !HAVE_DLOPEN */
97 #endif /* !OPENMPI_DLOPEN_LIBMPI */
98 
99 /* ------------------------------------------------------------------------- */
100 /* ------------------------------------------------------------------------- */
101 
102 
103 /* ------------------------------------------------------------------------- */
104 
105 #if (defined(OMPI_MAJOR_VERSION) && \
106      defined(OMPI_MINOR_VERSION) && \
107      defined(OMPI_RELEASE_VERSION))
108 #define PyMPI_OPENMPI_VERSION ((OMPI_MAJOR_VERSION   * 10000) + \
109                                (OMPI_MINOR_VERSION   * 100)   + \
110                                (OMPI_RELEASE_VERSION * 1))
111 #else
112 #define PyMPI_OPENMPI_VERSION 10000
113 #endif
114 
115 /* ------------------------------------------------------------------------- */
116 
117 /*
118  * Open MPI < 1.1.3 generates an error when MPI_File_get_errhandler()
119  * is called with the predefined error handlers MPI_ERRORS_RETURN and
120  * MPI_ERRORS_ARE_FATAL.
121  */
122 
123 #if PyMPI_OPENMPI_VERSION < 10103
124 
PyMPI_OPENMPI_Errhandler_free(MPI_Errhandler * errhandler)125 static int PyMPI_OPENMPI_Errhandler_free(MPI_Errhandler *errhandler)
126 {
127   if (errhandler && ((*errhandler == MPI_ERRORS_RETURN) ||
128                      (*errhandler == MPI_ERRORS_ARE_FATAL))) {
129     *errhandler = MPI_ERRHANDLER_NULL;
130     return MPI_SUCCESS;
131   }
132   return MPI_Errhandler_free(errhandler);
133 }
134 #undef  MPI_Errhandler_free
135 #define MPI_Errhandler_free PyMPI_OPENMPI_Errhandler_free
136 
137 #endif /* !(PyMPI_OPENMPI_VERSION < 10103) */
138 
139 /* ------------------------------------------------------------------------- */
140 
141 /*
142  * Open MPI 1.1 generates an error when MPI_File_get_errhandler() is
143  * called with the MPI_FILE_NULL handle.  The code below try to fix
144  * this bug by intercepting the calls to the functions setting and
145  * getting the error handlers for MPI_File's.
146  */
147 
148 #if PyMPI_OPENMPI_VERSION < 10200
149 
150 static MPI_Errhandler PyMPI_OPENMPI_FILE_NULL_ERRHANDLER = (MPI_Errhandler)0;
151 
PyMPI_OPENMPI_File_get_errhandler(MPI_File file,MPI_Errhandler * errhandler)152 static int PyMPI_OPENMPI_File_get_errhandler(MPI_File file,
153                                              MPI_Errhandler *errhandler)
154 {
155   if (file == MPI_FILE_NULL) {
156     if (PyMPI_OPENMPI_FILE_NULL_ERRHANDLER == (MPI_Errhandler)0) {
157       PyMPI_OPENMPI_FILE_NULL_ERRHANDLER = MPI_ERRORS_RETURN;
158     }
159     *errhandler = PyMPI_OPENMPI_FILE_NULL_ERRHANDLER;
160     return MPI_SUCCESS;
161   }
162   return MPI_File_get_errhandler(file, errhandler);
163 }
164 #undef  MPI_File_get_errhandler
165 #define MPI_File_get_errhandler PyMPI_OPENMPI_File_get_errhandler
166 
PyMPI_OPENMPI_File_set_errhandler(MPI_File file,MPI_Errhandler errhandler)167 static int PyMPI_OPENMPI_File_set_errhandler(MPI_File file,
168                                              MPI_Errhandler errhandler)
169 {
170   int ierr = MPI_File_set_errhandler(file, errhandler);
171   if (ierr != MPI_SUCCESS) return ierr;
172   if (file == MPI_FILE_NULL) {
173     PyMPI_OPENMPI_FILE_NULL_ERRHANDLER = errhandler;
174   }
175   return ierr;
176 }
177 #undef  MPI_File_set_errhandler
178 #define MPI_File_set_errhandler PyMPI_OPENMPI_File_set_errhandler
179 
180 #endif /* !(PyMPI_OPENMPI_VERSION < 10200) */
181 
182 /* ---------------------------------------------------------------- */
183 
184 #if PyMPI_OPENMPI_VERSION < 10301
185 
PyMPI_OPENMPI_File_c2f(MPI_File file)186 static MPI_Fint PyMPI_OPENMPI_File_c2f(MPI_File file)
187 {
188   if (file == MPI_FILE_NULL) return (MPI_Fint)0;
189   return MPI_File_c2f(file);
190 }
191 #define MPI_File_c2f PyMPI_OPENMPI_File_c2f
192 
193 #endif /* !(PyMPI_OPENMPI_VERSION < 10301) */
194 
195 /* ------------------------------------------------------------------------- */
196 
197 #if PyMPI_OPENMPI_VERSION < 10402
198 
PyMPI_OPENMPI_MPI_Cancel(MPI_Request * request)199 static int PyMPI_OPENMPI_MPI_Cancel(MPI_Request *request)
200 {
201   if (request && *request == MPI_REQUEST_NULL) {
202     MPI_Comm_call_errhandler(MPI_COMM_WORLD, MPI_ERR_REQUEST);
203     return MPI_ERR_REQUEST;
204   }
205   return MPI_Cancel(request);
206 }
207 #undef  MPI_Cancel
208 #define MPI_Cancel PyMPI_OPENMPI_MPI_Cancel
209 
PyMPI_OPENMPI_MPI_Request_free(MPI_Request * request)210 static int PyMPI_OPENMPI_MPI_Request_free(MPI_Request *request)
211 {
212   if (request && *request == MPI_REQUEST_NULL) {
213     MPI_Comm_call_errhandler(MPI_COMM_WORLD, MPI_ERR_REQUEST);
214     return MPI_ERR_REQUEST;
215   }
216   return MPI_Request_free(request);
217 }
218 #undef  MPI_Request_free
219 #define MPI_Request_free PyMPI_OPENMPI_MPI_Request_free
220 
PyMPI_OPENMPI_MPI_Win_get_errhandler(MPI_Win win,MPI_Errhandler * errhandler)221 static int PyMPI_OPENMPI_MPI_Win_get_errhandler(MPI_Win win,
222                                                 MPI_Errhandler *errhandler)
223 {
224   if (win == MPI_WIN_NULL) {
225     MPI_Comm_call_errhandler(MPI_COMM_WORLD, MPI_ERR_WIN);
226     return MPI_ERR_WIN;
227   }
228   return MPI_Win_get_errhandler(win, errhandler);
229 }
230 #undef  MPI_Win_get_errhandler
231 #define MPI_Win_get_errhandler PyMPI_OPENMPI_MPI_Win_get_errhandler
232 
PyMPI_OPENMPI_MPI_Win_set_errhandler(MPI_Win win,MPI_Errhandler errhandler)233 static int PyMPI_OPENMPI_MPI_Win_set_errhandler(MPI_Win win,
234                                                 MPI_Errhandler errhandler)
235 {
236   if (win == MPI_WIN_NULL) {
237     MPI_Comm_call_errhandler(MPI_COMM_WORLD, MPI_ERR_WIN);
238     return MPI_ERR_WIN;
239   }
240   return MPI_Win_set_errhandler(win, errhandler);
241 }
242 #undef  MPI_Win_set_errhandler
243 #define MPI_Win_set_errhandler PyMPI_OPENMPI_MPI_Win_set_errhandler
244 
245 #endif /* !(PyMPI_OPENMPI_VERSION < 10402) */
246 
247 /* ------------------------------------------------------------------------- */
248 
249 #endif /* !PyMPI_COMPAT_OPENMPI_H */
250 
251 /*
252   Local Variables:
253   c-basic-offset: 2
254   indent-tabs-mode: nil
255   End:
256 */
257