blob: 65b347e7a8c61f17f793eca61df9e60d9ac3abbf [file] [log] [blame]
#include "libgfortran.h"
#include "util.h"
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
/* Shared Memory objects live in their own namspace (usually found under
* /dev/shm/), so the "/" is needed. It is for some reason impossible to
* create a shared memory object without name.
*
* Apple, for some reason, only allows 31 characters in memfd names, so we need
* to make the name a bit shorter in that case. */
#ifndef __APPLE__
#define MEMOBJ_NAME "/gfortran_coarray_memfd"
#define CUT_INT(x) (x)
#else
#define MEMOBJ_NAME "/gfccas_"
#define CUT_INT(x) (x % 100000)
#endif
size_t
alignto (size_t size, size_t align)
{
return align * ((size + align - 1) / align);
}
size_t pagesize;
size_t
round_to_pagesize (size_t s)
{
return alignto (s, pagesize);
}
size_t
next_power_of_two (size_t size)
{
assert (size);
return 1 << (PTR_BITS - __builtin_clzl (size - 1));
}
#define ERRCHECK(a) do { \
int rc = a; \
if (rc) { \
errno = rc; \
perror (#a " failed"); \
exit (1); \
} \
} while(0)
void
initialize_shared_mutex (pthread_mutex_t *mutex)
{
pthread_mutexattr_t mattr;
ERRCHECK (pthread_mutexattr_init (&mattr));
ERRCHECK (pthread_mutexattr_setpshared (&mattr, PTHREAD_PROCESS_SHARED));
ERRCHECK (pthread_mutex_init (mutex, &mattr));
ERRCHECK (pthread_mutexattr_destroy (&mattr));
}
void
initialize_shared_condition (pthread_cond_t *cond)
{
pthread_condattr_t cattr;
ERRCHECK (pthread_condattr_init (&cattr));
ERRCHECK (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED));
ERRCHECK (pthread_cond_init (cond, &cattr));
ERRCHECK (pthread_condattr_destroy (&cattr));
}
int
get_shmem_fd (void)
{
char buffer[1 << 10];
int fd, id;
id = random ();
do
{
snprintf (buffer, sizeof (buffer), MEMOBJ_NAME "_%u_%d",
(unsigned int)getpid (), CUT_INT(id++));
fd = shm_open (buffer, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1 && errno != EEXIST)
{
perror("Failed to create the memfd");
exit(1);
}
}
while (fd == -1);
shm_unlink (buffer);
return fd;
}
bool
pack_array_prepare (pack_info *restrict pi,
const gfc_array_char *restrict source)
{
index_type dim;
bool packed;
index_type span;
index_type type_size;
index_type ssize;
dim = GFC_DESCRIPTOR_RANK (source);
type_size = GFC_DESCRIPTOR_SIZE (source);
ssize = type_size;
pi->num_elem = 1;
packed = true;
span = source->span != 0 ? source->span : type_size;
for (index_type n = 0; n < dim; n++)
{
pi->stride[n] = GFC_DESCRIPTOR_STRIDE (source, n) * span;
pi->extent[n] = GFC_DESCRIPTOR_EXTENT (source, n);
if (pi->extent[n] <= 0)
{
/* Do nothing. */
packed = 1;
pi->num_elem = 0;
break;
}
if (ssize != pi->stride[n])
packed = 0;
pi->num_elem *= pi->extent[n];
ssize *= pi->extent[n];
}
return packed;
}
void
pack_array_finish (pack_info *const restrict pi,
const gfc_array_char *const restrict source,
char *restrict dest)
{
index_type dim;
const char *restrict src;
index_type size;
index_type stride0;
index_type count[GFC_MAX_DIMENSIONS];
dim = GFC_DESCRIPTOR_RANK (source);
src = source->base_addr;
stride0 = pi->stride[0];
size = GFC_DESCRIPTOR_SIZE (source);
memset (count, '\0', sizeof (count) * dim);
while (src)
{
/* Copy the data. */
memcpy (dest, src, size);
/* Advance to the next element. */
dest += size;
src += stride0;
count[0]++;
/* Advance to the next source element. */
index_type n = 0;
while (count[n] == pi->extent[n])
{
/* When we get to the end of a dimension, reset it and increment
the next dimension. */
count[n] = 0;
/* We could precalculate these products, but this is a less
frequently used path so probably not worth it. */
src -= pi->stride[n] * pi->extent[n];
n++;
if (n == dim)
{
src = NULL;
break;
}
else
{
count[n]++;
src += pi->stride[n];
}
}
}
}
void
unpack_array_finish (pack_info *const restrict pi,
const gfc_array_char *restrict d,
const char *restrict src)
{
index_type stride0;
char *restrict dest;
index_type size;
index_type count[GFC_MAX_DIMENSIONS];
index_type dim;
size = GFC_DESCRIPTOR_SIZE (d);
stride0 = pi->stride[0];
dest = d->base_addr;
dim = GFC_DESCRIPTOR_RANK (d);
memset (count, '\0', sizeof (count) * dim);
while (dest)
{
memcpy (dest, src, size);
src += size;
dest += stride0;
count[0]++;
index_type n = 0;
while (count[n] == pi->extent[n])
{
count[n] = 0;
dest -= pi->stride[n] * pi->extent[n];
n++;
if (n == dim)
{
dest = NULL;
break;
}
else
{
count[n]++;
dest += pi->stride[n];
}
}
}
}