blob: 76ae0e53ccffea3bb869d3563d241831fcfb0f39 [file] [log] [blame]
/* Copyright (C) 2025-2026 Free Software Foundation, Inc.
Contributed by Thomas Koenig, Nicolas Koenig, Andre Vehreschild
This file is part of the GNU Fortran Shmem Coarray Library (caf_shmem).
Caf_shmem 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.
Caf_shmem 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 "supervisor.h"
#include "sync.h"
#include "teams_mgmt.h"
#include "thread_support.h"
#include <string.h>
static inline void
lock_table (sync_t *si)
{
caf_shmem_mutex_lock (&si->cis->sync_images_table_lock);
}
static inline void
unlock_table (sync_t *si)
{
caf_shmem_mutex_unlock (&si->cis->sync_images_table_lock);
}
void
sync_init (sync_t *si, shared_memory sm)
{
*si = (sync_t) {
&this_image.supervisor->sync_shared,
SHMPTR_AS (int *, this_image.supervisor->sync_shared.sync_images_table, sm),
SHMPTR_AS (caf_shmem_condvar *,
this_image.supervisor->sync_shared.sync_images_cond_vars, sm)};
}
void
sync_init_supervisor (sync_t *si, alloc *ai)
{
const int num_images = local->total_num_images;
const size_t table_size_in_bytes = sizeof (int) * num_images * num_images;
si->cis = &this_image.supervisor->sync_shared;
initialize_shared_mutex (&si->cis->event_lock);
initialize_shared_condition (&si->cis->event_cond, num_images);
initialize_shared_mutex (&si->cis->sync_images_table_lock);
si->cis->sync_images_table
= allocator_shared_malloc (alloc_get_allocator (ai), table_size_in_bytes);
si->cis->sync_images_cond_vars
= allocator_shared_malloc (alloc_get_allocator (ai),
sizeof (caf_shmem_condvar) * num_images);
si->table = SHMPTR_AS (int *, si->cis->sync_images_table, ai->mem);
si->triggers
= SHMPTR_AS (caf_shmem_condvar *, si->cis->sync_images_cond_vars, ai->mem);
for (int i = 0; i < num_images; i++)
initialize_shared_condition (&si->triggers[i], num_images);
memset (si->table, 0, table_size_in_bytes);
}
void
sync_table (sync_t *si, int *images, int size)
{
/* The variable `table` is an N x N matrix, where N is the number of all
images. The position (i, j) (where i and j are always the real images
index, i.e. after team de-mapping) tells whether image i has seen the same
number of synchronisation calls to sync_table like j. When table(i,j) ==
table(j,i) then the sync for i with this image is completed (here j is the
real image index of the current image). When this holds for all i in the
current set of images (or all images, if the set is empty), then sync table
command is completed.
*/
volatile int *table = si->table;
int i;
lock_table (si);
if (size > 0)
{
const size_t img_c = caf_current_team->u.image_info->image_map_size;
for (i = 0; i < size; ++i)
{
++table[images[i] + img_c * this_image.image_num];
caf_shmem_cond_signal (&si->triggers[images[i]]);
}
for (;;)
{
for (i = 0; i < size; ++i)
if (this_image.supervisor->images[images[i]].status == IMAGE_OK
&& table[images[i] + this_image.image_num * img_c]
> table[this_image.image_num + images[i] * img_c])
break;
if (i == size)
break;
caf_shmem_cond_wait (&si->triggers[this_image.image_num],
&si->cis->sync_images_table_lock);
}
}
else
{
int *map = caf_current_team->u.image_info->image_map;
size = caf_current_team->u.image_info->image_count.count;
for (i = 0; i < size; ++i)
{
if (this_image.supervisor->images[map[i]].status != IMAGE_OK)
continue;
++table[map[i] + size * this_image.image_num];
caf_shmem_cond_signal (&si->triggers[map[i]]);
}
for (;;)
{
for (i = 0; i < size; ++i)
if (this_image.supervisor->images[map[i]].status == IMAGE_OK
&& table[map[i] + size * this_image.image_num]
> table[this_image.image_num + map[i] * size])
break;
if (i == size)
break;
caf_shmem_cond_wait (&si->triggers[this_image.image_num],
&si->cis->sync_images_table_lock);
}
}
unlock_table (si);
}
void
sync_all (void)
{
counter_barrier_wait (&caf_current_team->u.image_info->image_count);
}
void
sync_team (caf_shmem_team_t team)
{
counter_barrier_wait (&team->u.image_info->image_count);
}
void
lock_event (sync_t *si)
{
caf_shmem_mutex_lock (&si->cis->event_lock);
}
void
unlock_event (sync_t *si)
{
caf_shmem_mutex_unlock (&si->cis->event_lock);
}
void
event_post (sync_t *si)
{
caf_shmem_cond_broadcast (&si->cis->event_cond);
}
void
event_wait (sync_t *si)
{
caf_shmem_cond_wait (&si->cis->event_cond, &si->cis->event_lock);
}