gcc/libgfortran/caf/single.c
Andre Vehreschild 08bdc2ac98 Fortran: Fix build on solaris [PR107635]
libgfortran/ChangeLog:

	PR fortran/107635
	* caf/single.c: Replace alloca with __builtin_alloca.
2025-02-21 09:13:50 +01:00

925 lines
25 KiB
C

/* Single-image implementation of GNU Fortran Coarray Library
Copyright (C) 2011-2025 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> /* For fputs and fprintf. */
#include <stdlib.h> /* For exit and malloc. */
#include <string.h> /* For memcpy and memset. */
#include <stdarg.h> /* For variadic arguments. */
#include <stdint.h>
#include <assert.h>
/* Define GFC_CAF_CHECK to enable run-time checking. */
/* #define GFC_CAF_CHECK 1 */
struct caf_single_token
{
/* The pointer to the memory registered. For arrays this is the data member
in the descriptor. For components it's the pure data pointer. */
void *memptr;
/* The descriptor when this token is associated to an allocatable array. */
gfc_descriptor_t *desc;
/* Set when the caf lib has allocated the memory in memptr and is responsible
for freeing it on deregister. */
bool owning_memory;
};
typedef struct caf_single_token *caf_single_token_t;
#define TOKEN(X) ((caf_single_token_t) (X))
#define MEMTOK(X) ((caf_single_token_t) (X))->memptr
/* Single-image implementation of the CAF library.
Note: For performance reasons -fcoarry=single should be used
rather than this library. */
/* Global variables. */
caf_static_t *caf_static_list = NULL;
typedef void (*getter_t) (void *, const int *, void **, int32_t *, void *,
caf_token_t, const size_t, size_t *, const size_t *);
typedef void (*is_present_t) (void *, const int *, int32_t *, void *,
caf_single_token_t, const size_t);
typedef void (*receiver_t) (void *, const int *, void *, const void *,
caf_token_t, const size_t, const size_t *,
const size_t *);
struct accessor_hash_t
{
int hash;
int pad;
union
{
getter_t getter;
is_present_t is_present;
receiver_t receiver;
} u;
};
static struct accessor_hash_t *accessor_hash_table = NULL;
static int aht_cap = 0;
static int aht_size = 0;
static enum {
AHT_UNINITIALIZED,
AHT_OPEN,
AHT_PREPARED
} accessor_hash_table_state
= AHT_UNINITIALIZED;
/* Keep in sync with mpi.c. */
static void
caf_runtime_error (const char *message, ...)
{
va_list ap;
fprintf (stderr, "Fortran runtime error: ");
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. */
exit (EXIT_FAILURE);
}
/* Error handling is similar everytime. */
static void
caf_internal_error (const char *msg, int *stat, char *errmsg,
size_t errmsg_len, ...)
{
va_list args;
va_start (args, errmsg_len);
if (stat)
{
*stat = 1;
if (errmsg_len > 0)
{
int len = snprintf (errmsg, errmsg_len, msg, args);
if (len >= 0 && errmsg_len > (size_t) len)
memset (&errmsg[len], ' ', errmsg_len - len);
}
va_end (args);
return;
}
else
caf_runtime_error (msg, args);
va_end (args);
}
void
_gfortran_caf_init (int *argc __attribute__ ((unused)),
char ***argv __attribute__ ((unused)))
{
}
void
_gfortran_caf_finalize (void)
{
free (accessor_hash_table);
while (caf_static_list != NULL)
{
caf_static_t *tmp = caf_static_list->prev;
free (((caf_single_token_t) caf_static_list->token)->memptr);
free (caf_static_list->token);
free (caf_static_list);
caf_static_list = tmp;
}
}
int
_gfortran_caf_this_image (int distance __attribute__ ((unused)))
{
return 1;
}
int
_gfortran_caf_num_images (int distance __attribute__ ((unused)),
int failed __attribute__ ((unused)))
{
return 1;
}
void
_gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
gfc_descriptor_t *data, int *stat, char *errmsg,
size_t errmsg_len)
{
const char alloc_fail_msg[] = "Failed to allocate coarray";
void *local;
caf_single_token_t single_token;
if (type == CAF_REGTYPE_LOCK_STATIC || type == CAF_REGTYPE_LOCK_ALLOC
|| type == CAF_REGTYPE_CRITICAL)
local = calloc (size, sizeof (bool));
else if (type == CAF_REGTYPE_EVENT_STATIC || type == CAF_REGTYPE_EVENT_ALLOC)
/* In the event_(wait|post) function the counter for events is a uint32,
so better allocate enough memory here. */
local = calloc (size, sizeof (uint32_t));
else if (type == CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY)
local = NULL;
else
local = malloc (size);
if (type != CAF_REGTYPE_COARRAY_ALLOC_ALLOCATE_ONLY)
*token = malloc (sizeof (struct caf_single_token));
if (unlikely (*token == NULL
|| (local == NULL
&& type != CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY)))
{
/* Freeing the memory conditionally seems pointless, but
caf_internal_error () may return, when a stat is given and then the
memory may be lost. */
free (local);
free (*token);
caf_internal_error (alloc_fail_msg, stat, errmsg, errmsg_len);
return;
}
single_token = TOKEN (*token);
single_token->memptr = local;
single_token->owning_memory = type != CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY;
single_token->desc = GFC_DESCRIPTOR_RANK (data) > 0 ? data : NULL;
if (stat)
*stat = 0;
if (type == CAF_REGTYPE_COARRAY_STATIC || type == CAF_REGTYPE_LOCK_STATIC
|| type == CAF_REGTYPE_CRITICAL || type == CAF_REGTYPE_EVENT_STATIC
|| type == CAF_REGTYPE_EVENT_ALLOC)
{
caf_static_t *tmp = malloc (sizeof (caf_static_t));
tmp->prev = caf_static_list;
tmp->token = *token;
caf_static_list = tmp;
}
GFC_DESCRIPTOR_DATA (data) = local;
}
void
_gfortran_caf_deregister (caf_token_t *token, caf_deregister_t type, int *stat,
char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
caf_single_token_t single_token = TOKEN (*token);
if (single_token->owning_memory && single_token->memptr)
free (single_token->memptr);
if (type != CAF_DEREGTYPE_COARRAY_DEALLOCATE_ONLY)
{
free (TOKEN (*token));
*token = NULL;
}
else
{
single_token->memptr = NULL;
single_token->owning_memory = false;
}
if (stat)
*stat = 0;
}
void
_gfortran_caf_sync_all (int *stat,
char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
__asm__ __volatile__ ("":::"memory");
if (stat)
*stat = 0;
}
void
_gfortran_caf_sync_memory (int *stat,
char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
__asm__ __volatile__ ("":::"memory");
if (stat)
*stat = 0;
}
void
_gfortran_caf_sync_images (int count __attribute__ ((unused)),
int images[] __attribute__ ((unused)),
int *stat,
char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
#ifdef GFC_CAF_CHECK
int i;
for (i = 0; i < count; i++)
if (images[i] != 1)
{
fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
"IMAGES", images[i]);
exit (EXIT_FAILURE);
}
#endif
__asm__ __volatile__ ("":::"memory");
if (stat)
*stat = 0;
}
extern void _gfortran_report_exception (void);
void
_gfortran_caf_stop_numeric(int stop_code, bool quiet)
{
if (!quiet)
{
_gfortran_report_exception ();
fprintf (stderr, "STOP %d\n", stop_code);
}
exit (stop_code);
}
void
_gfortran_caf_stop_str(const char *string, size_t len, bool quiet)
{
if (!quiet)
{
_gfortran_report_exception ();
fputs ("STOP ", stderr);
while (len--)
fputc (*(string++), stderr);
fputs ("\n", stderr);
}
exit (0);
}
void
_gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet)
{
if (!quiet)
{
_gfortran_report_exception ();
fputs ("ERROR STOP ", stderr);
while (len--)
fputc (*(string++), stderr);
fputs ("\n", stderr);
}
exit (1);
}
/* Reported that the program terminated because of a fail image issued.
Because this is a single image library, nothing else than aborting the whole
program can be done. */
void _gfortran_caf_fail_image (void)
{
fputs ("IMAGE FAILED!\n", stderr);
exit (0);
}
/* Get the status of image IMAGE. Because being the single image library all
other images are reported to be stopped. */
int _gfortran_caf_image_status (int image,
caf_team_t * team __attribute__ ((unused)))
{
if (image == 1)
return 0;
else
return CAF_STAT_STOPPED_IMAGE;
}
/* Single image library. There cannot be any failed images with only one
image. */
void
_gfortran_caf_failed_images (gfc_descriptor_t *array,
caf_team_t * team __attribute__ ((unused)),
int * kind)
{
int local_kind = kind != NULL ? *kind : 4;
array->base_addr = NULL;
array->dtype.type = BT_INTEGER;
array->dtype.elem_len = local_kind;
/* Setting lower_bound higher then upper_bound is what the compiler does to
indicate an empty array. */
array->dim[0].lower_bound = 0;
array->dim[0]._ubound = -1;
array->dim[0]._stride = 1;
array->offset = 0;
}
/* With only one image available no other images can be stopped. Therefore
return an empty array. */
void
_gfortran_caf_stopped_images (gfc_descriptor_t *array,
caf_team_t * team __attribute__ ((unused)),
int * kind)
{
int local_kind = kind != NULL ? *kind : 4;
array->base_addr = NULL;
array->dtype.type = BT_INTEGER;
array->dtype.elem_len = local_kind;
/* Setting lower_bound higher then upper_bound is what the compiler does to
indicate an empty array. */
array->dim[0].lower_bound = 0;
array->dim[0]._ubound = -1;
array->dim[0]._stride = 1;
array->offset = 0;
}
void
_gfortran_caf_error_stop (int error, bool quiet)
{
if (!quiet)
{
_gfortran_report_exception ();
fprintf (stderr, "ERROR STOP %d\n", error);
}
exit (error);
}
void
_gfortran_caf_co_broadcast (gfc_descriptor_t *a __attribute__ ((unused)),
int source_image __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
if (stat)
*stat = 0;
}
void
_gfortran_caf_co_sum (gfc_descriptor_t *a __attribute__ ((unused)),
int result_image __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
if (stat)
*stat = 0;
}
void
_gfortran_caf_co_min (gfc_descriptor_t *a __attribute__ ((unused)),
int result_image __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
int a_len __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
if (stat)
*stat = 0;
}
void
_gfortran_caf_co_max (gfc_descriptor_t *a __attribute__ ((unused)),
int result_image __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
int a_len __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
if (stat)
*stat = 0;
}
void
_gfortran_caf_co_reduce (gfc_descriptor_t *a __attribute__ ((unused)),
void * (*opr) (void *, void *)
__attribute__ ((unused)),
int opr_flags __attribute__ ((unused)),
int result_image __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
int a_len __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
if (stat)
*stat = 0;
}
void
_gfortran_caf_register_accessor (const int hash, getter_t accessor)
{
if (accessor_hash_table_state == AHT_UNINITIALIZED)
{
aht_cap = 16;
accessor_hash_table = calloc (aht_cap, sizeof (struct accessor_hash_t));
accessor_hash_table_state = AHT_OPEN;
}
if (aht_size == aht_cap)
{
aht_cap += 16;
accessor_hash_table = realloc (accessor_hash_table,
aht_cap * sizeof (struct accessor_hash_t));
}
if (accessor_hash_table_state == AHT_PREPARED)
{
accessor_hash_table_state = AHT_OPEN;
}
accessor_hash_table[aht_size].hash = hash;
accessor_hash_table[aht_size].u.getter = accessor;
++aht_size;
}
static int
hash_compare (const struct accessor_hash_t *lhs,
const struct accessor_hash_t *rhs)
{
return lhs->hash < rhs->hash ? -1 : (lhs->hash > rhs->hash ? 1 : 0);
}
void
_gfortran_caf_register_accessors_finish (void)
{
if (accessor_hash_table_state == AHT_PREPARED
|| accessor_hash_table_state == AHT_UNINITIALIZED)
return;
qsort (accessor_hash_table, aht_size, sizeof (struct accessor_hash_t),
(int (*) (const void *, const void *)) hash_compare);
accessor_hash_table_state = AHT_PREPARED;
}
int
_gfortran_caf_get_remote_function_index (const int hash)
{
if (accessor_hash_table_state != AHT_PREPARED)
{
caf_runtime_error ("the accessor hash table is not prepared.");
}
struct accessor_hash_t cand;
cand.hash = hash;
struct accessor_hash_t *f
= bsearch (&cand, accessor_hash_table, aht_size,
sizeof (struct accessor_hash_t),
(int (*) (const void *, const void *)) hash_compare);
int index = f ? f - accessor_hash_table : -1;
return index;
}
void
_gfortran_caf_get_from_remote (
caf_token_t token, const gfc_descriptor_t *opt_src_desc,
const size_t *opt_src_charlen, const int image_index,
const size_t dst_size __attribute__ ((unused)), void **dst_data,
size_t *opt_dst_charlen, gfc_descriptor_t *opt_dst_desc,
const bool may_realloc_dst, const int getter_index, void *add_data,
const size_t add_data_size __attribute__ ((unused)), int *stat,
caf_team_t *team __attribute__ ((unused)),
int *team_number __attribute__ ((unused)))
{
caf_single_token_t single_token = TOKEN (token);
void *src_ptr = opt_src_desc ? (void *) opt_src_desc : single_token->memptr;
int32_t free_buffer;
void *dst_ptr = opt_dst_desc ? (void *)opt_dst_desc : dst_data;
void *old_dst_data_ptr = NULL;
struct caf_single_token cb_token;
cb_token.memptr = add_data;
cb_token.desc = NULL;
cb_token.owning_memory = false;
if (stat)
*stat = 0;
if (opt_dst_desc && !may_realloc_dst)
{
old_dst_data_ptr = opt_dst_desc->base_addr;
opt_dst_desc->base_addr = NULL;
}
accessor_hash_table[getter_index].u.getter (add_data, &image_index, dst_ptr,
&free_buffer, src_ptr, &cb_token,
0, opt_dst_charlen,
opt_src_charlen);
if (opt_dst_desc && old_dst_data_ptr && !may_realloc_dst
&& opt_dst_desc->base_addr != old_dst_data_ptr)
{
size_t dsize = opt_dst_desc->span;
for (int i = 0; i < GFC_DESCRIPTOR_RANK (opt_dst_desc); ++i)
dsize *= GFC_DESCRIPTOR_EXTENT (opt_dst_desc, i);
memcpy (old_dst_data_ptr, opt_dst_desc->base_addr, dsize);
free (opt_dst_desc->base_addr);
opt_dst_desc->base_addr = old_dst_data_ptr;
}
}
int32_t
_gfortran_caf_is_present_on_remote (caf_token_t token, const int image_index,
const int present_index, void *add_data,
const size_t add_data_size
__attribute__ ((unused)))
{
/* Unregistered tokens are always not present. */
if (!token)
return 0;
caf_single_token_t single_token = TOKEN (token);
int32_t result;
struct caf_single_token cb_token = {add_data, NULL, false};
accessor_hash_table[present_index].u.is_present (add_data, &image_index,
&result,
single_token->memptr,
&cb_token, 0);
return result;
}
void
_gfortran_caf_send_to_remote (
caf_token_t token, gfc_descriptor_t *opt_dst_desc,
const size_t *opt_dst_charlen, const int image_index,
const size_t src_size __attribute__ ((unused)), const void *src_data,
const size_t *opt_src_charlen, const gfc_descriptor_t *opt_src_desc,
const int accessor_index, void *add_data,
const size_t add_data_size __attribute__ ((unused)), int *stat,
caf_team_t *team __attribute__ ((unused)),
int *team_number __attribute__ ((unused)))
{
caf_single_token_t single_token = TOKEN (token);
void *dst_ptr = opt_dst_desc ? (void *) opt_dst_desc : single_token->memptr;
const void *src_ptr = opt_src_desc ? (void *) opt_src_desc : src_data;
struct caf_single_token cb_token;
cb_token.memptr = add_data;
cb_token.desc = NULL;
cb_token.owning_memory = false;
if (stat)
*stat = 0;
accessor_hash_table[accessor_index].u.receiver (add_data, &image_index,
dst_ptr, src_ptr, &cb_token,
0, opt_dst_charlen,
opt_src_charlen);
}
void
_gfortran_caf_transfer_between_remotes (
caf_token_t dst_token, gfc_descriptor_t *opt_dst_desc,
size_t *opt_dst_charlen, const int dst_image_index,
const int dst_access_index, void *dst_add_data,
const size_t dst_add_data_size __attribute__ ((unused)),
caf_token_t src_token, const gfc_descriptor_t *opt_src_desc,
const size_t *opt_src_charlen, const int src_image_index,
const int src_access_index, void *src_add_data,
const size_t src_add_data_size __attribute__ ((unused)),
const size_t src_size, const bool scalar_transfer, int *dst_stat,
int *src_stat, caf_team_t *dst_team __attribute__ ((unused)),
int *dst_team_number __attribute__ ((unused)),
caf_team_t *src_team __attribute__ ((unused)),
int *src_team_number __attribute__ ((unused)))
{
caf_single_token_t src_single_token = TOKEN (src_token),
dst_single_token = TOKEN (dst_token);
void *src_ptr
= opt_src_desc ? (void *) opt_src_desc : src_single_token->memptr;
int32_t free_buffer;
void *dst_ptr
= opt_dst_desc ? (void *) opt_dst_desc : dst_single_token->memptr;
void *transfer_ptr, *buffer;
GFC_FULL_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) *transfer_desc = NULL;
struct caf_single_token cb_token;
cb_token.memptr = src_add_data;
cb_token.desc = NULL;
cb_token.owning_memory = false;
if (src_stat)
*src_stat = 0;
if (!scalar_transfer)
{
const size_t desc_size = sizeof (*transfer_desc);
transfer_desc = __builtin_alloca (desc_size);
memset (transfer_desc, 0, desc_size);
transfer_ptr = transfer_desc;
}
else if (opt_dst_charlen)
transfer_ptr = __builtin_alloca (*opt_dst_charlen * src_size);
else
{
buffer = NULL;
transfer_ptr = &buffer;
}
accessor_hash_table[src_access_index].u.getter (
src_add_data, &src_image_index, transfer_ptr, &free_buffer, src_ptr,
&cb_token, 0, opt_dst_charlen, opt_src_charlen);
if (dst_stat)
*dst_stat = 0;
if (scalar_transfer)
transfer_ptr = *(void **) transfer_ptr;
cb_token.memptr = dst_add_data;
accessor_hash_table[dst_access_index].u.receiver (dst_add_data,
&dst_image_index, dst_ptr,
transfer_ptr, &cb_token, 0,
opt_dst_charlen,
opt_src_charlen);
if (free_buffer)
free (transfer_desc ? transfer_desc->base_addr : transfer_ptr);
}
void
_gfortran_caf_atomic_define (caf_token_t token, size_t offset,
int image_index __attribute__ ((unused)),
void *value, int *stat,
int type __attribute__ ((unused)), int kind)
{
assert(kind == 4);
uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);
__atomic_store (atom, (uint32_t *) value, __ATOMIC_RELAXED);
if (stat)
*stat = 0;
}
void
_gfortran_caf_atomic_ref (caf_token_t token, size_t offset,
int image_index __attribute__ ((unused)),
void *value, int *stat,
int type __attribute__ ((unused)), int kind)
{
assert(kind == 4);
uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);
__atomic_load (atom, (uint32_t *) value, __ATOMIC_RELAXED);
if (stat)
*stat = 0;
}
void
_gfortran_caf_atomic_cas (caf_token_t token, size_t offset,
int image_index __attribute__ ((unused)),
void *old, void *compare, void *new_val, int *stat,
int type __attribute__ ((unused)), int kind)
{
assert(kind == 4);
uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);
*(uint32_t *) old = *(uint32_t *) compare;
(void) __atomic_compare_exchange_n (atom, (uint32_t *) old,
*(uint32_t *) new_val, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
if (stat)
*stat = 0;
}
void
_gfortran_caf_atomic_op (int op, caf_token_t token, size_t offset,
int image_index __attribute__ ((unused)),
void *value, void *old, int *stat,
int type __attribute__ ((unused)), int kind)
{
assert(kind == 4);
uint32_t res;
uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);
switch (op)
{
case GFC_CAF_ATOMIC_ADD:
res = __atomic_fetch_add (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
break;
case GFC_CAF_ATOMIC_AND:
res = __atomic_fetch_and (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
break;
case GFC_CAF_ATOMIC_OR:
res = __atomic_fetch_or (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
break;
case GFC_CAF_ATOMIC_XOR:
res = __atomic_fetch_xor (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
break;
default:
__builtin_unreachable();
}
if (old)
*(uint32_t *) old = res;
if (stat)
*stat = 0;
}
void
_gfortran_caf_event_post (caf_token_t token, size_t index,
int image_index __attribute__ ((unused)),
int *stat, char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
uint32_t value = 1;
uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
* sizeof (uint32_t));
__atomic_fetch_add (event, (uint32_t) value, __ATOMIC_RELAXED);
if(stat)
*stat = 0;
}
void
_gfortran_caf_event_wait (caf_token_t token, size_t index,
int until_count, int *stat,
char *errmsg __attribute__ ((unused)),
size_t errmsg_len __attribute__ ((unused)))
{
uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
* sizeof (uint32_t));
uint32_t value = (uint32_t)-until_count;
__atomic_fetch_add (event, (uint32_t) value, __ATOMIC_RELAXED);
if(stat)
*stat = 0;
}
void
_gfortran_caf_event_query (caf_token_t token, size_t index,
int image_index __attribute__ ((unused)),
int *count, int *stat)
{
uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
* sizeof (uint32_t));
__atomic_load (event, (uint32_t *) count, __ATOMIC_RELAXED);
if(stat)
*stat = 0;
}
void
_gfortran_caf_lock (caf_token_t token, size_t index,
int image_index __attribute__ ((unused)),
int *acquired_lock, int *stat, char *errmsg,
size_t errmsg_len)
{
const char *msg = "Already locked";
bool *lock = &((bool *) MEMTOK (token))[index];
if (!*lock)
{
*lock = true;
if (acquired_lock)
*acquired_lock = (int) true;
if (stat)
*stat = 0;
return;
}
if (acquired_lock)
{
*acquired_lock = (int) false;
if (stat)
*stat = 0;
return;
}
if (stat)
{
*stat = 1;
if (errmsg_len > 0)
{
size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
: sizeof (msg);
memcpy (errmsg, msg, len);
if (errmsg_len > len)
memset (&errmsg[len], ' ', errmsg_len-len);
}
return;
}
_gfortran_caf_error_stop_str (msg, strlen (msg), false);
}
void
_gfortran_caf_unlock (caf_token_t token, size_t index,
int image_index __attribute__ ((unused)),
int *stat, char *errmsg, size_t errmsg_len)
{
const char *msg = "Variable is not locked";
bool *lock = &((bool *) MEMTOK (token))[index];
if (*lock)
{
*lock = false;
if (stat)
*stat = 0;
return;
}
if (stat)
{
*stat = 1;
if (errmsg_len > 0)
{
size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
: sizeof (msg);
memcpy (errmsg, msg, len);
if (errmsg_len > len)
memset (&errmsg[len], ' ', errmsg_len-len);
}
return;
}
_gfortran_caf_error_stop_str (msg, strlen (msg), false);
}
/* Reference the libraries implementation. */
extern void _gfortran_random_init (int32_t, int32_t, int32_t);
void _gfortran_caf_random_init (bool repeatable, bool image_distinct)
{
/* In a single image implementation always forward to the gfortran
routine. */
_gfortran_random_init (repeatable, image_distinct, 1);
}