1627f7eb2Smrg /* MPI implementation of GNU Fortran Coarray Library
2*4c3eb207Smrg Copyright (C) 2011-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Tobias Burnus <burnus@net-b.de>
4627f7eb2Smrg
5627f7eb2Smrg This file is part of the GNU Fortran Coarray Runtime Library (libcaf).
6627f7eb2Smrg
7627f7eb2Smrg Libcaf is free software; you can redistribute it and/or modify
8627f7eb2Smrg it under the terms of the GNU General Public License as published by
9627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
10627f7eb2Smrg any later version.
11627f7eb2Smrg
12627f7eb2Smrg Libcaf is distributed in the hope that it will be useful,
13627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15627f7eb2Smrg GNU General Public License for more details.
16627f7eb2Smrg
17627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg 3.1, as published by the Free Software Foundation.
20627f7eb2Smrg
21627f7eb2Smrg You should have received a copy of the GNU General Public License and
22627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24627f7eb2Smrg <http://www.gnu.org/licenses/>. */
25627f7eb2Smrg
26627f7eb2Smrg #include "libcaf.h"
27627f7eb2Smrg #include <stdio.h>
28627f7eb2Smrg #include <stdlib.h>
29627f7eb2Smrg #include <string.h> /* For memcpy. */
30627f7eb2Smrg #include <stdarg.h> /* For variadic arguments. */
31627f7eb2Smrg #include <mpi.h>
32627f7eb2Smrg
33627f7eb2Smrg
34627f7eb2Smrg /* Define GFC_CAF_CHECK to enable run-time checking. */
35627f7eb2Smrg /* #define GFC_CAF_CHECK 1 */
36627f7eb2Smrg
37627f7eb2Smrg typedef void ** mpi_token_t;
38627f7eb2Smrg #define TOKEN(X) ((mpi_token_t) (X))
39627f7eb2Smrg
40627f7eb2Smrg static void error_stop (int error) __attribute__ ((noreturn));
41627f7eb2Smrg
42627f7eb2Smrg /* Global variables. */
43627f7eb2Smrg static int caf_mpi_initialized;
44627f7eb2Smrg static int caf_this_image;
45627f7eb2Smrg static int caf_num_images;
46627f7eb2Smrg static int caf_is_finalized;
47627f7eb2Smrg
48627f7eb2Smrg caf_static_t *caf_static_list = NULL;
49627f7eb2Smrg
50627f7eb2Smrg
51627f7eb2Smrg /* Keep in sync with single.c. */
52627f7eb2Smrg static void
caf_runtime_error(const char * message,...)53627f7eb2Smrg caf_runtime_error (const char *message, ...)
54627f7eb2Smrg {
55627f7eb2Smrg va_list ap;
56627f7eb2Smrg fprintf (stderr, "Fortran runtime error on image %d: ", caf_this_image);
57627f7eb2Smrg va_start (ap, message);
58627f7eb2Smrg vfprintf (stderr, message, ap);
59627f7eb2Smrg va_end (ap);
60627f7eb2Smrg fprintf (stderr, "\n");
61627f7eb2Smrg
62627f7eb2Smrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
63627f7eb2Smrg /* FIXME: Do some more effort than just MPI_ABORT. */
64627f7eb2Smrg MPI_Abort (MPI_COMM_WORLD, EXIT_FAILURE);
65627f7eb2Smrg
66627f7eb2Smrg /* Should be unreachable, but to make sure also call exit. */
67627f7eb2Smrg exit (EXIT_FAILURE);
68627f7eb2Smrg }
69627f7eb2Smrg
70627f7eb2Smrg
71627f7eb2Smrg /* Initialize coarray program. This routine assumes that no other
72627f7eb2Smrg MPI initialization happened before; otherwise MPI_Initialized
73627f7eb2Smrg had to be used. As the MPI library might modify the command-line
74627f7eb2Smrg arguments, the routine should be called before the run-time
75627f7eb2Smrg libaray is initialized. */
76627f7eb2Smrg
77627f7eb2Smrg void
_gfortran_caf_init(int * argc,char *** argv)78627f7eb2Smrg _gfortran_caf_init (int *argc, char ***argv)
79627f7eb2Smrg {
80627f7eb2Smrg if (caf_num_images == 0)
81627f7eb2Smrg {
82627f7eb2Smrg /* caf_mpi_initialized is only true if the main program is
83627f7eb2Smrg not written in Fortran. */
84627f7eb2Smrg MPI_Initialized (&caf_mpi_initialized);
85627f7eb2Smrg if (!caf_mpi_initialized)
86627f7eb2Smrg MPI_Init (argc, argv);
87627f7eb2Smrg
88627f7eb2Smrg MPI_Comm_size (MPI_COMM_WORLD, &caf_num_images);
89627f7eb2Smrg MPI_Comm_rank (MPI_COMM_WORLD, &caf_this_image);
90627f7eb2Smrg caf_this_image++;
91627f7eb2Smrg }
92627f7eb2Smrg }
93627f7eb2Smrg
94627f7eb2Smrg
95627f7eb2Smrg /* Finalize coarray program. */
96627f7eb2Smrg
97627f7eb2Smrg void
_gfortran_caf_finalize(void)98627f7eb2Smrg _gfortran_caf_finalize (void)
99627f7eb2Smrg {
100627f7eb2Smrg while (caf_static_list != NULL)
101627f7eb2Smrg {
102627f7eb2Smrg caf_static_t *tmp = caf_static_list->prev;
103627f7eb2Smrg
104627f7eb2Smrg free (TOKEN (caf_static_list->token)[caf_this_image-1]);
105627f7eb2Smrg free (TOKEN (caf_static_list->token));
106627f7eb2Smrg free (caf_static_list);
107627f7eb2Smrg caf_static_list = tmp;
108627f7eb2Smrg }
109627f7eb2Smrg
110627f7eb2Smrg if (!caf_mpi_initialized)
111627f7eb2Smrg MPI_Finalize ();
112627f7eb2Smrg
113627f7eb2Smrg caf_is_finalized = 1;
114627f7eb2Smrg }
115627f7eb2Smrg
116627f7eb2Smrg
117627f7eb2Smrg int
_gfortran_caf_this_image(int distance)118627f7eb2Smrg _gfortran_caf_this_image (int distance __attribute__ ((unused)))
119627f7eb2Smrg {
120627f7eb2Smrg return caf_this_image;
121627f7eb2Smrg }
122627f7eb2Smrg
123627f7eb2Smrg
124627f7eb2Smrg int
_gfortran_caf_num_images(int distance,int failed)125627f7eb2Smrg _gfortran_caf_num_images (int distance __attribute__ ((unused)),
126627f7eb2Smrg int failed __attribute__ ((unused)))
127627f7eb2Smrg {
128627f7eb2Smrg return caf_num_images;
129627f7eb2Smrg }
130627f7eb2Smrg
131627f7eb2Smrg
132627f7eb2Smrg void *
_gfortran_caf_register(size_t size,caf_register_t type,caf_token_t * token,int * stat,char * errmsg,size_t errmsg_len,int num_alloc_comps)133627f7eb2Smrg _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
134627f7eb2Smrg int *stat, char *errmsg, size_t errmsg_len,
135627f7eb2Smrg int num_alloc_comps __attribute__ ((unused)))
136627f7eb2Smrg {
137627f7eb2Smrg void *local;
138627f7eb2Smrg int err;
139627f7eb2Smrg
140627f7eb2Smrg if (unlikely (caf_is_finalized))
141627f7eb2Smrg goto error;
142627f7eb2Smrg
143627f7eb2Smrg /* Start MPI if not already started. */
144627f7eb2Smrg if (caf_num_images == 0)
145627f7eb2Smrg _gfortran_caf_init (NULL, NULL);
146627f7eb2Smrg
147627f7eb2Smrg /* Token contains only a list of pointers. */
148627f7eb2Smrg local = malloc (size);
149627f7eb2Smrg *token = malloc (sizeof (mpi_token_t) * caf_num_images);
150627f7eb2Smrg
151627f7eb2Smrg if (unlikely (local == NULL || *token == NULL))
152627f7eb2Smrg goto error;
153627f7eb2Smrg
154627f7eb2Smrg /* token[img-1] is the address of the token in image "img". */
155627f7eb2Smrg err = MPI_Allgather (&local, sizeof (void*), MPI_BYTE, TOKEN (*token),
156627f7eb2Smrg sizeof (void*), MPI_BYTE, MPI_COMM_WORLD);
157627f7eb2Smrg
158627f7eb2Smrg if (unlikely (err))
159627f7eb2Smrg {
160627f7eb2Smrg free (local);
161627f7eb2Smrg free (*token);
162627f7eb2Smrg goto error;
163627f7eb2Smrg }
164627f7eb2Smrg
165627f7eb2Smrg if (type == CAF_REGTYPE_COARRAY_STATIC)
166627f7eb2Smrg {
167627f7eb2Smrg caf_static_t *tmp = malloc (sizeof (caf_static_t));
168627f7eb2Smrg tmp->prev = caf_static_list;
169627f7eb2Smrg tmp->token = *token;
170627f7eb2Smrg caf_static_list = tmp;
171627f7eb2Smrg }
172627f7eb2Smrg
173627f7eb2Smrg if (stat)
174627f7eb2Smrg *stat = 0;
175627f7eb2Smrg
176627f7eb2Smrg return local;
177627f7eb2Smrg
178627f7eb2Smrg error:
179627f7eb2Smrg {
180627f7eb2Smrg char *msg;
181627f7eb2Smrg
182627f7eb2Smrg if (caf_is_finalized)
183627f7eb2Smrg msg = "Failed to allocate coarray - there are stopped images";
184627f7eb2Smrg else
185627f7eb2Smrg msg = "Failed to allocate coarray";
186627f7eb2Smrg
187627f7eb2Smrg if (stat)
188627f7eb2Smrg {
189627f7eb2Smrg *stat = caf_is_finalized ? STAT_STOPPED_IMAGE : 1;
190627f7eb2Smrg if (errmsg_len > 0)
191627f7eb2Smrg {
192627f7eb2Smrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
193627f7eb2Smrg : strlen (msg);
194627f7eb2Smrg memcpy (errmsg, msg, len);
195627f7eb2Smrg if (errmsg_len > len)
196627f7eb2Smrg memset (&errmsg[len], ' ', errmsg_len-len);
197627f7eb2Smrg }
198627f7eb2Smrg }
199627f7eb2Smrg else
200627f7eb2Smrg caf_runtime_error (msg);
201627f7eb2Smrg }
202627f7eb2Smrg
203627f7eb2Smrg return NULL;
204627f7eb2Smrg }
205627f7eb2Smrg
206627f7eb2Smrg
207627f7eb2Smrg void
_gfortran_caf_deregister(caf_token_t * token,int * stat,char * errmsg,size_t errmsg_len)208627f7eb2Smrg _gfortran_caf_deregister (caf_token_t *token, int *stat, char *errmsg, size_t errmsg_len)
209627f7eb2Smrg {
210627f7eb2Smrg if (unlikely (caf_is_finalized))
211627f7eb2Smrg {
212627f7eb2Smrg const char msg[] = "Failed to deallocate coarray - "
213627f7eb2Smrg "there are stopped images";
214627f7eb2Smrg if (stat)
215627f7eb2Smrg {
216627f7eb2Smrg *stat = STAT_STOPPED_IMAGE;
217627f7eb2Smrg
218627f7eb2Smrg if (errmsg_len > 0)
219627f7eb2Smrg {
220627f7eb2Smrg size_t len = (sizeof (msg) - 1 > errmsg_len)
221627f7eb2Smrg ? errmsg_len : sizeof (msg) - 1;
222627f7eb2Smrg memcpy (errmsg, msg, len);
223627f7eb2Smrg if (errmsg_len > len)
224627f7eb2Smrg memset (&errmsg[len], ' ', errmsg_len-len);
225627f7eb2Smrg }
226627f7eb2Smrg return;
227627f7eb2Smrg }
228627f7eb2Smrg caf_runtime_error (msg);
229627f7eb2Smrg }
230627f7eb2Smrg
231627f7eb2Smrg _gfortran_caf_sync_all (NULL, NULL, 0);
232627f7eb2Smrg
233627f7eb2Smrg if (stat)
234627f7eb2Smrg *stat = 0;
235627f7eb2Smrg
236627f7eb2Smrg free (TOKEN (*token)[caf_this_image-1]);
237627f7eb2Smrg free (*token);
238627f7eb2Smrg }
239627f7eb2Smrg
240627f7eb2Smrg
241627f7eb2Smrg void
_gfortran_caf_sync_all(int * stat,char * errmsg,size_t errmsg_len)242627f7eb2Smrg _gfortran_caf_sync_all (int *stat, char *errmsg, size_t errmsg_len)
243627f7eb2Smrg {
244627f7eb2Smrg int ierr;
245627f7eb2Smrg
246627f7eb2Smrg if (unlikely (caf_is_finalized))
247627f7eb2Smrg ierr = STAT_STOPPED_IMAGE;
248627f7eb2Smrg else
249627f7eb2Smrg ierr = MPI_Barrier (MPI_COMM_WORLD);
250627f7eb2Smrg
251627f7eb2Smrg if (stat)
252627f7eb2Smrg *stat = ierr;
253627f7eb2Smrg
254627f7eb2Smrg if (ierr)
255627f7eb2Smrg {
256627f7eb2Smrg char *msg;
257627f7eb2Smrg if (caf_is_finalized)
258627f7eb2Smrg msg = "SYNC ALL failed - there are stopped images";
259627f7eb2Smrg else
260627f7eb2Smrg msg = "SYNC ALL failed";
261627f7eb2Smrg
262627f7eb2Smrg if (errmsg_len > 0)
263627f7eb2Smrg {
264627f7eb2Smrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
265627f7eb2Smrg : strlen (msg);
266627f7eb2Smrg memcpy (errmsg, msg, len);
267627f7eb2Smrg if (errmsg_len > len)
268627f7eb2Smrg memset (&errmsg[len], ' ', errmsg_len-len);
269627f7eb2Smrg }
270627f7eb2Smrg else
271627f7eb2Smrg caf_runtime_error (msg);
272627f7eb2Smrg }
273627f7eb2Smrg }
274627f7eb2Smrg
275627f7eb2Smrg
276627f7eb2Smrg /* SYNC IMAGES. Note: SYNC IMAGES(*) is passed as count == -1 while
277627f7eb2Smrg SYNC IMAGES([]) has count == 0. Note further that SYNC IMAGES(*)
278627f7eb2Smrg is not equivalent to SYNC ALL. */
279627f7eb2Smrg void
_gfortran_caf_sync_images(int count,int images[],int * stat,char * errmsg,size_t errmsg_len)280627f7eb2Smrg _gfortran_caf_sync_images (int count, int images[], int *stat, char *errmsg,
281627f7eb2Smrg size_t errmsg_len)
282627f7eb2Smrg {
283627f7eb2Smrg int ierr;
284627f7eb2Smrg if (count == 0 || (count == 1 && images[0] == caf_this_image))
285627f7eb2Smrg {
286627f7eb2Smrg if (stat)
287627f7eb2Smrg *stat = 0;
288627f7eb2Smrg return;
289627f7eb2Smrg }
290627f7eb2Smrg
291627f7eb2Smrg #ifdef GFC_CAF_CHECK
292627f7eb2Smrg {
293627f7eb2Smrg int i;
294627f7eb2Smrg
295627f7eb2Smrg for (i = 0; i < count; i++)
296627f7eb2Smrg if (images[i] < 1 || images[i] > caf_num_images)
297627f7eb2Smrg {
298627f7eb2Smrg fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
299627f7eb2Smrg "IMAGES", images[i]);
300627f7eb2Smrg error_stop (1);
301627f7eb2Smrg }
302627f7eb2Smrg }
303627f7eb2Smrg #endif
304627f7eb2Smrg
305627f7eb2Smrg /* FIXME: SYNC IMAGES with a nontrivial argument cannot easily be
306627f7eb2Smrg mapped to MPI communicators. Thus, exist early with an error message. */
307627f7eb2Smrg if (count > 0)
308627f7eb2Smrg {
309627f7eb2Smrg fprintf (stderr, "COARRAY ERROR: SYNC IMAGES not yet implemented");
310627f7eb2Smrg error_stop (1);
311627f7eb2Smrg }
312627f7eb2Smrg
313627f7eb2Smrg /* Handle SYNC IMAGES(*). */
314627f7eb2Smrg if (unlikely (caf_is_finalized))
315627f7eb2Smrg ierr = STAT_STOPPED_IMAGE;
316627f7eb2Smrg else
317627f7eb2Smrg ierr = MPI_Barrier (MPI_COMM_WORLD);
318627f7eb2Smrg
319627f7eb2Smrg if (stat)
320627f7eb2Smrg *stat = ierr;
321627f7eb2Smrg
322627f7eb2Smrg if (ierr)
323627f7eb2Smrg {
324627f7eb2Smrg char *msg;
325627f7eb2Smrg if (caf_is_finalized)
326627f7eb2Smrg msg = "SYNC IMAGES failed - there are stopped images";
327627f7eb2Smrg else
328627f7eb2Smrg msg = "SYNC IMAGES failed";
329627f7eb2Smrg
330627f7eb2Smrg if (errmsg_len > 0)
331627f7eb2Smrg {
332627f7eb2Smrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
333627f7eb2Smrg : strlen (msg);
334627f7eb2Smrg memcpy (errmsg, msg, len);
335627f7eb2Smrg if (errmsg_len > len)
336627f7eb2Smrg memset (&errmsg[len], ' ', errmsg_len-len);
337627f7eb2Smrg }
338627f7eb2Smrg else
339627f7eb2Smrg caf_runtime_error (msg);
340627f7eb2Smrg }
341627f7eb2Smrg }
342627f7eb2Smrg
343627f7eb2Smrg
344627f7eb2Smrg /* ERROR STOP the other images. */
345627f7eb2Smrg
346627f7eb2Smrg static void
error_stop(int error)347627f7eb2Smrg error_stop (int error)
348627f7eb2Smrg {
349627f7eb2Smrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
350627f7eb2Smrg /* FIXME: Do some more effort than just MPI_ABORT. */
351627f7eb2Smrg MPI_Abort (MPI_COMM_WORLD, error);
352627f7eb2Smrg
353627f7eb2Smrg /* Should be unreachable, but to make sure also call exit. */
354627f7eb2Smrg exit (error);
355627f7eb2Smrg }
356627f7eb2Smrg
357627f7eb2Smrg
358627f7eb2Smrg /* ERROR STOP function for string arguments. */
359627f7eb2Smrg
360627f7eb2Smrg void
_gfortran_caf_error_stop_str(const char * string,size_t len,bool quiet)361627f7eb2Smrg _gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet)
362627f7eb2Smrg {
363627f7eb2Smrg if (!quiet)
364627f7eb2Smrg {
365627f7eb2Smrg fputs ("ERROR STOP ", stderr);
366627f7eb2Smrg while (len--)
367627f7eb2Smrg fputc (*(string++), stderr);
368627f7eb2Smrg fputs ("\n", stderr);
369627f7eb2Smrg }
370627f7eb2Smrg error_stop (1);
371627f7eb2Smrg }
372627f7eb2Smrg
373627f7eb2Smrg
374627f7eb2Smrg /* ERROR STOP function for numerical arguments. */
375627f7eb2Smrg
376627f7eb2Smrg void
_gfortran_caf_error_stop(int error,bool quiet)377627f7eb2Smrg _gfortran_caf_error_stop (int error, bool quiet)
378627f7eb2Smrg {
379627f7eb2Smrg if (!quiet)
380627f7eb2Smrg fprintf (stderr, "ERROR STOP %d\n", error);
381627f7eb2Smrg error_stop (error);
382627f7eb2Smrg }
383