blob: 49d8d374b7f3dc80b39ba79b15945507b90d0760 [file] [log] [blame]
/* Copyright (C) 2020 Free Software Foundation, Inc.
Contributed by Nicolas Koenig
This file is part of the GNU Fortran Native Coarray Library (libnca).
Libnca 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.
Libnca 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 "libgfortran.h"
#include "libcoarraynative.h"
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
/* This implements shared memory based on POSIX mmap. We start with
memory block of the size of the global shared memory data, rounded
up to one pagesize, and enlarge as needed.
We address the memory via a shared_memory_ptr, which is an offset into
the shared memory block. The metadata is situated at offset 0.
In order to be able to resize the memory and to keep pointers
valid, we keep the old mapping around, so the memory is actually
visible several times to the process. Thus, pointers returned by
shared_memory_get_mem_with_alignment remain valid even when
resizing. */
/* Global metadata for shared memory, always kept at offset 0. */
typedef struct
{
size_t used;
} global_shared_memory_meta;
/* Type realization for opaque type shared_memory. */
typedef struct shared_memory_act
{
union {
void *base;
global_shared_memory_meta *meta;
} glbl;
size_t size; // const
} shared_memory_act;
/* Convenience wrapper for mmap. */
static inline void *
map_memory (size_t size)
{
void *ret
= mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (ret == MAP_FAILED)
{
perror ("mmap failed");
exit (1);
}
return ret;
}
/* Get a pointer into the shared memory block with alignemnt
(works similar to sbrk). */
shared_mem_ptr
shared_memory_get_mem_with_alignment (shared_memory_act **pmem, size_t size,
size_t align)
{
shared_memory_act* mem = *pmem;
size_t aligned_curr_size = alignto(mem->glbl.meta->used, align);
void *p = mem->glbl.base+aligned_curr_size;
mem->glbl.meta->used = aligned_curr_size + size;
return (shared_mem_ptr) {.p = p};
}
/* If another image changed the size, update the size accordingly. */
void
shared_memory_prepare (shared_memory_act **pmem)
{
asm volatile("":::"memory");
}
/* Initialize the memory with one page, the shared metadata of the
shared memory is stored at the beginning. */
void
shared_memory_init (shared_memory_act **pmem, size_t size)
{
shared_memory_act *mem;
mem = malloc (sizeof(shared_memory_act));
mem->glbl.base = map_memory(size);
mem->size = size;
mem->glbl.meta->used = sizeof(global_shared_memory_meta);
*pmem = mem;
}