Dear all, as requested,
See attached patch 8 of 13
Best Regards,
Jerry
commit 290f3b399ec3cb5991e28edf30cc55ba3a39c176
Author: Andre Vehreschild <[email protected]>
Date: Wed Aug 6 15:36:54 2025 +0200
Fortran: Fix caf_shmem syncing on Windows.
Cygwin's libc's pthread implementation does not support setting
pshared on mutexes and condition variables. Therefore Windows
synchronisation primitives needed to be used directly.
On MSYS2/UCRT64 fork and mmap are not available and Windows core
functionality needs to be used.
libgfortran/ChangeLog:
* caf/shmem.c (_gfortran_caf_init): Cleanup thread helper after
use.
(_gfortran_caf_finalize): Same.
(_gfortran_caf_register): Handle lock_t correctly on Windows.
(GEN_OP): Prevent warnings on non-initialized.
(_gfortran_caf_lock): Handle lock_t correctly on Windows.
(_gfortran_caf_unlock): Same.
(_gfortran_caf_random_init): Fix formatting.
(_gfortran_caf_form_team): Add more images to counter_barrier.
* caf/shmem/alloc.c: Use routines from thread_support.
* caf/shmem/allocator.c (allocator_lock): Same.
(allocator_unlock): Same.
* caf/shmem/allocator.h: Same.
* caf/shmem/collective_subroutine.c (get_collsub_buf): Same.
* caf/shmem/collective_subroutine.h: Same.
* caf/shmem/counter_barrier.c (lock_counter_barrier): Same.
(unlock_counter_barrier): Same.
(counter_barrier_init): Same.
(counter_barrier_wait): Same.
(change_internal_barrier_count): Same.
(counter_barrier_add): Same.
(counter_barrier_init_add): Only increase value w/o signaling.
(counter_barrier_get_count): Use routines from thread_support.
* caf/shmem/counter_barrier.h: Same.
(counter_barrier_init_add): New routine.
* caf/shmem/shared_memory.c: Use windows routines where
applicable.
(shared_memory_set_env): Same.
(shared_memory_get_master): Same.
(shared_memory_init): Same.
(shared_memory_cleanup): Same.
* caf/shmem/shared_memory.h: Use types from thread_support.
* caf/shmem/supervisor.c: Use windows routines where applicable.
(get_memory_size_from_envvar): Same.
(ensure_shmem_initialization): Same.
(supervisor_main_loop): Use windows process start on windows
without fork().
* caf/shmem/supervisor.h: Use types from thread_support.
* caf/shmem/sync.c (lock_table): Use routines from thread_support.
(unlock_table): Same.
(sync_init): Same.
(sync_init_supervisor): Same.
(sync_table): Same.
(lock_event): Same.
(unlock_event): Same.
(event_post): Same.
(event_wait): Same.
* caf/shmem/sync.h: Use types from thread_support.
* caf/shmem/teams_mgmt.c (update_teams_images): Use routines from
thread_support.
* caf/shmem/thread_support.c: Add synchronisation primitives for
windows.
(smax): Windows only: Max for size_t.
(get_handle): Windows only: Get the windows handle for a given
id or create a new one, if it does not exist.
(get_mutex): Windows only: Shortcut for getting a windows mutex
handle.
(get_condvar): Windows only: Same, but for condition variable.
(thread_support_init_supervisor): Windows only: Clear tracker of
allocated handle ids.
(caf_shmem_mutex_lock): Windows only: Implememtation of lock,
(caf_shmem_mutex_trylock): Windows only: trylock, and
(caf_shmem_mutex_unlock): Windows only: unlock for Windows.
(bm_is_set): Windows only: Check a bit is set in a mask.
(bm_clear_bit): Windows only: Clear a bit in a mask.
(bm_set_mask): Windows only: Set all bits in a mask.
(bm_is_none): Windows only: Check if all bits are cleared.
(caf_shmem_cond_wait): Windows only: Condition variable
implemenation fro wait,
(caf_shmem_cond_broadcast): Windows only: broadcast, and
(caf_shmem_cond_signal): Windows only: signal on Windows.
(caf_shmem_cond_update_count): Windows only: Need to know the
images participating in a condition variable.
(thread_support_cleanup): Windows only: Clean up the handles on
exit.
* caf/shmem/thread_support.h: Conditionally compile the types
as required for Windows and other OSes.
diff --git a/libgfortran/caf/shmem.c b/libgfortran/caf/shmem.c
index b8d92d657f5..266feab3e45 100644
--- a/libgfortran/caf/shmem.c
+++ b/libgfortran/caf/shmem.c
@@ -94,6 +94,8 @@ _gfortran_caf_init (int *argc, char ***argv)
if (supervisor_main_loop (argc, argv, &exit_code))
return;
+
+ thread_support_cleanup ();
shared_memory_cleanup (&local->sm);
/* Free pseudo tokens and memory to allow main process to survive caf_init.
@@ -107,6 +109,7 @@ _gfortran_caf_init (int *argc, char ***argv)
caf_static_list = tmp;
}
free (local);
+
exit (exit_code);
}
@@ -150,6 +153,8 @@ _gfortran_caf_finalize (void)
caf_teams_formed = NULL;
free (local);
+
+ thread_support_cleanup ();
}
int
@@ -267,19 +272,25 @@ _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
{
lock_t *addr;
bool created;
+ size_t alloc_size;
allocator_lock (&local->ai.alloc);
- /* Allocate enough space for the metadata infront of the lock
- array. */
- addr
- = alloc_get_memory_by_id_created (&local->ai, size * sizeof (lock_t),
- next_memid, &created);
+#if defined(WIN32) || defined(__CYGWIN__)
+ /* On Windows mutexes are not an object stored in the shmem but
+ identified by an id. */
+ alloc_size = size * caf_current_team->u.image_info->image_count.count;
+#else
+ alloc_size = size;
+#endif
+ addr = alloc_get_memory_by_id_created (&local->ai,
+ alloc_size * sizeof (lock_t),
+ next_memid, &created);
if (created)
{
/* Initialize the mutex only, when the memory was allocated for the
first time. */
- for (size_t c = 0; c < size; ++c)
+ for (size_t c = 0; c < alloc_size; ++c)
initialize_shared_errorcheck_mutex (&addr[c]);
}
size *= sizeof (lock_t);
@@ -852,6 +863,7 @@ typedef void *opr_t;
default: \
caf_runtime_error ("" #name \
" not available for type/kind combination"); \
+ opr = NULL; /* Prevent false warnings. */ \
} \
break; \
}
@@ -873,10 +885,12 @@ typedef void *opr_t;
default: \
caf_runtime_error ("" #name \
" not available for type/kind combination"); \
+ opr = NULL; /* Prevent false warning. */ \
} \
break; \
default: \
caf_runtime_error ("" #name " not available for type/kind combination"); \
+ opr = NULL; /* Prevent false warning. */ \
}
void
@@ -1473,17 +1487,23 @@ _gfortran_caf_event_query (caf_token_t token, size_t index, int image_index,
}
void
-_gfortran_caf_lock (caf_token_t token, size_t index,
- int image_index __attribute__ ((unused)),
+_gfortran_caf_lock (caf_token_t token, size_t index, int image_index,
int *acquired_lock, int *stat, char *errmsg,
size_t errmsg_len)
{
const char *msg = "Already locked";
- lock_t *lock = &((lock_t *) MEMTOK (token))[index];
+#if defined(WIN32) || defined(__CYGWIN__)
+ const size_t lock_index
+ = image_index * caf_current_team->u.image_info->image_count.count + index;
+#else
+ const size_t lock_index = index;
+ (void) image_index; // Prevent unused warnings.
+#endif
+ lock_t *lock = &((lock_t *) MEMTOK (token))[lock_index];
int res;
- res
- = acquired_lock ? pthread_mutex_trylock (lock) : pthread_mutex_lock (lock);
+ res = acquired_lock ? caf_shmem_mutex_trylock (lock)
+ : caf_shmem_mutex_lock (lock);
if (stat)
*stat = res == EBUSY ? GFC_STAT_LOCKED : 0;
@@ -1501,28 +1521,32 @@ _gfortran_caf_lock (caf_token_t token, size_t index,
{
if (errmsg_len > 0)
{
- size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
- : sizeof (msg);
+ 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);
+ 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)),
+_gfortran_caf_unlock (caf_token_t token, size_t index, int image_index,
int *stat, char *errmsg, size_t errmsg_len)
{
const char *msg = "Variable is not locked";
- lock_t *lock = &((lock_t *) MEMTOK (token))[index];
+#if defined(WIN32) || defined(__CYGWIN__)
+ const size_t lock_index
+ = image_index * caf_current_team->u.image_info->image_count.count + index;
+#else
+ const size_t lock_index = index;
+ (void) image_index; // Prevent unused warnings.
+#endif
+ lock_t *lock = &((lock_t *) MEMTOK (token))[lock_index];
int res;
- res = pthread_mutex_unlock (lock);
+ res = caf_shmem_mutex_unlock (lock);
if (res == 0)
{
@@ -1535,34 +1559,33 @@ _gfortran_caf_unlock (caf_token_t token, size_t index,
{
/* res == EPERM means that the lock is locked. Now figure, if by us by
trying to lock it or by other image, which fails. */
- res = pthread_mutex_trylock (lock);
+ res = caf_shmem_mutex_trylock (lock);
if (res == EBUSY)
*stat = GFC_STAT_LOCKED_OTHER_IMAGE;
else
{
*stat = GFC_STAT_UNLOCKED;
- pthread_mutex_unlock (lock);
+ caf_shmem_mutex_unlock (lock);
}
if (errmsg_len > 0)
{
- size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
- : sizeof (msg);
+ 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);
+ memset (&errmsg[len], ' ', errmsg_len - len);
}
return;
}
_gfortran_caf_error_stop_str (msg, strlen (msg), false);
}
-
/* Reference the libraries implementation. */
extern void _gfortran_random_seed_i4 (int32_t *size, gfc_array_i4 *put,
gfc_array_i4 *get);
-void _gfortran_caf_random_init (bool repeatable, bool image_distinct)
+void
+_gfortran_caf_random_init (bool repeatable, bool image_distinct)
{
static struct
{
@@ -1720,8 +1743,8 @@ _gfortran_caf_form_team (int team_no, caf_team_t *team, int *new_index,
++i)
t->u.image_info->image_map[i] = -1;
}
- counter_barrier_add (&t->u.image_info->image_count, 1);
- counter_barrier_add (&t->u.image_info->collsub.barrier, 1);
+ counter_barrier_init_add (&t->u.image_info->image_count, 1);
+ counter_barrier_init_add (&t->u.image_info->collsub.barrier, 1);
allocator_unlock (&local->ai.alloc);
if (new_index)
diff --git a/libgfortran/caf/shmem/alloc.c b/libgfortran/caf/shmem/alloc.c
index fecf97c03ff..ea250ac6922 100644
--- a/libgfortran/caf/shmem/alloc.c
+++ b/libgfortran/caf/shmem/alloc.c
@@ -30,9 +30,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "../caf_error.h"
#include "supervisor.h"
#include "shared_memory.h"
+#include "thread_support.h"
#include <assert.h>
-#include <pthread.h>
#include <string.h>
/* Worker's part to initialize the alloc interface. */
diff --git a/libgfortran/caf/shmem/allocator.c b/libgfortran/caf/shmem/allocator.c
index 3ea4d50e045..2a22abb2a80 100644
--- a/libgfortran/caf/shmem/allocator.c
+++ b/libgfortran/caf/shmem/allocator.c
@@ -133,11 +133,11 @@ allocator_shared_free (allocator *a, shared_mem_ptr p, size_t size)
void
allocator_lock (allocator *a)
{
- pthread_mutex_lock (&a->s->lock);
+ caf_shmem_mutex_lock (&a->s->lock);
}
void
allocator_unlock (allocator *a)
{
- pthread_mutex_unlock (&a->s->lock);
+ caf_shmem_mutex_unlock (&a->s->lock);
}
diff --git a/libgfortran/caf/shmem/allocator.h b/libgfortran/caf/shmem/allocator.h
index 53b6abeeba1..0cf31ea837a 100644
--- a/libgfortran/caf/shmem/allocator.h
+++ b/libgfortran/caf/shmem/allocator.h
@@ -29,16 +29,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define ALLOCATOR_HDR
#include "shared_memory.h"
+#include "thread_support.h"
#include <stddef.h>
-#include <pthread.h>
/* The number of bits a void pointer has. */
#define VOIDP_BITS (__CHAR_BIT__ * sizeof (void *))
/* The shared memory part of the allocator. */
typedef struct {
- pthread_mutex_t lock;
+ caf_shmem_mutex lock;
shared_mem_ptr free_bucket_head[VOIDP_BITS];
} allocator_shared;
diff --git a/libgfortran/caf/shmem/collective_subroutine.c b/libgfortran/caf/shmem/collective_subroutine.c
index 257a048d63d..d261b412a93 100644
--- a/libgfortran/caf/shmem/collective_subroutine.c
+++ b/libgfortran/caf/shmem/collective_subroutine.c
@@ -198,7 +198,7 @@ get_collsub_buf (size_t size)
{
void *ret;
- pthread_mutex_lock (&caf_current_team->u.image_info->collsub.mutex);
+ caf_shmem_mutex_lock (&caf_current_team->u.image_info->collsub.mutex);
/* curr_size is always at least sizeof(double), so we don't need to worry
about size == 0. */
if (size > caf_current_team->u.image_info->collsub.curr_size)
@@ -214,7 +214,7 @@ get_collsub_buf (size_t size)
ret = SHMPTR_AS (void *, caf_current_team->u.image_info->collsub.collsub_buf,
&local->sm);
- pthread_mutex_unlock (&caf_current_team->u.image_info->collsub.mutex);
+ caf_shmem_mutex_unlock (&caf_current_team->u.image_info->collsub.mutex);
return ret;
}
diff --git a/libgfortran/caf/shmem/collective_subroutine.h b/libgfortran/caf/shmem/collective_subroutine.h
index 8c37186c867..bdddab07a93 100644
--- a/libgfortran/caf/shmem/collective_subroutine.h
+++ b/libgfortran/caf/shmem/collective_subroutine.h
@@ -36,7 +36,7 @@ typedef struct collsub_shared
size_t curr_size;
shared_mem_ptr collsub_buf;
counter_barrier barrier;
- pthread_mutex_t mutex;
+ caf_shmem_mutex mutex;
} collsub_shared;
void collsub_init_supervisor (collsub_shared *, allocator *,
diff --git a/libgfortran/caf/shmem/counter_barrier.c b/libgfortran/caf/shmem/counter_barrier.c
index f78ba7fe852..2cda2afb2ed 100644
--- a/libgfortran/caf/shmem/counter_barrier.c
+++ b/libgfortran/caf/shmem/counter_barrier.c
@@ -34,7 +34,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
static inline void
lock_counter_barrier (counter_barrier *b)
{
- pthread_mutex_lock (&b->mutex);
+ caf_shmem_mutex_lock (&b->mutex);
}
/* Unlock the associated counter of this barrier. */
@@ -42,15 +42,15 @@ lock_counter_barrier (counter_barrier *b)
static inline void
unlock_counter_barrier (counter_barrier *b)
{
- pthread_mutex_unlock (&b->mutex);
+ caf_shmem_mutex_unlock (&b->mutex);
}
void
counter_barrier_init (counter_barrier *b, int val)
{
- *b = (counter_barrier) {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
- val, 0, val};
- initialize_shared_condition (&b->cond);
+ *b = (counter_barrier) {CAF_SHMEM_MUTEX_INITIALIZER,
+ CAF_SHMEM_COND_INITIALIZER, val, 0, val};
+ initialize_shared_condition (&b->cond, val);
initialize_shared_mutex (&b->mutex);
}
@@ -60,15 +60,14 @@ counter_barrier_wait (counter_barrier *b)
int wait_group_beginning;
lock_counter_barrier (b);
-
wait_group_beginning = b->curr_wait_group;
if ((--b->wait_count) <= 0)
- pthread_cond_broadcast (&b->cond);
+ caf_shmem_cond_broadcast (&b->cond);
else
{
while (b->wait_count > 0 && b->curr_wait_group == wait_group_beginning)
- pthread_cond_wait (&b->cond, &b->mutex);
+ caf_shmem_cond_wait (&b->cond, &b->mutex);
}
if (b->wait_count <= 0)
@@ -80,13 +79,12 @@ counter_barrier_wait (counter_barrier *b)
unlock_counter_barrier (b);
}
-
static inline void
change_internal_barrier_count (counter_barrier *b, int val)
{
b->wait_count += val;
if (b->wait_count <= 0)
- pthread_cond_broadcast (&b->cond);
+ caf_shmem_cond_broadcast (&b->cond);
}
int
@@ -103,19 +101,27 @@ int
counter_barrier_add (counter_barrier *c, int val)
{
int ret;
- pthread_mutex_lock (&c->mutex);
+ caf_shmem_mutex_lock (&c->mutex);
ret = counter_barrier_add_locked (c, val);
- pthread_mutex_unlock (&c->mutex);
+ caf_shmem_mutex_unlock (&c->mutex);
return ret;
}
+void
+counter_barrier_init_add (counter_barrier *b, int val)
+{
+ b->count += val;
+ b->wait_count += val;
+ caf_shmem_cond_update_count (&b->cond, val);
+}
+
int
counter_barrier_get_count (counter_barrier *c)
{
int ret;
- pthread_mutex_lock (&c->mutex);
+ caf_shmem_mutex_lock (&c->mutex);
ret = c->count;
- pthread_mutex_unlock (&c->mutex);
+ caf_shmem_mutex_unlock (&c->mutex);
return ret;
}
diff --git a/libgfortran/caf/shmem/counter_barrier.h b/libgfortran/caf/shmem/counter_barrier.h
index a28c58812a5..ab3d35ada74 100644
--- a/libgfortran/caf/shmem/counter_barrier.h
+++ b/libgfortran/caf/shmem/counter_barrier.h
@@ -25,7 +25,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef COUNTER_BARRIER_HDR
#define COUNTER_BARRIER_HDR
-#include <pthread.h>
+#include "thread_support.h"
/* Usable as counter barrier and as waitable counter.
This "class" allows to sync all images acting as a barrier. For this the
@@ -41,8 +41,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
typedef struct
{
- pthread_mutex_t mutex;
- pthread_cond_t cond;
+ caf_shmem_mutex mutex;
+ caf_shmem_condvar cond;
volatile int wait_count;
volatile int curr_wait_group;
volatile int count;
@@ -65,6 +65,10 @@ int counter_barrier_add_locked (counter_barrier *, int);
int counter_barrier_add (counter_barrier *, int);
+/* Add the given number to the counter barrier. This version does not signal.
+ The mutex needs to be locked for this routine to be safe. */
+void counter_barrier_init_add (counter_barrier *, int);
+
/* Get the count of the barrier. */
int counter_barrier_get_count (counter_barrier *);
diff --git a/libgfortran/caf/shmem/shared_memory.c b/libgfortran/caf/shmem/shared_memory.c
index 2b3666ddd3b..d0789a4bac6 100644
--- a/libgfortran/caf/shmem/shared_memory.c
+++ b/libgfortran/caf/shmem/shared_memory.c
@@ -22,6 +22,10 @@ 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/>. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "libgfortran.h"
#include "allocator.h"
#include "shared_memory.h"
@@ -30,7 +34,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
+#elif defined(WIN32)
+#include <Windows.h>
+#include <Memoryapi.h>
+#endif
#include <unistd.h>
/* This implements shared memory based on POSIX mmap. We start with
@@ -56,7 +65,11 @@ shared_memory_set_env (pid_t pid)
char buffer[bufsize];
snprintf (buffer, bufsize, "%d", pid);
+#ifdef HAVE_SETENV
setenv (ENV_PPID, buffer, 1);
+#else
+ SetEnvironmentVariable (ENV_PPID, buffer);
+#endif
#undef bufsize
}
@@ -82,7 +95,7 @@ shared_mem_ptr
shared_memory_get_master (shared_memory_act *mem, size_t size, size_t align)
{
if (mem->glbl.meta->master)
- return (shared_mem_ptr) {mem->glbl.meta->master};
+ return (shared_mem_ptr) {mem->glbl.meta->master};
else
{
ptrdiff_t loc = mem->glbl.meta->used;
@@ -112,7 +125,6 @@ shared_memory_init (shared_memory_act *mem, size_t size)
char shm_name[NAME_MAX];
const char *env_val = getenv (ENV_PPID), *base = getenv (ENV_BASE);
pid_t ppid = getpid ();
- int shm_fd, res;
void *base_ptr;
if (env_val)
@@ -131,70 +143,138 @@ shared_memory_init (shared_memory_act *mem, size_t size)
if (!env_val)
{
- shm_fd = shm_open (shm_name, O_CREAT | O_RDWR | O_EXCL, 0600);
- if (shm_fd == -1)
+#ifdef HAVE_MMAP
+ int res;
+
+ mem->shm_fd = shm_open (shm_name, O_CREAT | O_RDWR | O_EXCL, 0600);
+ if (mem->shm_fd == -1)
{
perror ("creating shared memory segment failed.");
exit (1);
}
- res = ftruncate (shm_fd, size);
+ res = ftruncate (mem->shm_fd, size);
if (res == -1)
{
perror ("resizing shared memory segment failed.");
exit (1);
}
+#elif defined(WIN32)
+ mem->shm_fd
+ = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
+ size >> (sizeof (DWORD) * 8),
+ (DWORD) (size & ~((DWORD) 0)), shm_name);
+ if (mem->shm_fd == NULL)
+ {
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError ();
+
+ if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL)
+ == 0)
+ {
+ fprintf (stderr, "formatting the error message failed.\n");
+ ExitProcess (dw);
+ }
+
+ fprintf (stderr, "creating shared memory segment failed: %d, %s\n",
+ dw, (LPCTSTR) lpMsgBuf);
+
+ LocalFree (lpMsgBuf);
+ exit (1);
+ }
+#else
+#error "no way to map shared memory."
+#endif
}
else
{
- shm_fd = shm_open (shm_name, O_RDWR, 0);
- if (shm_fd == -1)
+#ifdef HAVE_MMAP
+ mem->shm_fd = shm_open (shm_name, O_RDWR, 0);
+ if (mem->shm_fd == -1)
{
perror ("opening shared memory segment failed.");
exit (1);
}
+#elif defined(WIN32)
+ mem->shm_fd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, shm_name);
+ if (mem->shm_fd == NULL)
+ {
+ perror ("opening shared memory segment failed.");
+ exit (1);
+ }
+#endif
}
-
+#ifdef HAVE_MMAP
mem->glbl.base
- = mmap (base_ptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
- res = close (shm_fd);
+ = mmap (base_ptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, mem->shm_fd, 0);
if (mem->glbl.base == MAP_FAILED)
{
perror ("mmap failed");
exit (1);
}
+#elif defined(WIN32)
+ mem->glbl.base
+ = (LPTSTR) MapViewOfFileExNuma (mem->shm_fd, FILE_MAP_ALL_ACCESS, 0, 0,
+ size, base_ptr, NUMA_NO_PREFERRED_NODE);
+ if (mem->glbl.base == NULL)
+ {
+ perror ("MapViewOfFile failed");
+ exit (1);
+ }
+#endif
if (!base_ptr)
{
#define bufsize 20
char buffer[bufsize];
snprintf (buffer, bufsize, "%p", mem->glbl.base);
+#ifdef HAVE_SETENV
setenv (ENV_BASE, buffer, 1);
+#else
+ SetEnvironmentVariable (ENV_BASE, buffer);
+#endif
#undef bufsize
}
- if (res)
- { // from close()
- perror ("closing shm file handle failed. Trying to continue...");
- }
mem->size = size;
if (!env_val)
*mem->glbl.meta
= (global_shared_memory_meta) {sizeof (global_shared_memory_meta), 0};
-
}
void
-shared_memory_cleanup (shared_memory_act *)
+shared_memory_cleanup (shared_memory_act *mem)
{
char shm_name[NAME_MAX];
- int res;
snprintf (shm_name, NAME_MAX, "/gfor-shm-%s", shared_memory_get_env ());
+#ifdef HAVE_MMAP
+ int res = munmap (mem->glbl.base, mem->size);
+ if (res)
+ {
+ perror ("unmapping shared memory segment failed");
+ }
+ res = close (mem->shm_fd);
+ if (res)
+ {
+ perror ("closing shm file handle failed. Trying to continue...");
+ }
res = shm_unlink (shm_name);
if (res == -1)
{
perror ("shm_unlink failed");
exit (1);
}
+#elif defined(WIN32)
+ if (!UnmapViewOfFile (mem->glbl.base))
+ {
+ perror ("unmapping shared memory segment failed");
+ }
+ CloseHandle (mem->shm_fd);
+#endif
}
#undef NAME_MAX
diff --git a/libgfortran/caf/shmem/shared_memory.h b/libgfortran/caf/shmem/shared_memory.h
index 01ac2811e5d..3d031875ed2 100644
--- a/libgfortran/caf/shmem/shared_memory.h
+++ b/libgfortran/caf/shmem/shared_memory.h
@@ -25,6 +25,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef SHARED_MEMORY_H
#define SHARED_MEMORY_H
+#include "thread_support.h"
+
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
@@ -47,6 +49,7 @@ typedef struct shared_memory_act
global_shared_memory_meta *meta;
} glbl;
size_t size; // const
+ caf_shmem_fd shm_fd;
} shared_memory_act;
/* A struct to serve as shared memory object. */
diff --git a/libgfortran/caf/shmem/supervisor.c b/libgfortran/caf/shmem/supervisor.c
index e4310b03e43..c39ffc6715c 100644
--- a/libgfortran/caf/shmem/supervisor.c
+++ b/libgfortran/caf/shmem/supervisor.c
@@ -22,8 +22,6 @@ 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 "config.h"
-
#include "../caf_error.h"
#include "supervisor.h"
#include "teams_mgmt.h"
@@ -38,6 +36,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#elif HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
+#if !defined(_SC_PAGE_SIZE) && defined(WIN32)
+#include <windows.h>
+#endif
#define GFORTRAN_ENV_NUM_IMAGES "GFORTRAN_NUM_IMAGES"
#define GFORTRAN_ENV_SHARED_MEMORY_SIZE "GFORTRAN_SHARED_MEMORY_SIZE"
@@ -56,8 +57,13 @@ get_image_num_from_envvar (void)
int nimages;
num_images_char = getenv (GFORTRAN_ENV_NUM_IMAGES);
if (!num_images_char)
- return sysconf (_SC_NPROCESSORS_ONLN); /* TODO: Make portable. */
- /* TODO: Error checking. */
+#ifdef _SC_NPROCESSORS_ONLN
+ return sysconf (_SC_NPROCESSORS_ONLN);
+#elif defined(WIN32)
+ num_images_char = getenv ("NUMBER_OF_PROCESSORS");
+#else
+#error "Unsupported system: No known way to get number of cores!"
+#endif
nimages = atoi (num_images_char);
return nimages;
}
@@ -105,7 +111,12 @@ get_memory_size_from_envvar (void)
if (sizeof (size_t) == 4)
sz = ((size_t) 1) << 28;
else
+#ifndef WIN32
sz = ((size_t) 1) << 34;
+#else
+ /* Use 1GB on Windows. */
+ sz = ((size_t) 1) << 30;
+#endif
}
return sz;
}
@@ -146,7 +157,19 @@ ensure_shmem_initialization (void)
return;
local = malloc (sizeof (image_local));
+#if defined(_SC_PAGE_SIZE)
pagesize = sysconf (_SC_PAGE_SIZE);
+#elif defined(WIN32)
+ {
+ SYSTEM_INFO si;
+ GetNativeSystemInfo (&si);
+ pagesize = si.dwAllocationGranularity;
+ }
+#else
+#warning \
+ "Unsupported system: No known way to get memory page size. Assuming 4k!"
+ pagesize = 4096;
+#endif
shmem_size = round_to_pagesize (get_memory_size_from_envvar ());
local->total_num_images = get_image_num_from_envvar ();
shared_memory_init (&local->sm, shmem_size);
@@ -199,6 +222,7 @@ ensure_shmem_initialization (void)
{
this_image = (image) {-1, get_supervisor ()};
this_image.supervisor->magic_number = SUPERVISOR_MAGIC_NUM;
+ thread_support_init_supervisor ();
counter_barrier_init (&this_image.supervisor->num_active_images,
local->total_num_images);
alloc_init_supervisor (&local->ai, &local->sm);
@@ -206,16 +230,31 @@ ensure_shmem_initialization (void)
}
}
+#if !defined(environ)
extern char **environ;
+#endif
+/* argc and argv may not be used on certain OSes. Flag them unused therefore.
+ */
int
-supervisor_main_loop (int *argc __attribute__ ((unused)), char ***argv,
- int *exit_code)
+supervisor_main_loop (int *argc __attribute__ ((unused)),
+ char ***argv __attribute__ ((unused)), int *exit_code)
{
supervisor *m;
- pid_t new_pid, finished_pid;
image im;
+#if defined(WIN32) && !defined(HAVE_FORK)
+ HANDLE *process_handles = malloc (sizeof (HANDLE) * local->total_num_images),
+ *thread_handles = malloc (sizeof (HANDLE) * local->total_num_images),
+ *waiting_handles = malloc (sizeof (HANDLE) * local->total_num_images);
+ int count_waiting = local->total_num_images;
+ LPTCH *envs = malloc (sizeof (LPTCH) * local->total_num_images);
+ LPTSTR currentDir;
+ DWORD cdLen = GetCurrentDirectory (0, NULL);
+ currentDir = malloc (cdLen);
+ GetCurrentDirectory (cdLen, currentDir);
+#else
int chstatus;
+#endif
*exit_code = 0;
shared_memory_set_env (getpid ());
@@ -223,6 +262,8 @@ supervisor_main_loop (int *argc __attribute__ ((unused)), char ***argv,
for (im.image_num = 0; im.image_num < local->total_num_images; im.image_num++)
{
+#ifdef HAVE_FORK
+ caf_shmem_pid new_pid;
if ((new_pid = fork ()))
{
if (new_pid == -1)
@@ -247,10 +288,63 @@ supervisor_main_loop (int *argc __attribute__ ((unused)), char ***argv,
execve ((*argv)[0], *argv, new_env);
return 1;
}
+#elif defined(WIN32)
+ LPTCH new_env;
+ size_t n = 0, es;
+ STARTUPINFO si;
+ DWORD dwFlags = 0;
+ PROCESS_INFORMATION pi;
+ LPTCH env = GetEnvironmentStrings ();
+
+ ZeroMemory (&si, sizeof (si));
+ si.cb = sizeof (si);
+ ZeroMemory (&pi, sizeof (pi));
+
+ /* Count the number of characters in the current environment. */
+ for (LPTSTR e = (LPTSTR) env; *e; es = lstrlen (e) + 1, e += es, n += es)
+ ;
+ new_env = (LPCH) malloc (n + 32 * sizeof (TCHAR));
+ memcpy (new_env, env, n);
+ snprintf (&((TCHAR *) new_env)[n], 32, "%s=%d%c", GFORTRAN_ENV_IMAGE_NUM,
+ im.image_num, (char) 0);
+ if (!CreateProcessA (NULL, GetCommandLine (), NULL, NULL, FALSE, dwFlags,
+ new_env, currentDir, &si, &pi))
+ {
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError ();
+
+ if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL)
+ == 0)
+ {
+ fprintf (stderr, "formatting the error message failed.\n");
+ ExitProcess (dw);
+ }
+
+ fprintf (stderr, "error spawning child: %ld, %s\n", dw,
+ (LPCTSTR) lpMsgBuf);
+
+ LocalFree (lpMsgBuf);
+ exit (1);
+ }
+ m->images[im.image_num] = (image_tracker) {pi.hProcess, IMAGE_OK};
+ process_handles[im.image_num] = waiting_handles[im.image_num]
+ = pi.hProcess;
+ thread_handles[im.image_num] = pi.hThread;
+ envs[im.image_num] = new_env;
+#else
+#error "no way known to start child processes."
+#endif
}
- for (int j, i = 0; i < local->total_num_images; i++)
+ for (int i = 0; i < local->total_num_images; i++)
{
- finished_pid = wait (&chstatus);
+#ifdef HAVE_FORK
+ caf_shmem_pid finished_pid = wait (&chstatus);
+ int j;
if (WIFEXITED (chstatus) && !WEXITSTATUS (chstatus))
{
for (j = 0;
@@ -303,10 +397,77 @@ supervisor_main_loop (int *argc __attribute__ ((unused)), char ***argv,
}
/* Trigger waiting sync images aka sync_table. */
for (j = 0; j < local->total_num_images; j++)
- pthread_cond_signal (&SHMPTR_AS (pthread_cond_t *,
- m->sync_shared.sync_images_cond_vars,
- &local->sm)[j]);
+ caf_shmem_cond_signal (&SHMPTR_AS (caf_shmem_condvar *,
+ m->sync_shared.sync_images_cond_vars,
+ &local->sm)[j]);
counter_barrier_add (&m->num_active_images, -1);
+#elif defined(WIN32)
+ DWORD res = WaitForMultipleObjects (count_waiting, waiting_handles, FALSE,
+ INFINITE);
+ HANDLE cand;
+ bool progress = false;
+ DWORD process_exit_code;
+ if (res == WAIT_FAILED)
+ caf_runtime_error ("waiting for process termination failed.");
+ int index = res - WAIT_OBJECT_0, finished_process;
+ bool fail;
+
+ do
+ {
+ cand = waiting_handles[index];
+ for (finished_process = 0;
+ finished_process < local->total_num_images
+ && cand != process_handles[finished_process];
+ ++finished_process)
+ ;
+
+ GetExitCodeProcess (cand, &process_exit_code);
+ fail = process_exit_code != 0;
+ fprintf (stderr, "terminating process %d with fail status %d (%ld)\n",
+ finished_process, fail, process_exit_code);
+ if (finished_process < local->total_num_images)
+ {
+ CloseHandle (process_handles[finished_process]);
+ process_handles[finished_process] = NULL;
+ CloseHandle (thread_handles[finished_process]);
+ FreeEnvironmentStrings (envs[finished_process]);
+ if (fail)
+ {
+ m->images[finished_process].status = IMAGE_FAILED;
+ atomic_fetch_add (&m->failed_images, 1);
+ if (*exit_code < process_exit_code)
+ *exit_code = process_exit_code;
+ }
+ else
+ {
+ m->images[finished_process].status = IMAGE_SUCCESS;
+ atomic_fetch_add (&m->finished_images, 1);
+ }
+ }
+ memmove (&waiting_handles[index], &waiting_handles[index + 1],
+ sizeof (HANDLE) * (count_waiting - index - 1));
+ --count_waiting;
+ counter_barrier_add (&m->num_active_images, -1);
+
+ /* Check if more than one process has terminated already. */
+ progress = false;
+ for (index = 0; index < count_waiting; ++index)
+ if (WaitForSingleObject (waiting_handles[index], 0)
+ == WAIT_OBJECT_0)
+ {
+ progress = true;
+ ++i;
+ break;
+ }
+ }
+ while (progress && count_waiting > 0);
+#endif
}
+
+#if defined(WIN32) && !defined(HAVE_FORK)
+ free (process_handles);
+ free (thread_handles);
+ free (envs);
+#endif
return 0;
}
diff --git a/libgfortran/caf/shmem/supervisor.h b/libgfortran/caf/shmem/supervisor.h
index 7afb8269674..7e5e19702e4 100644
--- a/libgfortran/caf/shmem/supervisor.h
+++ b/libgfortran/caf/shmem/supervisor.h
@@ -25,6 +25,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef SUPERVISOR_H
#define SUPERVISOR_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "caf/libcaf.h"
#include "alloc.h"
#include "collective_subroutine.h"
@@ -42,7 +46,7 @@ typedef enum
typedef struct
{
- pid_t pid;
+ caf_shmem_pid pid;
image_status status;
} image_tracker;
@@ -56,7 +60,10 @@ typedef struct supervisor
atomic_int failed_images;
atomic_int finished_images;
counter_barrier num_active_images;
- pthread_mutex_t image_tracker_lock;
+ caf_shmem_mutex image_tracker_lock;
+#ifdef WIN32
+ size_t global_used_handles;
+#endif
image_tracker images[];
} supervisor;
diff --git a/libgfortran/caf/shmem/sync.c b/libgfortran/caf/shmem/sync.c
index a456244629c..e1020a1e864 100644
--- a/libgfortran/caf/shmem/sync.c
+++ b/libgfortran/caf/shmem/sync.c
@@ -33,13 +33,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
static inline void
lock_table (sync_t *si)
{
- pthread_mutex_lock (&si->cis->sync_images_table_lock);
+ caf_shmem_mutex_lock (&si->cis->sync_images_table_lock);
}
static inline void
unlock_table (sync_t *si)
{
- pthread_mutex_unlock (&si->cis->sync_images_table_lock);
+ caf_shmem_mutex_unlock (&si->cis->sync_images_table_lock);
}
void
@@ -48,7 +48,7 @@ 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 (pthread_cond_t *,
+ SHMPTR_AS (caf_shmem_condvar *,
this_image.supervisor->sync_shared.sync_images_cond_vars, sm)};
}
@@ -61,7 +61,7 @@ sync_init_supervisor (sync_t *si, alloc *ai)
si->cis = &this_image.supervisor->sync_shared;
initialize_shared_mutex (&si->cis->event_lock);
- initialize_shared_condition (&si->cis->event_cond);
+ initialize_shared_condition (&si->cis->event_cond, num_images);
initialize_shared_mutex (&si->cis->sync_images_table_lock);
@@ -69,14 +69,14 @@ sync_init_supervisor (sync_t *si, alloc *ai)
= 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 (pthread_cond_t) * num_images);
+ sizeof (caf_shmem_condvar) * num_images);
si->table = SHMPTR_AS (int *, si->cis->sync_images_table, ai->mem);
si->triggers
- = SHMPTR_AS (pthread_cond_t *, si->cis->sync_images_cond_vars, ai->mem);
+ = 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]);
+ initialize_shared_condition (&si->triggers[i], num_images);
memset (si->table, 0, table_size_in_bytes);
}
@@ -103,7 +103,7 @@ sync_table (sync_t *si, int *images, int size)
for (i = 0; i < size; ++i)
{
++table[images[i] + img_c * this_image.image_num];
- pthread_cond_signal (&si->triggers[images[i]]);
+ caf_shmem_cond_signal (&si->triggers[images[i]]);
}
for (;;)
{
@@ -114,7 +114,7 @@ sync_table (sync_t *si, int *images, int size)
break;
if (i == size)
break;
- pthread_cond_wait (&si->triggers[this_image.image_num],
+ caf_shmem_cond_wait (&si->triggers[this_image.image_num],
&si->cis->sync_images_table_lock);
}
}
@@ -127,7 +127,7 @@ sync_table (sync_t *si, int *images, int size)
if (this_image.supervisor->images[map[i]].status != IMAGE_OK)
continue;
++table[map[i] + size * this_image.image_num];
- pthread_cond_signal (&si->triggers[map[i]]);
+ caf_shmem_cond_signal (&si->triggers[map[i]]);
}
for (;;)
{
@@ -138,7 +138,7 @@ sync_table (sync_t *si, int *images, int size)
break;
if (i == size)
break;
- pthread_cond_wait (&si->triggers[this_image.image_num],
+ caf_shmem_cond_wait (&si->triggers[this_image.image_num],
&si->cis->sync_images_table_lock);
}
}
@@ -160,23 +160,23 @@ sync_team (caf_shmem_team_t team)
void
lock_event (sync_t *si)
{
- pthread_mutex_lock (&si->cis->event_lock);
+ caf_shmem_mutex_lock (&si->cis->event_lock);
}
void
unlock_event (sync_t *si)
{
- pthread_mutex_unlock (&si->cis->event_lock);
+ caf_shmem_mutex_unlock (&si->cis->event_lock);
}
void
event_post (sync_t *si)
{
- pthread_cond_broadcast (&si->cis->event_cond);
+ caf_shmem_cond_broadcast (&si->cis->event_cond);
}
void
event_wait (sync_t *si)
{
- pthread_cond_wait (&si->cis->event_cond, &si->cis->event_lock);
+ caf_shmem_cond_wait (&si->cis->event_cond, &si->cis->event_lock);
}
diff --git a/libgfortran/caf/shmem/sync.h b/libgfortran/caf/shmem/sync.h
index a3e586bca24..a6d20614b67 100644
--- a/libgfortran/caf/shmem/sync.h
+++ b/libgfortran/caf/shmem/sync.h
@@ -28,13 +28,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "alloc.h"
#include "counter_barrier.h"
-#include <pthread.h>
-
typedef struct {
/* Mutex and condition variable needed for signaling events. */
- pthread_mutex_t event_lock;
- pthread_cond_t event_cond;
- pthread_mutex_t sync_images_table_lock;
+ caf_shmem_mutex event_lock;
+ caf_shmem_condvar event_cond;
+ caf_shmem_mutex sync_images_table_lock;
shared_mem_ptr sync_images_table;
shared_mem_ptr sync_images_cond_vars;
} sync_shared;
@@ -42,10 +40,10 @@ typedef struct {
typedef struct {
sync_shared *cis;
int *table; // we can cache the table and the trigger pointers here
- pthread_cond_t *triggers;
+ caf_shmem_condvar *triggers;
} sync_t;
-typedef pthread_mutex_t lock_t;
+typedef caf_shmem_mutex lock_t;
typedef int event_t;
diff --git a/libgfortran/caf/shmem/teams_mgmt.c b/libgfortran/caf/shmem/teams_mgmt.c
index 44a34d727c3..9bf8db2302c 100644
--- a/libgfortran/caf/shmem/teams_mgmt.c
+++ b/libgfortran/caf/shmem/teams_mgmt.c
@@ -31,7 +31,7 @@ caf_shmem_team_t caf_teams_formed = NULL;
void
update_teams_images (caf_shmem_team_t team)
{
- pthread_mutex_lock (&team->u.image_info->image_count.mutex);
+ caf_shmem_mutex_lock (&team->u.image_info->image_count.mutex);
if (team->u.image_info->num_term_images
!= this_image.supervisor->finished_images
+ this_image.supervisor->failed_images)
@@ -52,7 +52,7 @@ update_teams_images (caf_shmem_team_t team)
old_num
- team->u.image_info->num_term_images);
}
- pthread_mutex_unlock (&team->u.image_info->image_count.mutex);
+ caf_shmem_mutex_unlock (&team->u.image_info->image_count.mutex);
}
void
diff --git a/libgfortran/caf/shmem/thread_support.c b/libgfortran/caf/shmem/thread_support.c
old mode 100644
new mode 100755
index 572f39400b3..e2c53627c2f
--- a/libgfortran/caf/shmem/thread_support.c
+++ b/libgfortran/caf/shmem/thread_support.c
@@ -28,6 +28,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <stdlib.h>
#include <stdio.h>
+#if !defined(WIN32) && !defined(__CYGWIN__)
+#include <pthread.h>
+
#define ERRCHECK(a) \
do \
{ \
@@ -42,7 +45,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
while (0)
void
-initialize_shared_mutex (pthread_mutex_t *mutex)
+initialize_shared_mutex (caf_shmem_mutex *mutex)
{
pthread_mutexattr_t mattr;
ERRCHECK (pthread_mutexattr_init (&mattr));
@@ -52,18 +55,18 @@ initialize_shared_mutex (pthread_mutex_t *mutex)
}
void
-initialize_shared_errorcheck_mutex (pthread_mutex_t *mutex)
+initialize_shared_errorcheck_mutex (caf_shmem_mutex *mutex)
{
pthread_mutexattr_t mattr;
ERRCHECK (pthread_mutexattr_init (&mattr));
- ERRCHECK (pthread_mutexattr_setpshared (&mattr, PTHREAD_PROCESS_SHARED));
ERRCHECK (pthread_mutexattr_settype (&mattr, PTHREAD_MUTEX_ERRORCHECK));
+ 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)
+initialize_shared_condition (caf_shmem_condvar *cond, const int)
{
pthread_condattr_t cattr;
ERRCHECK (pthread_condattr_init (&cattr));
@@ -71,3 +74,302 @@ initialize_shared_condition (pthread_cond_t *cond)
ERRCHECK (pthread_cond_init (cond, &cattr));
ERRCHECK (pthread_condattr_destroy (&cattr));
}
+#else
+#include "../caf_error.h"
+#include "supervisor.h"
+#include "teams_mgmt.h"
+#include <windows.h>
+#include <assert.h>
+
+static HANDLE *handles = NULL;
+static size_t cap_handles = 0;
+
+static const int ULONGBITS = sizeof (unsigned long) << 3; // *8
+
+static size_t
+smax (size_t a, size_t b)
+{
+ return a < b ? b : a;
+}
+
+static HANDLE
+get_handle (const size_t id, const char t)
+{
+ const int add = t == 'c' ? 1 : 0;
+ while (id + add >= cap_handles)
+ {
+ cap_handles += 1024;
+ if (handles)
+ handles = realloc (handles, sizeof (HANDLE) * cap_handles);
+ else
+ handles = malloc (sizeof (HANDLE) * cap_handles);
+ if (!handles)
+ caf_runtime_error (
+ "can not get buffer for synchronication objects, aborting");
+
+ memset (&handles[cap_handles - 1024], 0, sizeof (HANDLE) * 1024);
+ }
+ if (!handles[id])
+ {
+ static char *pid = NULL;
+ char name[MAX_PATH];
+
+ if (!pid)
+ pid = shared_memory_get_env ();
+ snprintf (name, MAX_PATH, "Global_gfortran-%s-%c-%zd", pid, t, id);
+ switch (t)
+ {
+ case 'm':
+ handles[id] = CreateMutex (NULL, false, name);
+ break;
+ case 'c':
+ {
+ handles[id] = CreateSemaphore (NULL, 0, __INT_MAX__, name);
+ snprintf (name, MAX_PATH, "Global_gfortran-%s-%c-%zd_lock", pid, t,
+ id);
+ handles[id + 1] = CreateSemaphore (NULL, 1, 1, name);
+ this_image.supervisor->global_used_handles
+ = smax (this_image.supervisor->global_used_handles, id + 2);
+ break;
+ }
+ default:
+ caf_runtime_error ("Unknown handle type %c", t);
+ exit (1);
+ }
+ if (handles[id] == NULL)
+ {
+ caf_runtime_error (
+ "Could not create synchronisation object, error: %d",
+ GetLastError ());
+ return NULL;
+ }
+
+ this_image.supervisor->global_used_handles
+ = smax (this_image.supervisor->global_used_handles, id + 1);
+ }
+
+ return handles[id];
+}
+
+static HANDLE
+get_mutex (caf_shmem_mutex *m)
+{
+ return get_handle (m->id, 'm');
+}
+
+static HANDLE
+get_condvar (caf_shmem_condvar *cv)
+{
+ return get_handle (cv->id, 'c');
+}
+
+void
+thread_support_init_supervisor (void)
+{
+ if (local->total_num_images > ULONGBITS * MAX_NUM_SIGNALED)
+ caf_runtime_error ("Maximum number of supported images is %zd.",
+ ULONGBITS * MAX_NUM_SIGNALED);
+ this_image.supervisor->global_used_handles = 0;
+}
+
+int
+caf_shmem_mutex_lock (caf_shmem_mutex *m)
+{
+ HANDLE mutex = get_mutex (m);
+ DWORD res = WaitForSingleObject (mutex, INFINITE);
+
+ /* Return zero on success. */
+ return res != WAIT_OBJECT_0;
+}
+
+int
+caf_shmem_mutex_trylock (caf_shmem_mutex *m)
+{
+ HANDLE mutex = get_mutex (m);
+ DWORD res = WaitForSingleObject (mutex, 0);
+
+ return res == WAIT_OBJECT_0 ? 0 : EBUSY;
+}
+
+int
+caf_shmem_mutex_unlock (caf_shmem_mutex *m)
+{
+ HANDLE mutex = get_mutex (m);
+ BOOL res = ReleaseMutex (mutex);
+
+ if (!res)
+ {
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError ();
+
+ if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, dw, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL)
+ == 0)
+ {
+ fprintf (stderr, "%d: formatting the error message failed.\n",
+ this_image.image_num);
+ ExitProcess (dw);
+ }
+
+ fprintf (stderr, "%d: unlock mutex failed: %d, %s\n",
+ this_image.image_num, dw, (LPCTSTR) lpMsgBuf);
+
+ LocalFree (lpMsgBuf);
+ }
+ return res ? 0 : EPERM;
+}
+
+static bool
+bm_is_set (volatile unsigned long mask[], const int b)
+{
+ return (mask[b / ULONGBITS] & (1UL << (b % ULONGBITS))) != 0;
+}
+
+static void
+bm_clear_bit (volatile unsigned long mask[], const int b)
+{
+ mask[b / ULONGBITS] &= ~(1UL << (b % ULONGBITS));
+}
+
+static void
+bm_set_mask (volatile unsigned long mask[], const int size)
+{
+ const int entries = size / ULONGBITS;
+ const int rem = size % ULONGBITS;
+ int i = 0;
+ assert (entries >= 0);
+
+ for (; i < entries; ++i)
+ mask[i] = ~0UL;
+ if (rem != 0)
+ mask[i] = ~0UL >> (ULONGBITS - rem);
+}
+
+__attribute_used__ static bool
+bm_is_none (volatile unsigned long mask[], const int size)
+{
+ const int entries = size / ULONGBITS;
+ const int rem = size % ULONGBITS;
+ int i = 0;
+ for (; i < entries; ++i)
+ if (mask[i] != 0)
+ return false;
+
+ return rem == 0 || ((mask[i] & (~0UL >> (ULONGBITS - rem))) == 0);
+}
+
+void
+caf_shmem_cond_wait (caf_shmem_condvar *cv, caf_shmem_mutex *m)
+{
+ HANDLE mutex = get_mutex (m), condvar = get_condvar (cv),
+ lock = get_handle (cv->id + 1, 'c');
+ HANDLE entry[3] = {mutex, condvar, lock};
+ int res;
+
+ WaitForSingleObject (lock, INFINITE);
+ for (;;)
+ {
+ if (bm_is_set (cv->signaled, this_image.image_num) || cv->any)
+ {
+ break;
+ }
+ ReleaseMutex (mutex);
+ ReleaseSemaphore (lock, 1, NULL);
+ res = WaitForMultipleObjects (3, entry, true, INFINITE);
+ if (res != WAIT_OBJECT_0)
+ {
+ fprintf (stderr, "%d: failed to get all wait for: %d\n",
+ this_image.image_num, res);
+ fflush (stderr);
+ }
+ ReleaseSemaphore (condvar, 1, NULL);
+ }
+ res = WaitForSingleObject (condvar, INFINITE);
+ if (res != WAIT_OBJECT_0)
+ {
+ fprintf (stderr, "%d: failed to get condvar: %d\n", this_image.image_num,
+ res);
+ fflush (stderr);
+ }
+
+ bm_clear_bit (cv->signaled, this_image.image_num);
+ cv->any = 0;
+ ReleaseSemaphore (lock, 1, NULL);
+}
+
+void
+caf_shmem_cond_broadcast (caf_shmem_condvar *cv)
+{
+ HANDLE condvar = get_condvar (cv), lock = get_handle (cv->id + 1, 'c');
+
+ WaitForSingleObject (lock, INFINITE);
+ bm_set_mask (cv->signaled, cv->size);
+ bm_clear_bit (cv->signaled, this_image.image_num);
+
+ ReleaseSemaphore (condvar, cv->size, NULL);
+ ReleaseSemaphore (lock, 1, NULL);
+}
+
+void
+caf_shmem_cond_signal (caf_shmem_condvar *cv)
+{
+ HANDLE condvar = get_condvar (cv), lock = get_handle (cv->id + 1, 'c');
+
+ if (caf_current_team)
+ {
+ WaitForSingleObject (lock, INFINITE);
+ }
+ else
+ return;
+ /* The first image is zero, which wouldn't allow it to signal. */
+ cv->any = this_image.image_num + 1;
+ ReleaseSemaphore (condvar, 1, NULL);
+ ReleaseSemaphore (lock, 1, NULL);
+}
+
+void
+caf_shmem_cond_update_count (caf_shmem_condvar *cv, int val)
+{
+ cv->size += val;
+}
+
+void
+initialize_shared_mutex (caf_shmem_mutex *m)
+{
+ *m = (caf_shmem_mutex) {this_image.supervisor->global_used_handles};
+
+ get_mutex (m);
+}
+
+void
+initialize_shared_errorcheck_mutex (caf_shmem_mutex *m)
+{
+ *m = (caf_shmem_mutex) {this_image.supervisor->global_used_handles};
+
+ get_mutex (m);
+}
+
+void
+initialize_shared_condition (caf_shmem_condvar *cv, const int size)
+{
+ *cv = (caf_shmem_condvar) {this_image.supervisor->global_used_handles,
+ 0,
+ size,
+ {}};
+
+ memset ((void *) cv->signaled, 0, sizeof (unsigned long) * MAX_NUM_SIGNALED);
+ get_condvar (cv);
+ assert (bm_is_none (cv->signaled, cv->size));
+}
+
+void
+thread_support_cleanup (void)
+{
+ for (size_t i = 0; i < this_image.supervisor->global_used_handles; ++i)
+ if (handles[i])
+ CloseHandle (handles[i]);
+}
+#endif
diff --git a/libgfortran/caf/shmem/thread_support.h b/libgfortran/caf/shmem/thread_support.h
old mode 100644
new mode 100755
index e70b4b83c7d..351cdbbb868
--- a/libgfortran/caf/shmem/thread_support.h
+++ b/libgfortran/caf/shmem/thread_support.h
@@ -25,14 +25,89 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef THREAD_SUPPORT_H
#define THREAD_SUPPORT_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef WIN32
+#include <sys/types.h>
+
+typedef pid_t caf_shmem_pid;
+typedef int caf_shmem_fd;
+#else
+#include <handleapi.h>
+
+typedef HANDLE caf_shmem_pid;
+typedef HANDLE caf_shmem_fd;
+#endif
+
+#if !defined(WIN32) && !defined(__CYGWIN__)
#include <pthread.h>
+typedef pthread_mutex_t caf_shmem_mutex;
+typedef pthread_cond_t caf_shmem_condvar;
+
+#define CAF_SHMEM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define CAF_SHMEM_COND_INITIALIZER PTHREAD_COND_INITIALIZER
+
+#define thread_support_init_supervisor() (void) 0
+
+#define caf_shmem_mutex_lock pthread_mutex_lock
+#define caf_shmem_mutex_trylock pthread_mutex_trylock
+#define caf_shmem_mutex_unlock pthread_mutex_unlock
+
+#define caf_shmem_cond_wait pthread_cond_wait
+#define caf_shmem_cond_broadcast pthread_cond_broadcast
+#define caf_shmem_cond_signal pthread_cond_signal
+#define caf_shmem_cond_update_count(c, v) (void) 0
+
+#define thread_support_cleanup() (void) 0
+#else
+#include <synchapi.h>
+#include <stddef.h>
+
+typedef struct caf_shmem_mutex
+{
+ size_t id;
+} caf_shmem_mutex;
+
+#define MAX_NUM_SIGNALED 8
+
+typedef struct caf_shmem_condvar
+{
+ size_t id;
+ volatile int any;
+ int size;
+ volatile unsigned long signaled[MAX_NUM_SIGNALED];
+} caf_shmem_condvar;
+
+#define CAF_SHMEM_MUTEX_INITIALIZER (caf_shmem_mutex){0}
+#define CAF_SHMEM_COND_INITIALIZER \
+ (caf_shmem_condvar) \
+ { \
+ 0, 0, 0, {} \
+ }
+
+void thread_support_init_supervisor (void);
+
+int caf_shmem_mutex_lock (caf_shmem_mutex *);
+int caf_shmem_mutex_trylock (caf_shmem_mutex *);
+int caf_shmem_mutex_unlock (caf_shmem_mutex *);
+
+void caf_shmem_cond_wait (caf_shmem_condvar *, caf_shmem_mutex *);
+void caf_shmem_cond_broadcast (caf_shmem_condvar *);
+void caf_shmem_cond_signal (caf_shmem_condvar *);
+void caf_shmem_cond_update_count (caf_shmem_condvar *, int);
+
+void thread_support_cleanup (void);
+#endif
+
/* Support routines to setup pthread structs in shared memory. */
-void initialize_shared_mutex (pthread_mutex_t *);
+void initialize_shared_mutex (caf_shmem_mutex *);
-void initialize_shared_errorcheck_mutex (pthread_mutex_t *);
+void initialize_shared_errorcheck_mutex (caf_shmem_mutex *);
-void initialize_shared_condition (pthread_cond_t *);
+void initialize_shared_condition (caf_shmem_condvar *, const int size);
#endif