123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /* MPI implementation of GNU Fortran Coarray Library
- Copyright (C) 2011-2015 Free Software Foundation, Inc.
- Contributed by Tobias Burnus <burnus@net-b.de>
- This file is part of the GNU Fortran Coarray Runtime Library (libcaf).
- Libcaf is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- Libcaf 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 General Public License for more details.
- Under Section 7 of GPL version 3, you are granted additional
- permissions described in the GCC Runtime Library Exception, version
- 3.1, as published by the Free Software Foundation.
- You should have received a copy of the GNU General Public License and
- a copy of the GCC Runtime Library Exception along with this program;
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- <http://www.gnu.org/licenses/>. */
- #include "libcaf.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h> /* For memcpy. */
- #include <stdarg.h> /* For variadic arguments. */
- #include <mpi.h>
- /* Define GFC_CAF_CHECK to enable run-time checking. */
- /* #define GFC_CAF_CHECK 1 */
- typedef void ** mpi_token_t;
- #define TOKEN(X) ((mpi_token_t) (X))
- static void error_stop (int error) __attribute__ ((noreturn));
- /* Global variables. */
- static int caf_mpi_initialized;
- static int caf_this_image;
- static int caf_num_images;
- static int caf_is_finalized;
- caf_static_t *caf_static_list = NULL;
- /* Keep in sync with single.c. */
- static void
- caf_runtime_error (const char *message, ...)
- {
- va_list ap;
- fprintf (stderr, "Fortran runtime error on image %d: ", caf_this_image);
- va_start (ap, message);
- vfprintf (stderr, message, ap);
- va_end (ap);
- fprintf (stderr, "\n");
- /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
- /* FIXME: Do some more effort than just MPI_ABORT. */
- MPI_Abort (MPI_COMM_WORLD, EXIT_FAILURE);
- /* Should be unreachable, but to make sure also call exit. */
- exit (EXIT_FAILURE);
- }
- /* Initialize coarray program. This routine assumes that no other
- MPI initialization happened before; otherwise MPI_Initialized
- had to be used. As the MPI library might modify the command-line
- arguments, the routine should be called before the run-time
- libaray is initialized. */
- void
- _gfortran_caf_init (int *argc, char ***argv)
- {
- if (caf_num_images == 0)
- {
- /* caf_mpi_initialized is only true if the main program is
- not written in Fortran. */
- MPI_Initialized (&caf_mpi_initialized);
- if (!caf_mpi_initialized)
- MPI_Init (argc, argv);
- MPI_Comm_size (MPI_COMM_WORLD, &caf_num_images);
- MPI_Comm_rank (MPI_COMM_WORLD, &caf_this_image);
- caf_this_image++;
- }
- }
- /* Finalize coarray program. */
- void
- _gfortran_caf_finalize (void)
- {
- while (caf_static_list != NULL)
- {
- caf_static_t *tmp = caf_static_list->prev;
- free (TOKEN (caf_static_list->token)[caf_this_image-1]);
- free (TOKEN (caf_static_list->token));
- free (caf_static_list);
- caf_static_list = tmp;
- }
- if (!caf_mpi_initialized)
- MPI_Finalize ();
- caf_is_finalized = 1;
- }
- int
- _gfortran_caf_this_image (int distance __attribute__ ((unused)))
- {
- return caf_this_image;
- }
- int
- _gfortran_caf_num_images (int distance __attribute__ ((unused)),
- int failed __attribute__ ((unused)))
- {
- return caf_num_images;
- }
- void *
- _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
- int *stat, char *errmsg, int errmsg_len)
- {
- void *local;
- int err;
- if (unlikely (caf_is_finalized))
- goto error;
- /* Start MPI if not already started. */
- if (caf_num_images == 0)
- _gfortran_caf_init (NULL, NULL);
- /* Token contains only a list of pointers. */
- local = malloc (size);
- *token = malloc (sizeof (mpi_token_t) * caf_num_images);
- if (unlikely (local == NULL || *token == NULL))
- goto error;
- /* token[img-1] is the address of the token in image "img". */
- err = MPI_Allgather (&local, sizeof (void*), MPI_BYTE, TOKEN (*token),
- sizeof (void*), MPI_BYTE, MPI_COMM_WORLD);
- if (unlikely (err))
- {
- free (local);
- free (*token);
- goto error;
- }
- if (type == CAF_REGTYPE_COARRAY_STATIC)
- {
- caf_static_t *tmp = malloc (sizeof (caf_static_t));
- tmp->prev = caf_static_list;
- tmp->token = *token;
- caf_static_list = tmp;
- }
- if (stat)
- *stat = 0;
- return local;
- error:
- {
- char *msg;
- if (caf_is_finalized)
- msg = "Failed to allocate coarray - there are stopped images";
- else
- msg = "Failed to allocate coarray";
- if (stat)
- {
- *stat = caf_is_finalized ? STAT_STOPPED_IMAGE : 1;
- if (errmsg_len > 0)
- {
- int len = ((int) strlen (msg) > errmsg_len) ? errmsg_len
- : (int) strlen (msg);
- memcpy (errmsg, msg, len);
- if (errmsg_len > len)
- memset (&errmsg[len], ' ', errmsg_len-len);
- }
- }
- else
- caf_runtime_error (msg);
- }
- return NULL;
- }
- void
- _gfortran_caf_deregister (caf_token_t *token, int *stat, char *errmsg, int errmsg_len)
- {
- if (unlikely (caf_is_finalized))
- {
- const char msg[] = "Failed to deallocate coarray - "
- "there are stopped images";
- if (stat)
- {
- *stat = STAT_STOPPED_IMAGE;
-
- if (errmsg_len > 0)
- {
- int len = ((int) sizeof (msg) - 1 > errmsg_len)
- ? errmsg_len : (int) sizeof (msg) - 1;
- memcpy (errmsg, msg, len);
- if (errmsg_len > len)
- memset (&errmsg[len], ' ', errmsg_len-len);
- }
- return;
- }
- caf_runtime_error (msg);
- }
- _gfortran_caf_sync_all (NULL, NULL, 0);
- if (stat)
- *stat = 0;
- free (TOKEN (*token)[caf_this_image-1]);
- free (*token);
- }
- void
- _gfortran_caf_sync_all (int *stat, char *errmsg, int errmsg_len)
- {
- int ierr;
- if (unlikely (caf_is_finalized))
- ierr = STAT_STOPPED_IMAGE;
- else
- ierr = MPI_Barrier (MPI_COMM_WORLD);
-
- if (stat)
- *stat = ierr;
- if (ierr)
- {
- char *msg;
- if (caf_is_finalized)
- msg = "SYNC ALL failed - there are stopped images";
- else
- msg = "SYNC ALL failed";
- if (errmsg_len > 0)
- {
- int len = ((int) strlen (msg) > errmsg_len) ? errmsg_len
- : (int) strlen (msg);
- memcpy (errmsg, msg, len);
- if (errmsg_len > len)
- memset (&errmsg[len], ' ', errmsg_len-len);
- }
- else
- caf_runtime_error (msg);
- }
- }
- /* SYNC IMAGES. Note: SYNC IMAGES(*) is passed as count == -1 while
- SYNC IMAGES([]) has count == 0. Note further that SYNC IMAGES(*)
- is not equivalent to SYNC ALL. */
- void
- _gfortran_caf_sync_images (int count, int images[], int *stat, char *errmsg,
- int errmsg_len)
- {
- int ierr;
- if (count == 0 || (count == 1 && images[0] == caf_this_image))
- {
- if (stat)
- *stat = 0;
- return;
- }
- #ifdef GFC_CAF_CHECK
- {
- int i;
- for (i = 0; i < count; i++)
- if (images[i] < 1 || images[i] > caf_num_images)
- {
- fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
- "IMAGES", images[i]);
- error_stop (1);
- }
- }
- #endif
- /* FIXME: SYNC IMAGES with a nontrivial argument cannot easily be
- mapped to MPI communicators. Thus, exist early with an error message. */
- if (count > 0)
- {
- fprintf (stderr, "COARRAY ERROR: SYNC IMAGES not yet implemented");
- error_stop (1);
- }
- /* Handle SYNC IMAGES(*). */
- if (unlikely (caf_is_finalized))
- ierr = STAT_STOPPED_IMAGE;
- else
- ierr = MPI_Barrier (MPI_COMM_WORLD);
- if (stat)
- *stat = ierr;
- if (ierr)
- {
- char *msg;
- if (caf_is_finalized)
- msg = "SYNC IMAGES failed - there are stopped images";
- else
- msg = "SYNC IMAGES failed";
- if (errmsg_len > 0)
- {
- int len = ((int) strlen (msg) > errmsg_len) ? errmsg_len
- : (int) strlen (msg);
- memcpy (errmsg, msg, len);
- if (errmsg_len > len)
- memset (&errmsg[len], ' ', errmsg_len-len);
- }
- else
- caf_runtime_error (msg);
- }
- }
- /* ERROR STOP the other images. */
- static void
- error_stop (int error)
- {
- /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
- /* FIXME: Do some more effort than just MPI_ABORT. */
- MPI_Abort (MPI_COMM_WORLD, error);
- /* Should be unreachable, but to make sure also call exit. */
- exit (error);
- }
- /* ERROR STOP function for string arguments. */
- void
- _gfortran_caf_error_stop_str (const char *string, int32_t len)
- {
- fputs ("ERROR STOP ", stderr);
- while (len--)
- fputc (*(string++), stderr);
- fputs ("\n", stderr);
- error_stop (1);
- }
- /* ERROR STOP function for numerical arguments. */
- void
- _gfortran_caf_error_stop (int32_t error)
- {
- fprintf (stderr, "ERROR STOP %d\n", error);
- error_stop (error);
- }
|