1 1.1 mrg /* MPI implementation of GNU Fortran Coarray Library 2 1.1.1.3 mrg Copyright (C) 2011-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Tobias Burnus <burnus (at) net-b.de> 4 1.1 mrg 5 1.1 mrg This file is part of the GNU Fortran Coarray Runtime Library (libcaf). 6 1.1 mrg 7 1.1 mrg Libcaf is free software; you can redistribute it and/or modify 8 1.1 mrg it under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg Libcaf is distributed in the hope that it will be useful, 13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 mrg GNU General Public License for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg #include "libcaf.h" 27 1.1 mrg #include <stdio.h> 28 1.1 mrg #include <stdlib.h> 29 1.1 mrg #include <string.h> /* For memcpy. */ 30 1.1 mrg #include <stdarg.h> /* For variadic arguments. */ 31 1.1 mrg #include <mpi.h> 32 1.1 mrg 33 1.1 mrg 34 1.1 mrg /* Define GFC_CAF_CHECK to enable run-time checking. */ 35 1.1 mrg /* #define GFC_CAF_CHECK 1 */ 36 1.1 mrg 37 1.1 mrg typedef void ** mpi_token_t; 38 1.1 mrg #define TOKEN(X) ((mpi_token_t) (X)) 39 1.1 mrg 40 1.1 mrg static void error_stop (int error) __attribute__ ((noreturn)); 41 1.1 mrg 42 1.1 mrg /* Global variables. */ 43 1.1 mrg static int caf_mpi_initialized; 44 1.1 mrg static int caf_this_image; 45 1.1 mrg static int caf_num_images; 46 1.1 mrg static int caf_is_finalized; 47 1.1 mrg 48 1.1 mrg caf_static_t *caf_static_list = NULL; 49 1.1 mrg 50 1.1 mrg 51 1.1 mrg /* Keep in sync with single.c. */ 52 1.1 mrg static void 53 1.1 mrg caf_runtime_error (const char *message, ...) 54 1.1 mrg { 55 1.1 mrg va_list ap; 56 1.1 mrg fprintf (stderr, "Fortran runtime error on image %d: ", caf_this_image); 57 1.1 mrg va_start (ap, message); 58 1.1 mrg vfprintf (stderr, message, ap); 59 1.1 mrg va_end (ap); 60 1.1 mrg fprintf (stderr, "\n"); 61 1.1 mrg 62 1.1 mrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */ 63 1.1 mrg /* FIXME: Do some more effort than just MPI_ABORT. */ 64 1.1 mrg MPI_Abort (MPI_COMM_WORLD, EXIT_FAILURE); 65 1.1 mrg 66 1.1 mrg /* Should be unreachable, but to make sure also call exit. */ 67 1.1 mrg exit (EXIT_FAILURE); 68 1.1 mrg } 69 1.1 mrg 70 1.1 mrg 71 1.1 mrg /* Initialize coarray program. This routine assumes that no other 72 1.1 mrg MPI initialization happened before; otherwise MPI_Initialized 73 1.1 mrg had to be used. As the MPI library might modify the command-line 74 1.1 mrg arguments, the routine should be called before the run-time 75 1.1 mrg libaray is initialized. */ 76 1.1 mrg 77 1.1 mrg void 78 1.1 mrg _gfortran_caf_init (int *argc, char ***argv) 79 1.1 mrg { 80 1.1 mrg if (caf_num_images == 0) 81 1.1 mrg { 82 1.1 mrg /* caf_mpi_initialized is only true if the main program is 83 1.1 mrg not written in Fortran. */ 84 1.1 mrg MPI_Initialized (&caf_mpi_initialized); 85 1.1 mrg if (!caf_mpi_initialized) 86 1.1 mrg MPI_Init (argc, argv); 87 1.1 mrg 88 1.1 mrg MPI_Comm_size (MPI_COMM_WORLD, &caf_num_images); 89 1.1 mrg MPI_Comm_rank (MPI_COMM_WORLD, &caf_this_image); 90 1.1 mrg caf_this_image++; 91 1.1 mrg } 92 1.1 mrg } 93 1.1 mrg 94 1.1 mrg 95 1.1 mrg /* Finalize coarray program. */ 96 1.1 mrg 97 1.1 mrg void 98 1.1 mrg _gfortran_caf_finalize (void) 99 1.1 mrg { 100 1.1 mrg while (caf_static_list != NULL) 101 1.1 mrg { 102 1.1 mrg caf_static_t *tmp = caf_static_list->prev; 103 1.1 mrg 104 1.1 mrg free (TOKEN (caf_static_list->token)[caf_this_image-1]); 105 1.1 mrg free (TOKEN (caf_static_list->token)); 106 1.1 mrg free (caf_static_list); 107 1.1 mrg caf_static_list = tmp; 108 1.1 mrg } 109 1.1 mrg 110 1.1 mrg if (!caf_mpi_initialized) 111 1.1 mrg MPI_Finalize (); 112 1.1 mrg 113 1.1 mrg caf_is_finalized = 1; 114 1.1 mrg } 115 1.1 mrg 116 1.1 mrg 117 1.1 mrg int 118 1.1 mrg _gfortran_caf_this_image (int distance __attribute__ ((unused))) 119 1.1 mrg { 120 1.1 mrg return caf_this_image; 121 1.1 mrg } 122 1.1 mrg 123 1.1 mrg 124 1.1 mrg int 125 1.1 mrg _gfortran_caf_num_images (int distance __attribute__ ((unused)), 126 1.1 mrg int failed __attribute__ ((unused))) 127 1.1 mrg { 128 1.1 mrg return caf_num_images; 129 1.1 mrg } 130 1.1 mrg 131 1.1 mrg 132 1.1 mrg void * 133 1.1 mrg _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token, 134 1.1 mrg int *stat, char *errmsg, size_t errmsg_len, 135 1.1 mrg int num_alloc_comps __attribute__ ((unused))) 136 1.1 mrg { 137 1.1 mrg void *local; 138 1.1 mrg int err; 139 1.1 mrg 140 1.1 mrg if (unlikely (caf_is_finalized)) 141 1.1 mrg goto error; 142 1.1 mrg 143 1.1 mrg /* Start MPI if not already started. */ 144 1.1 mrg if (caf_num_images == 0) 145 1.1 mrg _gfortran_caf_init (NULL, NULL); 146 1.1 mrg 147 1.1 mrg /* Token contains only a list of pointers. */ 148 1.1 mrg local = malloc (size); 149 1.1 mrg *token = malloc (sizeof (mpi_token_t) * caf_num_images); 150 1.1 mrg 151 1.1 mrg if (unlikely (local == NULL || *token == NULL)) 152 1.1 mrg goto error; 153 1.1 mrg 154 1.1 mrg /* token[img-1] is the address of the token in image "img". */ 155 1.1 mrg err = MPI_Allgather (&local, sizeof (void*), MPI_BYTE, TOKEN (*token), 156 1.1 mrg sizeof (void*), MPI_BYTE, MPI_COMM_WORLD); 157 1.1 mrg 158 1.1 mrg if (unlikely (err)) 159 1.1 mrg { 160 1.1 mrg free (local); 161 1.1 mrg free (*token); 162 1.1 mrg goto error; 163 1.1 mrg } 164 1.1 mrg 165 1.1 mrg if (type == CAF_REGTYPE_COARRAY_STATIC) 166 1.1 mrg { 167 1.1 mrg caf_static_t *tmp = malloc (sizeof (caf_static_t)); 168 1.1 mrg tmp->prev = caf_static_list; 169 1.1 mrg tmp->token = *token; 170 1.1 mrg caf_static_list = tmp; 171 1.1 mrg } 172 1.1 mrg 173 1.1 mrg if (stat) 174 1.1 mrg *stat = 0; 175 1.1 mrg 176 1.1 mrg return local; 177 1.1 mrg 178 1.1 mrg error: 179 1.1 mrg { 180 1.1 mrg char *msg; 181 1.1 mrg 182 1.1 mrg if (caf_is_finalized) 183 1.1 mrg msg = "Failed to allocate coarray - there are stopped images"; 184 1.1 mrg else 185 1.1 mrg msg = "Failed to allocate coarray"; 186 1.1 mrg 187 1.1 mrg if (stat) 188 1.1 mrg { 189 1.1 mrg *stat = caf_is_finalized ? STAT_STOPPED_IMAGE : 1; 190 1.1 mrg if (errmsg_len > 0) 191 1.1 mrg { 192 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len 193 1.1 mrg : strlen (msg); 194 1.1 mrg memcpy (errmsg, msg, len); 195 1.1 mrg if (errmsg_len > len) 196 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len); 197 1.1 mrg } 198 1.1 mrg } 199 1.1 mrg else 200 1.1 mrg caf_runtime_error (msg); 201 1.1 mrg } 202 1.1 mrg 203 1.1 mrg return NULL; 204 1.1 mrg } 205 1.1 mrg 206 1.1 mrg 207 1.1 mrg void 208 1.1 mrg _gfortran_caf_deregister (caf_token_t *token, int *stat, char *errmsg, size_t errmsg_len) 209 1.1 mrg { 210 1.1 mrg if (unlikely (caf_is_finalized)) 211 1.1 mrg { 212 1.1 mrg const char msg[] = "Failed to deallocate coarray - " 213 1.1 mrg "there are stopped images"; 214 1.1 mrg if (stat) 215 1.1 mrg { 216 1.1 mrg *stat = STAT_STOPPED_IMAGE; 217 1.1 mrg 218 1.1 mrg if (errmsg_len > 0) 219 1.1 mrg { 220 1.1 mrg size_t len = (sizeof (msg) - 1 > errmsg_len) 221 1.1 mrg ? errmsg_len : sizeof (msg) - 1; 222 1.1 mrg memcpy (errmsg, msg, len); 223 1.1 mrg if (errmsg_len > len) 224 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len); 225 1.1 mrg } 226 1.1 mrg return; 227 1.1 mrg } 228 1.1 mrg caf_runtime_error (msg); 229 1.1 mrg } 230 1.1 mrg 231 1.1 mrg _gfortran_caf_sync_all (NULL, NULL, 0); 232 1.1 mrg 233 1.1 mrg if (stat) 234 1.1 mrg *stat = 0; 235 1.1 mrg 236 1.1 mrg free (TOKEN (*token)[caf_this_image-1]); 237 1.1 mrg free (*token); 238 1.1 mrg } 239 1.1 mrg 240 1.1 mrg 241 1.1 mrg void 242 1.1 mrg _gfortran_caf_sync_all (int *stat, char *errmsg, size_t errmsg_len) 243 1.1 mrg { 244 1.1 mrg int ierr; 245 1.1 mrg 246 1.1 mrg if (unlikely (caf_is_finalized)) 247 1.1 mrg ierr = STAT_STOPPED_IMAGE; 248 1.1 mrg else 249 1.1 mrg ierr = MPI_Barrier (MPI_COMM_WORLD); 250 1.1 mrg 251 1.1 mrg if (stat) 252 1.1 mrg *stat = ierr; 253 1.1 mrg 254 1.1 mrg if (ierr) 255 1.1 mrg { 256 1.1 mrg char *msg; 257 1.1 mrg if (caf_is_finalized) 258 1.1 mrg msg = "SYNC ALL failed - there are stopped images"; 259 1.1 mrg else 260 1.1 mrg msg = "SYNC ALL failed"; 261 1.1 mrg 262 1.1 mrg if (errmsg_len > 0) 263 1.1 mrg { 264 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len 265 1.1 mrg : strlen (msg); 266 1.1 mrg memcpy (errmsg, msg, len); 267 1.1 mrg if (errmsg_len > len) 268 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len); 269 1.1 mrg } 270 1.1 mrg else 271 1.1 mrg caf_runtime_error (msg); 272 1.1 mrg } 273 1.1 mrg } 274 1.1 mrg 275 1.1 mrg 276 1.1 mrg /* SYNC IMAGES. Note: SYNC IMAGES(*) is passed as count == -1 while 277 1.1 mrg SYNC IMAGES([]) has count == 0. Note further that SYNC IMAGES(*) 278 1.1 mrg is not equivalent to SYNC ALL. */ 279 1.1 mrg void 280 1.1 mrg _gfortran_caf_sync_images (int count, int images[], int *stat, char *errmsg, 281 1.1 mrg size_t errmsg_len) 282 1.1 mrg { 283 1.1 mrg int ierr; 284 1.1 mrg if (count == 0 || (count == 1 && images[0] == caf_this_image)) 285 1.1 mrg { 286 1.1 mrg if (stat) 287 1.1 mrg *stat = 0; 288 1.1 mrg return; 289 1.1 mrg } 290 1.1 mrg 291 1.1 mrg #ifdef GFC_CAF_CHECK 292 1.1 mrg { 293 1.1 mrg int i; 294 1.1 mrg 295 1.1 mrg for (i = 0; i < count; i++) 296 1.1 mrg if (images[i] < 1 || images[i] > caf_num_images) 297 1.1 mrg { 298 1.1 mrg fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC " 299 1.1 mrg "IMAGES", images[i]); 300 1.1 mrg error_stop (1); 301 1.1 mrg } 302 1.1 mrg } 303 1.1 mrg #endif 304 1.1 mrg 305 1.1 mrg /* FIXME: SYNC IMAGES with a nontrivial argument cannot easily be 306 1.1 mrg mapped to MPI communicators. Thus, exist early with an error message. */ 307 1.1 mrg if (count > 0) 308 1.1 mrg { 309 1.1 mrg fprintf (stderr, "COARRAY ERROR: SYNC IMAGES not yet implemented"); 310 1.1 mrg error_stop (1); 311 1.1 mrg } 312 1.1 mrg 313 1.1 mrg /* Handle SYNC IMAGES(*). */ 314 1.1 mrg if (unlikely (caf_is_finalized)) 315 1.1 mrg ierr = STAT_STOPPED_IMAGE; 316 1.1 mrg else 317 1.1 mrg ierr = MPI_Barrier (MPI_COMM_WORLD); 318 1.1 mrg 319 1.1 mrg if (stat) 320 1.1 mrg *stat = ierr; 321 1.1 mrg 322 1.1 mrg if (ierr) 323 1.1 mrg { 324 1.1 mrg char *msg; 325 1.1 mrg if (caf_is_finalized) 326 1.1 mrg msg = "SYNC IMAGES failed - there are stopped images"; 327 1.1 mrg else 328 1.1 mrg msg = "SYNC IMAGES failed"; 329 1.1 mrg 330 1.1 mrg if (errmsg_len > 0) 331 1.1 mrg { 332 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len 333 1.1 mrg : strlen (msg); 334 1.1 mrg memcpy (errmsg, msg, len); 335 1.1 mrg if (errmsg_len > len) 336 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len); 337 1.1 mrg } 338 1.1 mrg else 339 1.1 mrg caf_runtime_error (msg); 340 1.1 mrg } 341 1.1 mrg } 342 1.1 mrg 343 1.1 mrg 344 1.1 mrg /* ERROR STOP the other images. */ 345 1.1 mrg 346 1.1 mrg static void 347 1.1 mrg error_stop (int error) 348 1.1 mrg { 349 1.1 mrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */ 350 1.1 mrg /* FIXME: Do some more effort than just MPI_ABORT. */ 351 1.1 mrg MPI_Abort (MPI_COMM_WORLD, error); 352 1.1 mrg 353 1.1 mrg /* Should be unreachable, but to make sure also call exit. */ 354 1.1 mrg exit (error); 355 1.1 mrg } 356 1.1 mrg 357 1.1 mrg 358 1.1 mrg /* ERROR STOP function for string arguments. */ 359 1.1 mrg 360 1.1 mrg void 361 1.1 mrg _gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet) 362 1.1 mrg { 363 1.1 mrg if (!quiet) 364 1.1 mrg { 365 1.1 mrg fputs ("ERROR STOP ", stderr); 366 1.1 mrg while (len--) 367 1.1 mrg fputc (*(string++), stderr); 368 1.1 mrg fputs ("\n", stderr); 369 1.1 mrg } 370 1.1 mrg error_stop (1); 371 1.1 mrg } 372 1.1 mrg 373 1.1 mrg 374 1.1 mrg /* ERROR STOP function for numerical arguments. */ 375 1.1 mrg 376 1.1 mrg void 377 1.1 mrg _gfortran_caf_error_stop (int error, bool quiet) 378 1.1 mrg { 379 1.1 mrg if (!quiet) 380 1.1 mrg fprintf (stderr, "ERROR STOP %d\n", error); 381 1.1 mrg error_stop (error); 382 1.1 mrg } 383