| /* Copyright (C) 2019-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 <string.h> |
| |
| static void |
| sync_all_init (counter_barrier *b) |
| { |
| master_bind_active_image_barrier (this_image.m, b); |
| } |
| |
| static inline void |
| lock_table (sync_iface *si) |
| { |
| pthread_mutex_lock (&si->cis->table_lock); |
| } |
| |
| static inline void |
| unlock_table (sync_iface *si) |
| { |
| pthread_mutex_unlock (&si->cis->table_lock); |
| } |
| |
| static inline void |
| wait_table_cond (sync_iface *si, pthread_cond_t *cond) |
| { |
| pthread_cond_wait (cond, &si->cis->table_lock); |
| } |
| |
| static int * |
| get_locked_table (sync_iface *si) |
| { |
| lock_table (si); |
| return si->table; |
| } |
| |
| void |
| sync_iface_init (sync_iface *si, alloc_iface *ai, shared_memory *sm) |
| { |
| si->cis = SHMPTR_AS ( |
| sync_iface_shared *, |
| shared_malloc (get_allocator (ai), sizeof (sync_iface_shared)), sm); |
| |
| sync_all_init (&si->cis->sync_all); |
| initialize_shared_mutex (&si->cis->table_lock); |
| si->sm = sm; |
| si->a = get_allocator (ai); |
| |
| si->cis->table = shared_malloc (si->a, sizeof (int) * local->total_num_images |
| * local->total_num_images); |
| si->cis->triggers = shared_malloc (si->a, sizeof (pthread_cond_t) |
| * local->total_num_images); |
| |
| si->table = SHMPTR_AS (int *, si->cis->table, si->sm); |
| si->triggers = SHMPTR_AS (pthread_cond_t *, si->cis->triggers, si->sm); |
| |
| for (int i = 0; i < local->total_num_images; i++) |
| initialize_shared_condition (&si->triggers[i]); |
| } |
| |
| /* TODO: Maybe check whether synchronizing image is still alive. */ |
| void |
| sync_table (sync_iface *si, int *images, int size) |
| { |
| #if defined(DEBUG_NATIVE_COARRAY) && DEBUG_NATIVE_COARRAY |
| dprintf (2, |
| "Image %d waiting for these %ld images: ", this_image.image_num + 1, |
| size); |
| for (int d_i = 0; (size_t)d_i < size; d_i++) |
| dprintf (2, "%d ", images[d_i]); |
| dprintf (2, "\n"); |
| #endif |
| int i; |
| int done; |
| int *table = get_locked_table (si); |
| if (size > 0) |
| { |
| for (i = 0; i < size; i++) |
| { |
| table[images[i] - 1 + local->total_num_images * this_image.image_num]++; |
| pthread_cond_signal (&si->triggers[images[i] - 1]); |
| } |
| for (;;) |
| { |
| done = 1; |
| for (i = 0; i < size; i++) |
| done &= si->table[images[i] - 1 |
| + this_image.image_num * local->total_num_images] |
| == si->table[this_image.image_num |
| + (images[i] - 1) * local->total_num_images]; |
| if (done) |
| break; |
| wait_table_cond (si, &si->triggers[this_image.image_num]); |
| } |
| } |
| else |
| { |
| size = local->total_num_images; |
| for (i = 0; i < size; i++) |
| { |
| table[i + local->total_num_images * this_image.image_num]++; |
| pthread_cond_signal (&si->triggers[i]); |
| } |
| for (;;) |
| { |
| done = 1; |
| for (i = 0; i < size; i++) |
| done &= si->table[i + this_image.image_num * local->total_num_images] |
| == si->table[this_image.image_num |
| + i * local->total_num_images]; |
| if (done) |
| break; |
| wait_table_cond (si, &si->triggers[this_image.image_num]); |
| } |
| } |
| unlock_table (si); |
| } |
| |
| void |
| sync_all (sync_iface *si) |
| { |
| counter_barrier_wait (&si->cis->sync_all); |
| } |