From 458820fa6e35ae77ce6159e0b95898a2a42d30db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?=
 <alexey.pawlow@gmail.com>
Date: Thu, 17 Jun 2021 18:51:12 +0530
Subject: [PATCH 002/N] build: add --with-nt-threads and make it default on
 mingw
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Naveen M K <naveen521kk@gmail.com>
Co-authored-by: Алексей <alexey.pawlow@gmail.com>
Co-authored-by: Christoph Reiter <reiter.christoph@gmail.com>
---
 Include/internal/pycore_condvar.h          |   4 +
 Include/internal/pycore_pythread.h         |   6 ++
 Include/pythread.h                         |   6 ++
 Modules/_multiprocessing/multiprocessing.h |   5 +-
 configure.ac                               | 102 ++++++++++++++++++++-
 pyconfig.h.in                              |   3 +
 6 files changed, 122 insertions(+), 4 deletions(-)

diff --git a/Include/internal/pycore_condvar.h b/Include/internal/pycore_condvar.h
index 55271f0..8b23568 100644
--- a/Include/internal/pycore_condvar.h
+++ b/Include/internal/pycore_condvar.h
@@ -35,6 +35,10 @@
 #  define WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>              // CRITICAL_SECTION
+/* winpthreads are involved via windows header, so need undef _POSIX_THREADS after header include */
+#if defined(_POSIX_THREADS)
+#undef _POSIX_THREADS
+#endif
 
 /* options */
 /* emulated condition variables are provided for those that want
diff --git a/Include/internal/pycore_pythread.h b/Include/internal/pycore_pythread.h
index 3610c62..a2b2e12 100644
--- a/Include/internal/pycore_pythread.h
+++ b/Include/internal/pycore_pythread.h
@@ -16,6 +16,12 @@ extern "C" {
                             && !defined(_POSIX_SEMAPHORES))
 #  include <unistd.h>             // _POSIX_THREADS, _POSIX_SEMAPHORES
 #endif
+#ifdef __MINGW32__
+# if !defined(HAVE_PTHREAD_H) || defined(NT_THREADS)
+#  undef _POSIX_THREADS
+# endif
+#endif
+
 #if (defined(HAVE_PTHREAD_H) && !defined(_POSIX_THREADS) \
                              && !defined(_POSIX_SEMAPHORES))
    // This means pthreads are not implemented in libc headers, hence the macro
diff --git a/Include/pythread.h b/Include/pythread.h
index a3216c5..9b4d2ae 100644
--- a/Include/pythread.h
+++ b/Include/pythread.h
@@ -7,6 +7,12 @@ typedef void *PyThread_type_lock;
 extern "C" {
 #endif
 
+#ifdef __MINGW32__
+# if !defined(HAVE_PTHREAD_H) || defined(NT_THREADS)
+#  undef _POSIX_THREADS
+# endif
+#endif
+
 /* Return status codes for Python lock acquisition.  Chosen for maximum
  * backwards compatibility, ie failure -> 0, success -> 1.  */
 typedef enum PyLockStatus {
diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h
index 099004b..a31443b 100644
--- a/Modules/_multiprocessing/multiprocessing.h
+++ b/Modules/_multiprocessing/multiprocessing.h
@@ -30,7 +30,10 @@
 #  endif
 #  define SEM_HANDLE HANDLE
 #  define SEM_VALUE_MAX LONG_MAX
-#  define HAVE_MP_SEMAPHORE
+#    define HAVE_MP_SEMAPHORE
+#  if defined(HAVE_SEM_OPEN) && defined(_POSIX_THREADS)
+#    include <semaphore.h>
+#  endif
 #else
 #  include <fcntl.h>                 /* O_CREAT and O_EXCL */
 #  if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
diff --git a/configure.ac b/configure.ac
index 597a44b..be9b319 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2832,6 +2832,53 @@ then
 	BASECFLAGS="$BASECFLAGS $ac_arch_flags"
 fi
 
+dnl NOTE:
+dnl - GCC 4.4+ for mingw* require and use posix threads(pthreads-w32)
+dnl - Host may contain installed pthreads-w32.
+dnl - On windows platform only NT-thread model is supported. 
+dnl To avoid miss detection scipt first will check for NT-thread model
+dnl and if is not found will try to detect build options for pthread
+dnl model. Autodetection could be overiden if variable with_nt_threads
+dnl is set in "Site Configuration" (see autoconf manual).
+dnl If NT-thread model is enabled script skips some checks that
+dnl impact build process. When a new functionality is added, developers
+dnl are responsible to update configure script to avoid thread models
+dnl to be mixed.
+
+AC_MSG_CHECKING([for --with-nt-threads])
+AC_ARG_WITH(nt-threads,
+            AS_HELP_STRING([--with-nt-threads], [build with windows threads (default is system-dependent)]),
+[
+	case $withval in
+	no)	with_nt_threads=no;;
+	yes)	with_nt_threads=yes;;
+	*)	with_nt_threads=yes;;
+	esac
+], [
+	case $host in
+		*-*-mingw*) with_nt_threads=yes;;
+		*) with_nt_threads=no;;
+	esac
+])
+AC_MSG_RESULT([$with_nt_threads])
+
+if test $with_nt_threads = yes ; then
+AC_MSG_CHECKING([whether linking with nt-threads work])
+AC_LINK_IFELSE([
+    AC_LANG_PROGRAM([[]],[[_beginthread(0, 0, 0);]])
+  ],
+  [AC_MSG_RESULT([yes])],
+  [AC_MSG_ERROR([failed to link with nt-threads])])
+fi
+
+if test $with_nt_threads = yes ; then
+  dnl temporary default flag to avoid additional pthread checks
+  dnl and initilize other ac..thread flags to no
+  ac_cv_pthread_is_default=no
+  ac_cv_kthread=no
+  ac_cv_pthread=no
+  dnl ac_cv_kpthread is set to no if default is yes (see below)
+else
 # On some compilers, pthreads are available without further options
 # (e.g. MacOS X). On some of these systems, the compiler will not
 # complain if unaccepted options are passed (e.g. gcc on Mac OS X).
