Home | History | Annotate | Line # | Download | only in caf
      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