[PATCH 8/13] Coarray shared memory library

Jerry D <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.fortran
Message-ID <[email protected]>
Dear all, as requested,

See attached patch 8 of 13

Best Regards,

Jerry
pr88076_v4_8.diff (text/x-patch, 52.1 KB)
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.