@@ -2943,6 +2990,8 @@ int main(void){
 CC="$ac_save_cc"])
 fi
 
+fi
+
 # If we have set a CC compiler flag for thread support then
 # check if it works for CXX, too.
 if test ! -z "$CXX"
@@ -2962,6 +3011,10 @@ elif test "$ac_cv_pthread" = "yes"
 then
   CXX="$CXX -pthread"
   ac_cv_cxx_thread=yes
+elif test "$with_nt_threads" = "yes"
+then
+  dnl set to always to skip extra pthread check below
+  ac_cv_cxx_thread=always
 else
   ac_cv_cxx_thread=no
 fi
@@ -3003,8 +3056,8 @@ AC_CHECK_HEADERS([ \
   alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h fcntl.h grp.h \
   io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h linux/limits.h linux/memfd.h \
   linux/random.h linux/soundcard.h \
-  linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pthread.h pty.h \
-  sched.h setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \
+  linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h netpacket/packet.h poll.h process.h pty.h \
+  setjmp.h shadow.h signal.h spawn.h stropts.h sys/audioio.h sys/bsdtty.h sys/devpoll.h \
   sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h sys/kern_control.h \
   sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/pidfd.h sys/poll.h \
   sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \
@@ -3015,6 +3068,14 @@ AC_CHECK_HEADERS([ \
 AC_HEADER_DIRENT
 AC_HEADER_MAJOR
 
+# If using nt threads, don't look for pthread.h or thread.h
+if test "x$with_nt_threads" = xno ; then
+AC_HEADER_STDC
+AC_CHECK_HEADERS(pthread.h sched.h thread.h)
+AC_HEADER_DIRENT
+AC_HEADER_MAJOR
+fi
+
 # bluetooth/bluetooth.h has been known to not compile with -std=c99.
 # http://permalink.gmane.org/gmane.linux.bluez.kernel/22294
 SAVE_CFLAGS=$CFLAGS
@@ -3222,6 +3283,10 @@ elif test "$ac_cv_pthread" = "yes"
 then CC="$CC -pthread"
 fi
 
+if test $with_nt_threads = yes ; then
+  dnl skip check for pthread_t if NT-thread model is enabled
+  ac_cv_have_pthread_t=skip
+else
 AC_CACHE_CHECK([for pthread_t], [ac_cv_have_pthread_t], [
 AC_COMPILE_IFELSE([
   AC_LANG_PROGRAM([[@%:@include <pthread.h>]], [[pthread_t x; x = *(pthread_t*)0;]])
@@ -3253,7 +3318,7 @@ AS_VAR_IF([ac_cv_pthread_key_t_is_arithmetic_type], [yes], [
     AC_DEFINE([PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT], [1],
               [Define if pthread_key_t is compatible with int.])
 ])
-
+fi
 CC="$ac_save_cc"
 
 AC_MSG_CHECKING([for --enable-framework])
@@ -3881,10 +3946,15 @@ then
   fi
 fi
 
+if test $with_nt_threads = yes ; then
+  dnl do not search for sem_init if NT-thread model is enabled
+  :
+else
 # 'Real Time' functions on Solaris
 # posix4 on Solaris 2.6
 # pthread (first!) on Linux
 AC_SEARCH_LIBS([sem_init], [pthread rt posix4])
+fi
 
 # check if we need libintl for locale functions
 AC_CHECK_LIB([intl], [textdomain],
@@ -4619,6 +4689,11 @@ then
         CXX="$CXX -pthread"
     fi
     posix_threads=yes
+elif test $with_nt_threads = yes
+then
+    posix_threads=no
+    AC_DEFINE(NT_THREADS, 1,
+        [Define to 1 if you want to use native NT threads])
 else
     if test ! -z "$withval" -a -d "$withval"
     then LDFLAGS="$LDFLAGS -L$withval"
@@ -5215,6 +5290,15 @@ if test "$ac_sys_system" = "Linux-android"; then
 fi
 
 # checks for library functions
+if test $with_nt_threads = yes ; then
+  dnl GCC(mingw) 4.4+ require and use posix threads(pthreads-w32)
+  dnl and host may contain installed pthreads-w32.
+  dnl Skip checks for some functions declared in pthreads-w32 if
+  dnl NT-thread model is enabled.
+  ac_cv_func_pthread_kill=skip
+  ac_cv_func_sem_open=skip
+  ac_cv_func_sched_setscheduler=skip
+fi
 AC_CHECK_FUNCS([ \
   accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \
   copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \
@@ -6108,6 +6192,10 @@ dnl actually works.  For FreeBSD versions <= 7.2,
 dnl the kernel module that provides POSIX semaphores
 dnl isn't loaded by default, so an attempt to call
 dnl sem_open results in a 'Signal 12' error.
+if test $with_nt_threads = yes ; then
+  dnl skip posix semaphores test if NT-thread model is enabled
+  ac_cv_posix_semaphores_enabled=no
+fi
 AC_CACHE_CHECK([whether POSIX semaphores are enabled], [ac_cv_posix_semaphores_enabled],
   AC_RUN_IFELSE([
     AC_LANG_SOURCE([
@@ -6141,6 +6229,14 @@ AS_VAR_IF([ac_cv_posix_semaphores_enabled], [no], [
 ])
 
 dnl Multiprocessing check for broken sem_getvalue
+if test $with_nt_threads = yes ; then
+  dnl Skip test if NT-thread model is enabled.
+  dnl NOTE the test case below fail for pthreads-w32 as:
+  dnl - SEM_FAILED is not defined;
+  dnl - sem_open is a stub;
+  dnl - sem_getvalue work(!).
+  ac_cv_broken_sem_getvalue=skip
+fi
 AC_CACHE_CHECK([for broken sem_getvalue], [ac_cv_broken_sem_getvalue],
   AC_RUN_IFELSE([
     AC_LANG_SOURCE([
diff --git a/pyconfig.h.in b/pyconfig.h.in
index e18a642..60daba7 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -1633,6 +1633,9 @@
 /* Define if mvwdelch in curses.h is an expression. */
 #undef MVWDELCH_IS_EXPRESSION
 
+/* Define to 1 if you want to use native NT threads */
+#undef NT_THREADS
+
 /* Define to the address where bug reports for this package should be sent. */
 #undef PACKAGE_BUGREPORT
 
