# HG changeset patch
# Parent a3a10b48d3dd47ace5cb20ba4d2d809dc3713234
Implement basic thread-safe I/O infrastructure.

diff --git a/mingwrt/mingwex/xfd.h b/mingwrt/mingwex/xfd.h
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfd.h
@@ -0,0 +1,203 @@
+/*
+ * xfd.h
+ *
+ * Private header file; it defines the macros, structures and inline
+ * functions, and declares the prototypes for all public API functions,
+ * as required to implement the MinGW.org Thread Safe I/O subsystem.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <windows.h>
+#include <sys/types.h>
+
+#if 0
+#define INIT_XFD_SLOTS  32
+#define GROW_XFD_SLOTS  16
+#endif
+
+#ifdef EBUG
+/* When compiled with the -DEBUG option, define the __mingw_dprintf() macro
+ * to emit a specified message on stderr, (using the fprintf() function, but
+ * emulating printf() semantics;  this requires inclusion of <stdio.h>, for
+ * the fprintf() function prototype).
+ */
+#include <stdio.h>
+#define __mingw_dprintf(...)  fprintf( stderr, __VA_ARGS__ )
+#else
+/* Not compiling with -DEBUG; define __mingw_dprintf() as a NOP macro;
+ * (usage should still be in terms of printf() semantics).
+ */
+#define __mingw_dprintf(...)
+#endif
+
+struct xfd
+{ /* Structure of a MinGW.org extended file descriptor; each descriptor
+   * may be associated with multiple indices, (via the dup() API), the
+   * number of which are recorded in "ref_count"; the "mutex" field is
+   * implemented as a CRITICAL_SECTION, which may be used to facilitate
+   * restricted access to the associated data stream, such that only one
+   * thread is permitted to access it at any one time.
+   */
+  int			 ref_count;
+  CRITICAL_SECTION	 mutex;
+};
+
+struct xfdtab
+{ /* Extended file descriptors are stored in a dynamically allocated
+   * array, (mapped in parallel with the CRT's file descriptor table).
+   * It is initially allocated, with a small initial size, only when it
+   * is first required; subsequently, it may be expanded as may become
+   * necessary, (but will never shrink).  The "slots" field represents
+   * the current number of available entries, each of which is either
+   * NULL, or a pointer to an extended file descriptor structure.
+   */
+  int			 slots;
+  struct xfd		*entries[/*INIT_XFD_SLOTS*/];
+};
+
+_BEGIN_C_DECLS
+
+/* Only one extended file descriptor table is required; it is always
+ * accessed via this global pointer, (which itself, is initialized to
+ * NULL, pending dynamic allocation of the descriptor table).
+ */
+extern struct xfdtab *__mingw_xfdtab;
+
+#define XFD_EXTERN  extern __cdecl __MINGW_NOTHROW
+#define XFD_INLINE  static __inline__ __attribute__((__always_inline__))
+
+/* The read() and write() functions, (and similarly pread() and pwrite()
+ * functions), are semantically congruent; the following macros facilitate
+ * use of generalized templates to generate each of these congruent pairs
+ * of object modules from common source files.
+ */
+#define __mingw_xfd_expand(FUNCTION,SUFFIX) FUNCTION##SUFFIX
+#define __mingw_xfd(FUNCTION) __mingw_xfd_expand(__mingw_xfd_,FUNCTION)
+#define __mingw_xfd_callout(FUNCTION) __mingw_xfd_expand(_,FUNCTION)
+#define __buf_t(FUNCTION) __mingw_xfd_expand(FUNCTION,_buf_t)
+
+XFD_EXTERN  struct xfd *__mingw_xfdtab_new_entry (void);
+XFD_EXTERN  struct xfd *__mingw_xfdtab_map_entry (int, struct xfd *);
+
+#ifdef EBADF
+/* This serves as witness that <errno.h> has been included; provide this
+ * inline helper to facilitate errno assignment, on return from functions
+ * which terminate abnormally.
+ */
+XFD_INLINE intptr_t __mingw_xfd_error( int errcode, intptr_t retval )
+{ errno = errcode; return retval; }
+#endif
+
+XFD_INLINE int __mingw_xfd_mappable( int fd )
+{
+  /* Helper to determine if the specified "fd" is mappable, within the
+   * current extent (if any) of the extended file descriptor table.
+   */
+  return (__mingw_xfdtab != NULL) && (__mingw_xfdtab->slots >= fd);
+}
+
+XFD_INLINE struct xfd *__mingw_xfd_mapped_entry( int fd )
+{
+  /* Helper to retrieve the extended file descriptor associated with "fd"
+   * from the extended descriptor table, returning NULL if "fd" has never
+   * been mapped to any extended file descriptor.
+   */
+  return __mingw_xfd_mappable( fd ) ? __mingw_xfdtab->entries[fd] : NULL;
+}
+
+XFD_INLINE void __mingw_xfd_acquire_mutex( struct xfd *entry )
+{
+  /* Helper to acquire exclusive ownership of the "mutex" associated
+   * with an extended file descriptor; nominally to be expanded inline,
+   * as a single call to EnterCriticalSection(), (or other alternative
+   * implementation of the "mutex" acquisition mechanism), we wrap it
+   * in __mingw_dprintf() calls to facilitate debugging.
+   */
+  __mingw_dprintf( "acquire mutex @ %#p ... ", &entry->mutex );
+  EnterCriticalSection( &entry->mutex );
+  __mingw_dprintf( "okay.\n" );
+}
+
+XFD_INLINE void __mingw_xfd_release_mutex( struct xfd *entry )
+{
+  /* Helper to relinquish ownership of the "mutex" associated with an
+   * extended file descriptor; nominally to be expanded inline, as one
+   * single call to LeaveCriticalSection(), (or other alternative, as
+   * appropriate for the "mutex" implementation), once again, we wrap
+   * it in __mingw_dprintf() calls to facilitate debugging.
+   */
+  __mingw_dprintf( "release mutex @ %#p ... ", &entry->mutex );
+  LeaveCriticalSection( &entry->mutex );
+  __mingw_dprintf( "done.\n" );
+}
+
+XFD_INLINE void __mingw_xfd_create_mutex( struct xfd *entry )
+{
+  /* Helper to create (initialize) the "mutex", which is associated
+   * with the passed extended file descriptor, and immediately seek
+   * to acquire ownership thereof.
+   */
+  __mingw_dprintf( "create mutex @ %#p\n", &entry->mutex );
+  InitializeCriticalSection( &entry->mutex );
+  __mingw_xfd_acquire_mutex( entry );
+}
+
+XFD_INLINE void __mingw_xfd_destroy_mutex( struct xfd *entry )
+{
+  /* Helper to reclaim the system resources associated with a defunct
+   * extended file descriptor "mutex"; we should call this before the
+   * memory allocated for the extended file descriptor is returned to
+   * the free heap pool.
+   */
+  __mingw_dprintf( "destroy mutex @ %#p ... ", &entry->mutex );
+  DeleteCriticalSection( &entry->mutex );
+  __mingw_dprintf( "okay\n" );
+}
+
+/* Provide prototypes for those functions which implement the public
+ * API; (these are primarily to circumvent any "-Wmissing-prototype"
+ * warnings, which GCC may emit during implementation build).
+ */
+XFD_EXTERN  int __mingw_xfd_dup (int);
+XFD_EXTERN  int __mingw_xfd_dup2 (int, int);
+XFD_EXTERN  int __mingw_xfd_fcntl (int, int, ...);
+XFD_EXTERN  int __mingw_xfd_creat (const char *, int);
+XFD_EXTERN  int __mingw_xfd_open (const char *, int, ...);
+XFD_EXTERN  ssize_t __mingw_xfd_read (int, void *, size_t);
+XFD_EXTERN  ssize_t __mingw_xfd_pread (int, void *, size_t, __off64_t);
+XFD_EXTERN  ssize_t __mingw_xfd_pwrite (int, const void *, size_t, __off64_t);
+XFD_EXTERN  ssize_t __mingw_xfd_write (int, const void *, size_t);
+XFD_EXTERN  __off64_t __mingw_xfd_lseek (int, __off64_t, int);
+XFD_EXTERN  int __mingw_xfd_close (int);
+
+/* Define action codes, for use with the __mingw_xfd_fcntl() function.
+ */
+enum { XFD_GETFD, XFD_SETFD };
+
+_END_C_DECLS
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdclose.c b/mingwrt/mingwex/xfdclose.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdclose.c
@@ -0,0 +1,109 @@
+/*
+ * xfdclose.c
+ *
+ * Implementation of MinGW.org thread safe wrapper for close() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* The following private header file defines the extended file descriptor
+ * infrastructure, and associated function prototypes, which are required
+ * by the thread safe I/O option...
+ */
+#include "xfd.h"
+
+/* ...while these system headers provide the function prototype for the
+ * underlying close() function, and the free() function which is used to
+ * return memory, occupied by any defunct extended file descriptor, to
+ * the free heap pool.
+ */
+#include <unistd.h>
+#include <stdlib.h>
+
+ssize_t __mingw_xfd_close( int fd )
+{
+  /* Close the file descriptor "fd", subject to acquisition of any
+   * associated mutex, (specified within the extended "fd" descriptor);
+   * if no such extended descriptor is present...
+   */
+  struct xfd *xfd_entry; int status;
+  if( __mingw_xfd_mapped_entry( fd ) == NULL )
+    /*
+     * ...simply fall back to performing a regular close() on "fd".
+     */
+    return _close( fd );
+
+  /* When an extended descriptor is present, block the calling thread
+   * until the associated mutex has been acquired...
+   */
+  __mingw_xfd_acquire_mutex( xfd_entry = __mingw_xfdtab->entries[fd] );
+  /*
+   * ...before performing the close() call, saving its return value
+   * for eventual return to the caller, after cleaning up the memory
+   * state of the associated extended file descriptor.
+   */
+  if( (status = _close( fd )) == 0 )
+  {
+    /* After successfully closing the file descriptor, and before we
+     * relinquish our ownership of the associated mutex, we must mark
+     * its extended file descriptor table entry as unused...
+     */
+    __mingw_xfdtab->entries[fd] = NULL;
+    /*
+     * ...and check if any other extended descriptor refers to the same
+     * underlying data stream...
+     */
+    if( --xfd_entry->ref_count > 0 )
+      /*
+       * ...in which case, we simply relinquish ownership of the mutex,
+       * but leave the duplicate descriptor in place, otherwise...
+       */
+      __mingw_xfd_release_mutex( xfd_entry );
+
+    else
+    { /* ...when this was the last (or only) extended descriptor which
+       * was associated with the underlying data stream, we may delete
+       * the mutex, and release the memory used by the extended file
+       * descriptor, which has now become defunct.
+       */
+      __mingw_xfd_destroy_mutex( xfd_entry );
+      free( xfd_entry );
+    }
+  }
+  else
+    /* The close() call was unsuccessful; simply relinquish ownership
+     * of the associated mutex, taking no further action...
+     */
+    __mingw_xfd_release_mutex( xfd_entry );
+
+  /* ...and ultimately, return the status of the close() request.
+   */
+  return status;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdcntl.c b/mingwrt/mingwex/xfdcntl.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdcntl.c
@@ -0,0 +1,153 @@
+/*
+ * xfdcntl.c
+ *
+ * Extended file descriptor management API for MinGW thread-safe I/O.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* These system headers must be included...
+ */
+#include <errno.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+/* ...BEFORE this implementation private header, otherwise some of
+ * the required private definitions may not be exposed.
+ */
+#include "xfd.h"
+
+XFD_INLINE struct xfd *__mingw_xfdtab_error( int errcode )
+{
+  /* Provides an alternative to the __mingw_xfd_error() function, which
+   * may be used to set errno, when the requisite return value is a NULL
+   * pointer to an extended file descriptor, rather than an integer.
+   */
+  errno = errcode; return (struct xfd *)(NULL);
+}
+
+XFD_INLINE struct xfd *__mingw_xfd_getfd( int fd )
+{
+  /* Helper function to validate the specified file descriptor, and
+   * to acquire a thread safe lock on it, returning an extended file
+   * descriptor for subsequent access to the lock.
+   */
+  struct xfd *xfd_entry, *xfd_mapped;
+
+  /* First, ensure that the descriptor in non-negative, as any valid
+   * file descriptor must be.
+   */
+  if( fd < 0 ) return __mingw_xfdtab_error( EBADF );
+
+  /* When an extended file descriptor has already been mapped to the
+   * original file descriptor...
+   */
+  if( (xfd_entry = xfd_mapped = __mingw_xfd_mapped_entry( fd )) != NULL )
+  {
+    /* ...then we may simply request a lock on it...
+     */
+    __mingw_xfd_acquire_mutex( xfd_entry );
+  }
+  /* ...otherwise, we attempt to map an extended file descriptor now...
+   */
+  else if( (xfd_entry = __mingw_xfdtab_new_entry()) == NULL )
+  {
+    /* ...bailing out, if unsuccessful.
+     */
+    return __mingw_xfdtab_error( ENOMEM );
+  }
+
+  if( (xfd_mapped == NULL)
+  &&  (__mingw_xfdtab_map_entry( fd, xfd_entry ) != xfd_entry)  )
+  {
+    /* An extended file descriptor lock was successfully acquired, but
+     * mapping to the original file descriptor failed; discard the lock,
+     * and bail out.
+     */
+    __mingw_xfd_destroy_mutex( xfd_entry );
+    return NULL;
+  }
+
+  /* An extended file descriptor lock has been successfully acquired,
+   * and mapped to the original file descriptor; return it.
+   */
+  return xfd_entry;
+}
+
+XFD_INLINE int __mingw_xfd_setfd( int fd, struct xfd *entry )
+{
+  /* Helper to complete the mapping of an extended file descriptor,
+   * ensuring that it is appropriately associated with the specified
+   * basic CRT file descriptor...
+   */
+  if( __mingw_xfdtab_map_entry( fd, entry ) != entry )
+  {
+    /* ...but relinquishing the basic descriptor, and bailing out, in
+     * the event that the mapping is unsuccessful...
+     */
+    _close( fd );
+    return -1;
+  }
+  /* ...or returning the specified file descriptor, when successful.
+   */
+  return fd;
+}
+
+int __mingw_xfd_fcntl( int fd, int action, ... )
+{
+  /* Single public entry point, for access to the extended (thread-safe)
+   * file descriptor management API.
+   */
+  int status = -1;
+  va_list argv; va_start( argv, action );
+
+  switch( action )
+  {
+    case XFD_GETFD:
+      /* Update "argv" (a pointer) to retrieve the extended file descriptor
+       * which is associated with "fd", allocating one if necessary; return
+       * the "invalid fd" status, if no extended descriptor retrieved.
+       */
+      if( (*va_arg( argv, struct xfd **) = __mingw_xfd_getfd( fd )) != NULL )
+	status = fd;
+      break;
+
+    case XFD_SETFD:
+      /* Associate the extended file descriptor represented by "argv" with
+       * the basic file descriptor "fd", (which may be a duplicate); close
+       * the I/O stream associated with "fd", and return the "invalid fd"
+       * status code, on failure to complete the association.
+       */
+      status = __mingw_xfd_setfd( fd, va_arg( argv, struct xfd * ));
+  }
+
+  va_end( argv );
+  return status;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdcreat.c b/mingwrt/mingwex/xfdcreat.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdcreat.c
@@ -0,0 +1,52 @@
+/*
+ * xfdcreat.c
+ *
+ * Implementation of MinGW.org thread-safe creat() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <fcntl.h>
+
+/* creat() is nominally a trivial derivative of the open() function; declare
+ * appropriate thread-safe function prototypes locally, to minimize pollution
+ * from <windows.h>, (which would be included by "xfd.h").
+ */
+extern __cdecl __MINGW_NOTHROW  int __mingw_xfd_creat (const char *, int);
+extern __cdecl __MINGW_NOTHROW  int __mingw_xfd_open (const char *, int, ...);
+
+/* Although sufficiently trivial to suggest an inline implementation, such a
+ * creat() implementation would force inclusion of <fcntl.h> by <io.h>; this
+ * is undesirable, so we provide this external implementation instead...
+ */
+int __mingw_xfd_creat( const char *name, int pmode )
+{
+  /* ...simply invoking the thread-safe open(), with appropriate mode flags.
+   */
+  return __mingw_xfd_open( name, O_CREAT | O_WRONLY | O_TRUNC, pmode );
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfddup.c b/mingwrt/mingwex/xfddup.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfddup.c
@@ -0,0 +1,82 @@
+/*
+ * xfddup.c
+ *
+ * MinGW thread safe wrapper for the CRT dup() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* By including this private header early, we selectively exclude some of
+ * its content, which we do not require, before...
+ */
+#include "xfd.h"
+
+/* ...we include this system header, to declare the low level I/O API.
+ */
+#include <unistd.h>
+
+int __mingw_xfd_dup( int fd )
+{
+  /* Obtain a duplicate file descriptor for an existing I/O data stream.
+   * If an extented descriptor, to support thread-safe asynchronous access,
+   * is already associated with the original file descriptor, on return it
+   * will become associated with both the original and the duplicate file
+   * descriptors; if no such original extended file descriptor exists, a
+   * new one will be allocated, and similarly associated with both the
+   * original and the duplicate file descriptors.
+   */
+  int newfd; struct xfd *xfd_entry;
+  if( __mingw_xfd_fcntl( fd, XFD_GETFD, &xfd_entry ) < 0 )
+    /*
+     * On failure to establish an extended descriptor association for
+     * the original file descriptor, we decline to proceed, and return
+     * an "invalid fd" status; errno will have been set by the XFD_GETFD
+     * request, to indicate the cause of failure.
+     */
+    return -1;
+
+  /* If we get to here, we have successfully established an extended
+   * descriptor association for the original file descriptor, for which
+   * we have also acquired a lock; we may proceed to request a duplicate
+   * file descriptor, and...
+   */
+  if( (newfd = _dup( fd )) >= 0 )
+    /*
+     * ...when successful, we also associate the same original extended
+     * descriptor with it.
+     */
+    newfd = __mingw_xfd_fcntl( newfd, XFD_SETFD, xfd_entry );
+
+  /* In any event, we must release the original extended descriptor lock,
+   * before we return the acquired duplicate file descriptor itself.
+   */
+  __mingw_xfd_release_mutex( xfd_entry );
+  return newfd;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfddup2.c b/mingwrt/mingwex/xfddup2.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfddup2.c
@@ -0,0 +1,140 @@
+/*
+ * xfddup2.c
+ *
+ * MinGW thread safe wrapper for the CRT dup2() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* By including this private header early, we selectively exclude some of
+ * its content, which we do not require, before...
+ */
+#include "xfd.h"
+
+/* ...we include this system header, to declare the low level I/O API.
+ */
+#include <unistd.h>
+
+/* GCC's optimizer may go crazy with this code; keep it sane, by forcing
+ * optimization for minimum size.
+ */
+#pragma GCC optimize("Os")
+int __mingw_xfd_dup2( int fd, int newfd )
+{
+  /* Force file descriptor "newfd" to refer to the same data stream as "fd",
+   * with provision for thread-safe asynchronous access.  Although based on
+   * an original POSIX function, Microsoft's implementation does NOT comply
+   * with POSIX semantics; this implementation mimics Microsoft's, returning
+   * zero on success, (whereas POSIX mandates returning "newfd"); otherwise,
+   * return -1 on failure, which is consistent with both Microsoft's actual
+   * and POSIX mandatory behaviour.
+   */
+  struct xfd *xfd_entry;
+
+  /* Both "fd" and "newfd" must represent valid file descriptors; i.e. they
+   * must be non-negative integers, not exceeding the POSIX OPEN_MAX limit,
+   * (which Microsoft do not define).  Initially, reject any negative value,
+   * while acquiring an extended descriptor lock for "fd", (assigning one if
+   * necessary)...
+   */
+  if( __mingw_xfd_fcntl( (newfd < 0) ? newfd : fd, XFD_GETFD, &xfd_entry ) < 0 )
+    /*
+     * ...bailing out on failure.
+     */
+    return -1;
+
+  /* When we get to here, we have established and acquired a lock on
+   * "fd"; if "fd" and "newfd" are equal, our work is done...
+   */
+  if( newfd != fd )
+  {
+    /* ...otherwise, we must check for prior existence of any extended
+     * descriptor, which may already be associated with "newfd", and if
+     * such a descriptor does exist...
+     */
+    struct xfd *alt_xfd_entry;
+    if( (alt_xfd_entry = __mingw_xfd_mapped_entry( newfd )) != NULL )
+      /*
+       * ...we must also acquire a lock on it.
+       */
+      __mingw_xfd_acquire_mutex( alt_xfd_entry );
+
+    /* We may now safely call Microsoft's _dup2() function, to force
+     * association of "newfd" with the "fd" stream; we anticipate zero
+     * as return value, on success, but we will accept any non-negative
+     * value as equivalent, (to accommodate the POSIX stipulation that
+     * it should be "newfd"; FIXME: consider checking that non-zero
+     * does actually match "newfd").
+     */
+    if( _dup2( fd, newfd ) >= 0 )
+    {
+      /* Any prior stream association for "newfd" will now have been
+       * closed; if there was an extended descriptor associated with
+       * such a stream, we must decrement its reference count...
+       */
+      if( alt_xfd_entry != NULL )
+	--alt_xfd_entry->ref_count;
+
+      /* ...and instead, associate "newfd" with the extended descriptor
+       * which we already know to be associated with "fd", (increasing
+       * its reference count).
+       */
+      __mingw_xfd_fcntl( newfd, XFD_SETFD, xfd_entry );
+    }
+
+    /* When there was an extended descriptor previously associated with
+     * "newfd"...
+     */
+    if( alt_xfd_entry != NULL )
+    {
+      /* ...and there are other streams associated with it...
+       */
+      if( alt_xfd_entry->ref_count > 0 )
+	/*
+	 * ...then we may simply relinquish the lock we hold on it...
+	 */
+	__mingw_xfd_release_mutex( alt_xfd_entry );
+
+      else
+	/* ...but, when the reference count indicates that there are
+	 * no other stream associations for this descriptor, then we
+	 * may reclaim all resources allocated for it.
+	 */
+	__mingw_xfd_destroy_mutex( alt_xfd_entry );
+    }
+  }
+
+  /* Finally, we must release our lock on the extended descriptor for
+   * the original "fd" data stream, before returning zero, which thus
+   * imitates the Microsoft _dup2() behaviour.
+   */
+  __mingw_xfd_release_mutex( xfd_entry );
+  return 0;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdlseek.c b/mingwrt/mingwex/xfdlseek.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdlseek.c
@@ -0,0 +1,77 @@
+/*
+ * xfdlseek.c
+ *
+ * Implementation of MinGW.org thread safe wrapper for lseek() function,
+ * suitable for use with both 32-bit and 64-bit file offsets.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* The following private header file defines the extended file descriptor
+ * infrastructure, and associated function prototypes, which are required
+ * by the thread safe I/O option...
+ */
+#include "xfd.h"
+
+/* ...while this system header provides the function prototype for the
+ * underlying read() function API; note that we refer to this using its
+ * Microsoft "uglified" name, to avoid recursively calling the standard
+ * name, which we may have remapped to this thread-safe implementation.
+ */
+#include <unistd.h>
+
+off64_t __mingw_xfd_lseek( int fd, off64_t offset, int whence )
+{
+  /* Reposition the file associated with descriptor "fd" to specified
+   * offset, subject to acquisition of any associated mutex, (specified
+   * within the extended "fd" descriptor); if no extended descriptor is
+   * present...
+   */
+  off64_t thence;
+  if( __mingw_xfd_mapped_entry( fd ) == NULL )
+    /*
+     * ...fall back to performing a regular 64-bit lseek() on "fd".
+     */
+    return _lseeki64( fd, offset, whence );
+
+  /* When an extended descriptor is present, block the calling thread
+   * until the associated mutex has been acquired...
+   */
+  __mingw_xfd_acquire_mutex( __mingw_xfdtab->entries[fd] );
+  /*
+   * ...before performing the lseek() call, saving its return value...
+   */
+  thence = _lseeki64( fd, offset, whence );
+  /*
+   * ...for deferred return, only after releasing the mutex.
+   */
+  __mingw_xfd_release_mutex( __mingw_xfdtab->entries[fd] );
+  return thence;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdopen.c b/mingwrt/mingwex/xfdopen.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdopen.c
@@ -0,0 +1,108 @@
+/*
+ * xfdopen.c
+ *
+ * Implementation of MinGW.org thread-safe open() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* The following system headers must be included before...
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+/* ...this private header, to ensure that all appropriate declarations
+ * will be exposed.
+ */
+#include "xfd.h"
+
+int __mingw_xfd_open( const char *name, int mode, ... )
+{
+  /* Open a data stream for thread-safe I/O; this requires an extended
+   * file descriptor to be allocated, and it must subsequently be bound
+   * to the regular file descriptor, as returned by the system open()
+   * function, but...
+   */
+  struct xfd *xfd_entry;
+  if( (xfd_entry = __mingw_xfdtab_new_entry()) == NULL )
+    /*
+     * ...when allocation of an extended file descriptor fails, then we
+     * choose not to proceed, but to set errno and bail out.
+     */
+    return __mingw_xfd_error( ENOMEM, -1 );
+
+  else
+  { /* Allocation of an extended file descriptor was successful, and we
+     * have been granted ownership of its associated mutex; we may now
+     * proceed to open a system file descriptor with which to associate
+     * it, noting that...
+     */
+    int fd, pmode = 0;
+    if( (mode & O_CREAT) == O_CREAT )
+    {
+      /* ...when the open() mode flags include O_CREAT, a third argument
+       * becomes mandatory, to specify the permissions which will be set
+       * for any new directory entry which may be created.
+       */
+      va_list argv;
+      va_start( argv, mode );
+      pmode = va_arg( argv, int );
+      va_end( argv );
+    }
+
+    /* We may now invoke the system open() function, and, provided this
+     * is successful, bind our extended file descriptor to the system
+     * file descriptor thus obtained.
+     */
+    if(  ((fd = _open( name, mode, pmode )) >= 0)
+    &&  (__mingw_xfdtab_map_entry( fd, xfd_entry ) == xfd_entry)  )
+      /*
+       * When this has been completed successfully, we may relinquish
+       * ownership of the extended file descriptor's mutex, and we are
+       * done...
+       */
+      __mingw_xfd_release_mutex( xfd_entry );
+
+    else
+    { /* ...but when the system open() call fails, we have no further
+       * use for the extended file descriptor -- we have nothing with
+       * which to associate it -- so we may destroy the mutex, and
+       * restore the allocated memory to the free heap pool.
+       */
+      __mingw_xfd_destroy_mutex( xfd_entry );
+      free( xfd_entry );
+    }
+    /* In either case, we return whatever file descriptor, or status
+     * code, which we obtained from the system open() call.
+     */
+    return fd;
+  }
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdpread.c b/mingwrt/mingwex/xfdpread.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdpread.c
@@ -0,0 +1,131 @@
+/*
+ * xfdpread.c
+ *
+ * Generic template implementing pread() and pwrite() functions, conforming
+ * (approximately) to POSIX.1-2008, (and the earlier POSIX Extended Systems
+ * Interface v5), specifications; this is dependent on the MinGW.org Thread
+ * Safe I/O extensions.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * This module must be compiled twice, to generate separate object modules
+ * for each of the pread() and pwrite() functions, e.g.:
+ *
+ *   gcc -c -D FUNCTION=pread -o xfdpread.o xfdpread.c
+ *   gcc -c -D FUNCTION=pwrite -o xfdpwrite.o xfdpread.c
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* These system headers provide the function prototype for the underlying
+ * _read() and _write() functions, and error reporting APIs; (note that we
+ * refer to these by their Microsoft "uglified" names, to avoid recursively
+ * calling the thread-safe wrappers, which we may have mapped so that they
+ * may be invoked by calling the standard POSIX function names).
+ */
+#include <unistd.h>
+#include <errno.h>
+
+/* The following private header file defines the extended file descriptor
+ * infrastructure, and associated function prototypes, which are required
+ * by the thread safe I/O option.
+ */
+#include "xfd.h"
+
+#ifndef FUNCTION
+/* If the user neglected to specify the "-D FUNCTION=..." selection, assume
+ * that the intent is to compile as the pread() function implementation.
+ */
+#define FUNCTION      pread
+#endif
+#define pread_buf_t   void
+#define pwrite_buf_t  const void
+
+/* Default __mingw_xfd_callouts for pread() and pwrite() would map to
+ * _pread() and _pwrite() respectively; since MSVCRT.DLL doesn't provide
+ * these, (and we want _read() and _write() anyway), redefine the mapped
+ * callback names accordingly.
+ */
+#define _pread       _read
+#define _pwrite      _write
+
+ssize_t __mingw_xfd(FUNCTION)
+(int fd, __buf_t(FUNCTION) *buf, size_t count, __off64_t offset )
+{
+  /* Read data from the file associated with descriptor "fd", subject to
+   * acquisition of any associated mutex, (specified within the extended
+   * "fd" descriptor); if no such extended descriptor is present...
+   */
+  __off64_t saved_file_position; ssize_t retval = -1;
+  if( __mingw_xfd_mapped_entry( fd ) == NULL )
+    /*
+     * ...then this call is unsupported, so bail out immediately, while
+     * reporting an invalid file descriptor.
+     */
+    return (ssize_t)(__mingw_xfd_error( EBADF, -1 ));
+
+  /* When an extended descriptor is present, block the calling thread
+   * until the associated mutex has been acquired.
+   */
+  __mingw_xfd_acquire_mutex( __mingw_xfdtab->entries[fd] );
+
+  /* POSIX.1 stipulates that pread() should read from a specified file
+   * offset, but without changing the file position associated with "fd";
+   * unfortunately, Windows doesn't readily support any such capability,
+   * so we must emulate it by saving the current file position...
+   */
+  saved_file_position = _lseeki64( fd, (__off64_t)(0), SEEK_CUR );
+  /*
+   * ...then moving to the position whence the data is to be read.
+   */
+  if( _lseeki64( fd, offset, SEEK_SET ) == offset )
+    /*
+     * Only if we successfully changed the file position to the correct
+     * offset, as specified, do we proceed to read the data, saving the
+     * return value for subsequent return to the caller.
+     */
+    retval = __mingw_xfd_callout(FUNCTION)( fd, buf, count );
+
+  else
+    /* The file position was NOT successfully changed to the specified
+     * offset; it is likely that the file descriptor refers to a data
+     * stream which is non-seekable, (e.g. a pipe), so we set errno to
+     * reflect this, leaving the return value as initially set to -1,
+     * which is the appropriate POSIX.1 indication of failure.
+     */
+    errno = ESPIPE;
+
+  /* Finally, restore the saved file position, (thus completing the
+   * emulation of a read with no change of file position), before we
+   * release the mutex, and return the previously deferred result.
+   */
+  _lseeki64( fd, saved_file_position, SEEK_SET );
+  __mingw_xfd_release_mutex( __mingw_xfdtab->entries[fd] );
+  return retval;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdread.c b/mingwrt/mingwex/xfdread.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdread.c
@@ -0,0 +1,92 @@
+/*
+ * xfdread.c
+ *
+ * Generic template implementing the MinGW.org thread-safe I/O wrappers
+ * for each of the read() and write() functions.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * This module must be compiled twice, to generate separate object modules
+ * for each of the read() and write() function wrappers, e.g.:
+ *
+ *   gcc -c -D FUNCTION=read -o xfdread.o xfdread.c
+ *   gcc -c -D FUNCTION=write -o xfdwrite.o xfdread.c
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* The following private header file defines the extended file descriptor
+ * infrastructure, and associated function prototypes, which are required
+ * by the thread safe I/O option...
+ */
+#include "xfd.h"
+
+/* ...while this system header provides the function prototypes for the
+ * underlying _read() and _write() functions; note that we refer to these
+ * using their Microsoft "uglified" names, to avoid recursively calling
+ * the thread-safe wrappers, which we may have mapped so that they may
+ * be invoked by calling the standard POSIX function names).
+ */
+#include <unistd.h>
+
+#ifndef FUNCTION
+/* If the user neglected to specify the "-D FUNCTION=..." selection,
+ * assume that the intent is to compile the read() function wrapper.
+ */
+#define FUNCTION     read
+#endif
+#define read_buf_t   void
+#define write_buf_t  const void
+
+ssize_t __mingw_xfd(FUNCTION) (int fd, __buf_t(FUNCTION) *buf, size_t count)
+{
+  /* Read data from the file associated with descriptor "fd", subject to
+   * acquisition of any associated mutex, (specified within the extended
+   * "fd" descriptor); if no such extended descriptor is present...
+   */
+  if( __mingw_xfd_mapped_entry( fd ) == NULL )
+    /*
+     * ...fall back to performing a regular read()/write() on "fd".
+     */
+    return __mingw_xfd_callout(FUNCTION)( fd, buf, count );
+
+  /* When an extended descriptor is present, block the calling thread
+   * until the associated mutex has been acquired...
+   */
+  __mingw_xfd_acquire_mutex( __mingw_xfdtab->entries[fd] );
+  /*
+   * ...before performing the read() call, saving its return value...
+   */
+  count = (size_t)(__mingw_xfd_callout(FUNCTION)( fd, buf, count ));
+  /*
+   * ...for deferred return, only after releasing the mutex.
+   */
+  __mingw_xfd_release_mutex( __mingw_xfdtab->entries[fd] );
+  return (ssize_t)(count);
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdtab.c b/mingwrt/mingwex/xfdtab.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdtab.c
@@ -0,0 +1,122 @@
+/*
+ * xfdtab.c
+ *
+ * Implementation of the extended file descriptor table, which provides
+ * support infrastructure for the MinGW.org thread safe I/O extension.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+
+/* Helper functions for management of the extended file descriptor table,
+ * and its entries, require declarations from these system headers:
+ */
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* The necessary structure definitions, for the extended file descriptor
+ * table, and its respective entries, are provided in this header file,
+ * (which is considered to be private to the implementation):
+ */
+#include "xfd.h"
+
+/* Initially, the extended file descriptor table is unallocated; it will
+ * be created as, and when, it becomes necessary.
+ */
+struct xfdtab *__mingw_xfdtab = NULL;
+
+struct xfd *__mingw_xfdtab_new_entry( void )
+{
+  /* Helper to allocate heap memory for a new extended file descriptor,
+   * and prepare it for insertion into the extended descriptor table.
+   */
+  struct xfd *xfd_entry;
+  if( (xfd_entry = malloc( sizeof( struct xfd ) )) != NULL )
+  {
+    /* When memory has been sucessfully allocated, we may initialize,
+     * and acquire ownership of, the mutex associated with the newly
+     * created extended file descriptor, and...
+     */
+    __mingw_xfd_create_mutex( xfd_entry );
+    /*
+     * ...initialize its reference count to zero, prior to assignment
+     * of its first reference within the extended descriptor table.
+     */
+    xfd_entry->ref_count = 0;
+  }
+  return xfd_entry;
+}
+
+struct xfd *__mingw_xfdtab_map_entry( int fd, struct xfd *xfd_entry )
+{
+  /* Helper to insert an extended file descriptor reference into the
+   * extended file descriptor table.
+   */
+  if( !__mingw_xfd_mappable( fd ) )
+  {
+    /* The required insertion point for the intended reference does
+     * not (yet) lie within the current extent of the extended file
+     * descriptor table; compute a new table size, in increments of
+     * sixteen entries, sufficient to accommodate it.
+     */
+    struct xfdtab *new_xfdtab = __mingw_xfdtab;
+    int fd_base = (new_xfdtab == NULL) ? 0 : new_xfdtab->slots;
+    int fd_extent = 1 + (fd | 0xF);
+
+    /* Attempt to expand the descriptor table to this new size...
+     */
+    struct extent { int slots; struct xfd *entries[fd_extent]; };
+    if( (new_xfdtab = realloc(new_xfdtab, sizeof( struct extent ) )) == NULL )
+      /*
+       * ...bailing out if sufficient memory cannot be allocated.
+       */
+      return (struct xfd *)(__mingw_xfd_error( ENOMEM, (intptr_t)(NULL) ));
+
+    /* If we get to here, the extended descriptor table has been
+     * successfully expanded; initialize each of its newly added
+     * file descriptor reference slots (as unassigned)...
+     */
+    while( fd_base < (new_xfdtab->slots = fd_extent) )
+      new_xfdtab->entries[fd_base++] = NULL;
+
+    /* ...and update the global reference pointer.
+     */
+    __mingw_xfdtab = new_xfdtab;
+  }
+
+  /* Increment the reference count for the specified entry...
+   */
+  ++xfd_entry->ref_count;
+  /*
+   * ...for which we may now safely insert a reference into the
+   * extended file descriptor table, and return the entry.
+   */
+  return (__mingw_xfdtab->entries[fd] = xfd_entry);
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/xfdtemp.c b/mingwrt/mingwex/xfdtemp.c
new file mode 100644
--- /dev/null
+++ b/mingwrt/mingwex/xfdtemp.c
@@ -0,0 +1,90 @@
+/*
+ * xfdtemp.c
+ *
+ * Implementation of MinGW.org thread-safe mkstemp() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2017, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define _XOPEN_SOURCE 700
+#define WIN32_LEAN_AND_MEAN
+
+/* The following system headers must be included before...
+ */
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* ...this private header, to ensure that all appropriate declarations
+ * will be exposed.
+ */
+#include "xfd.h"
+
+int __mingw_xfd_mkstemp( char *name )
+{
+  /* Open a temporary file for exclusive thread-safe I/O; this requires
+   * an extended file descriptor to be allocated, and it must subsequently
+   * be bound to the regular file descriptor, as returned by the mkstemp()
+   * function, but...
+   */
+  int fd; struct xfd *xfd_entry;
+  if( (xfd_entry = __mingw_xfdtab_new_entry()) == NULL )
+    /*
+     * ...when allocation of an extended file descriptor fails, then we
+     * choose not to proceed, but to set errno and bail out.
+     */
+    return __mingw_xfd_error( ENOMEM, -1 );
+
+  /* Allocation of an extended file descriptor was successful, and we
+   * have been granted ownership of its associated mutex; we may now
+   * request a system file descriptor, for a nominally temporary file,
+   * with which to associate it.
+   */
+  if(  ((fd = __mingw_mkstemp( _MKSTEMP_INVOKE, name )) >= 0)
+  &&  (__mingw_xfdtab_map_entry( fd, xfd_entry ) == xfd_entry)  )
+    /*
+     * When this has been completed successfully, we may relinquish
+     * ownership of the extended file descriptor's mutex, and we are
+     * done...
+     */
+      __mingw_xfd_release_mutex( xfd_entry );
+
+  else
+  { /* ...but when the mkstemp() call fails, we have no further use
+     * for the extended file descriptor -- we have nothing with which
+     * to associate it -- so we may destroy the mutex, and restore the
+     * allocated memory to the free heap pool.
+     */
+    __mingw_xfd_destroy_mutex( xfd_entry );
+    free( xfd_entry );
+  }
+  /* In either case, we return whatever file descriptor, or status
+   * code, which we obtained from the mkstemp() call.
+   */
+  return fd;
+}
+
+/* $RCSfile$: end of file */
