mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-18 23:51:08 +08:00
Reimplement GNU threads library on native Windows
This reimplements the GNU threads library on native Windows (except for the Objective-C specific subset) using direct Win32 API calls, in lieu of the implementation based on semaphores. This base implementations requires Windows XP/Server 2003, which was the default minimal setting of MinGW-W64 until end of 2020. This also adds the support required for the C++11 threads, using again direct Win32 API calls; this additional layer requires Windows Vista/Server 2008 and is enabled only if _WIN32_WINNT >= 0x0600. This also changes libstdc++ to pass -D_WIN32_WINNT=0x0600 but only when the switch --enable-libstdcxx-threads is passed, which means that C++11 threads are still disabled by default *unless* MinGW-W64 itself is configured for Windows Vista/Server 2008 or later by default (this has been the case in the development version since end of 2020, for earlier versions you can configure it --with-default-win32-winnt=0x0600 to get the same effect). I only manually tested it on i686-w64-mingw32 and x86_64-w64-mingw32 but AdaCore has used it in their C/C++/Ada compilers for 3 years now and the 30_threads chapter of the libstdc++ testsuite was clean at the time. 2022-10-31 Eric Botcazou <ebotcazou@adacore.com> libgcc/ * config.host (i[34567]86-*-mingw*): Add thread fragment after EH one as well as new i386/t-slibgcc-mingw fragment. (x86_64-*-mingw*): Likewise. * config/i386/gthr-win32.h: If _WIN32_WINNT is at least 0x0600, define both __GTHREAD_HAS_COND and __GTHREADS_CXX0X to 1. Error out if _GTHREAD_USE_MUTEX_TIMEDLOCK is 1. Include stdlib.h instead of errno.h and do not include _mingw.h. (CONST_CAST2): Add specific definition for C++. (ATTRIBUTE_UNUSED): New macro. (__UNUSED_PARAM): Delete. Define WIN32_LEAN_AND_MEAN before including windows.h. (__gthread_objc_data_tls): Use TLS_OUT_OF_INDEXES instead of (DWORD)-1. (__gthread_objc_init_thread_system): Likewise. (__gthread_objc_thread_get_data): Minor tweak. (__gthread_objc_condition_allocate): Use ATTRIBUTE_UNUSED. (__gthread_objc_condition_deallocate): Likewise. (__gthread_objc_condition_wait): Likewise. (__gthread_objc_condition_broadcast): Likewise. (__gthread_objc_condition_signal): Likewise. Include sys/time.h. (__gthr_win32_DWORD): New typedef. (__gthr_win32_HANDLE): Likewise. (__gthr_win32_CRITICAL_SECTION): Likewise. (__gthr_win32_CONDITION_VARIABLE): Likewise. (__gthread_t): Adjust. (__gthread_key_t): Likewise. (__gthread_mutex_t): Likewise. (__gthread_recursive_mutex_t): Likewise. (__gthread_cond_t): New typedef. (__gthread_time_t): Likewise. (__GTHREAD_MUTEX_INIT_DEFAULT): Delete. (__GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT): Likewise. (__GTHREAD_COND_INIT_FUNCTION): Define. (__GTHREAD_TIME_INIT): Likewise. (__gthr_i486_lock_cmp_xchg): Delete. (__gthr_win32_create): Declare. (__gthr_win32_join): Likewise. (__gthr_win32_self): Likewise. (__gthr_win32_detach): Likewise. (__gthr_win32_equal): Likewise. (__gthr_win32_yield): Likewise. (__gthr_win32_mutex_destroy): Likewise. (__gthr_win32_cond_init_function): Likewise if __GTHREADS_HAS_COND is 1. (__gthr_win32_cond_broadcast): Likewise. (__gthr_win32_cond_signal): Likewise. (__gthr_win32_cond_wait): Likewise. (__gthr_win32_cond_timedwait): Likewise. (__gthr_win32_recursive_mutex_init_function): Delete. (__gthr_win32_recursive_mutex_lock): Likewise. (__gthr_win32_recursive_mutex_unlock): Likewise. (__gthr_win32_recursive_mutex_destroy): Likewise. (__gthread_create): New inline function. (__gthread_join): Likewise. (__gthread_self): Likewise. (__gthread_detach): Likewise. (__gthread_equal): Likewise. (__gthread_yield): Likewise. (__gthread_cond_init_function): Likewise if __GTHREADS_HAS_COND is 1. (__gthread_cond_broadcast): Likewise. (__gthread_cond_signal): Likewise. (__gthread_cond_wait): Likewise. (__gthread_cond_timedwait): Likewise. (__GTHREAD_WIN32_INLINE): New macro. (__GTHREAD_WIN32_COND_INLINE): Likewise. (__GTHREAD_WIN32_ACTIVE_P): Likewise. Define WIN32_LEAN_AND_MEAN before including windows.h. (__gthread_once): Minor tweaks. (__gthread_key_create): Use ATTRIBUTE_UNUSED and TLS_OUT_OF_INDEXES. (__gthread_key_delete): Minor tweak. (__gthread_getspecific): Likewise. (__gthread_setspecific): Likewise. (__gthread_mutex_init_function): Reimplement. (__gthread_mutex_destroy): Likewise. (__gthread_mutex_lock): Likewise. (__gthread_mutex_trylock): Likewise. (__gthread_mutex_unlock): Likewise. (__gthr_win32_abs_to_rel_time): Declare. (__gthread_recursive_mutex_init_function): Reimplement. (__gthread_recursive_mutex_destroy): Likewise. (__gthread_recursive_mutex_lock): Likewise. (__gthread_recursive_mutex_trylock): Likewise. (__gthread_recursive_mutex_unlock): Likewise. (__gthread_cond_destroy): New inline function. (__gthread_cond_wait_recursive): Likewise. * config/i386/gthr-win32.c: Delete everything. Include gthr-win32.h to get the out-of-line version of inline routines. Add compile-time checks for the local version of the Win32 types. * config/i386/gthr-win32-cond.c: New file. * config/i386/gthr-win32-thread.c: Likewise. * config/i386/t-gthr-win32: Add config/i386/gthr-win32-thread.c to the EH part, config/i386/gthr-win32-cond.c and config/i386/gthr-win32.c to the static version of libgcc. * config/i386/t-slibgcc-mingw: New file. * config/i386/libgcc-mingw.ver: Likewise. libstdc++-v3/ * acinclude.m4 (GLIBCXX_EXPORT_FLAGS): Substitute CPPFLAGS. (GLIBCXX_ENABLE_LIBSTDCXX_TIME): Set ac_has_sched_yield and ac_has_win32_sleep to yes for MinGW. Change HAVE_WIN32_SLEEP into _GLIBCXX_USE_WIN32_SLEEP. (GLIBCXX_CHECK_GTHREADS): Add _WIN32_THREADS to compilation flags for Win32 threads and force _GTHREAD_USE_MUTEX_TIMEDLOCK to 0 for them. Add -D_WIN32_WINNT=0x0600 to compilation flags if yes was configured and add it to CPPFLAGS on success. * config.h.in: Regenerate. * configure: Likewise. * config/os/mingw32-w64/os_defines.h (_GLIBCXX_USE_GET_NPROCS_WIN32): Define to 1. * config/os/mingw32/os_defines.h (_GLIBCXX_USE_GET_NPROCS_WIN32): Ditto * src/c++11/thread.cc (get_nprocs): Provide Win32 implementation if _GLIBCXX_USE_GET_NPROCS_WIN32 is defined. Replace HAVE_WIN32_SLEEP with USE_WIN32_SLEEP. * testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc: Add missing conditional compilation. * testsuite/lib/libstdc++.exp (check_v3_target_sleep): Add support for _GLIBCXX_USE_WIN32_SLEEP. (check_v3_target_nprocs): Likewise for _GLIBCXX_USE_GET_NPROCS_WIN32. Signed-off-by: Eric Botcazou <ebotcazou@adacore.com> Signed-off-by: Jonathan Yong <10walls@gmail.com>
This commit is contained in:
parent
6a95f0e0a0
commit
9149a5b7e0
@ -820,13 +820,13 @@ i[34567]86-*-mingw*)
|
||||
fi
|
||||
case ${target_thread_file} in
|
||||
win32)
|
||||
tmake_file="$tmake_file i386/t-gthr-win32"
|
||||
tmake_thr_file="i386/t-gthr-win32"
|
||||
;;
|
||||
posix)
|
||||
tmake_file="i386/t-mingw-pthread $tmake_file"
|
||||
tmake_thr_file="i386/t-mingw-pthread"
|
||||
;;
|
||||
mcf)
|
||||
tmake_file="i386/t-mingw-mcfgthread $tmake_file"
|
||||
tmake_thr_file="i386/t-mingw-mcfgthread"
|
||||
;;
|
||||
esac
|
||||
# This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h
|
||||
@ -842,18 +842,18 @@ i[34567]86-*-mingw*)
|
||||
else
|
||||
tmake_dlldir_file="i386/t-dlldir-x"
|
||||
fi
|
||||
tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-mingw32 t-crtfm i386/t-chkstk t-dfprules"
|
||||
tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_thr_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-slibgcc-mingw i386/t-cygming i386/t-mingw32 t-crtfm i386/t-chkstk t-dfprules"
|
||||
;;
|
||||
x86_64-*-mingw*)
|
||||
case ${target_thread_file} in
|
||||
win32)
|
||||
tmake_file="$tmake_file i386/t-gthr-win32"
|
||||
tmake_thr_file="i386/t-gthr-win32"
|
||||
;;
|
||||
posix)
|
||||
tmake_file="i386/t-mingw-pthread $tmake_file"
|
||||
tmake_thr_file="i386/t-mingw-pthread"
|
||||
;;
|
||||
mcf)
|
||||
tmake_file="i386/t-mingw-mcfgthread $tmake_file"
|
||||
tmake_thr_file="i386/t-mingw-mcfgthread"
|
||||
;;
|
||||
esac
|
||||
# This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h
|
||||
@ -872,7 +872,7 @@ x86_64-*-mingw*)
|
||||
else
|
||||
tmake_dlldir_file="i386/t-dlldir-x"
|
||||
fi
|
||||
tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-mingw32 t-dfprules t-crtfm i386/t-chkstk"
|
||||
tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_thr_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-slibgcc-mingw i386/t-cygming i386/t-mingw32 t-dfprules t-crtfm i386/t-chkstk"
|
||||
extra_parts="$extra_parts crtbegin.o crtend.o crtfastmath.o"
|
||||
if test x$enable_vtable_verify = xyes; then
|
||||
extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o"
|
||||
|
89
libgcc/config/i386/gthr-win32-cond.c
Normal file
89
libgcc/config/i386/gthr-win32-cond.c
Normal file
@ -0,0 +1,89 @@
|
||||
/* Implementation of threads compatibility routines for libgcc2. */
|
||||
|
||||
/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This module is separate from the rest of the implementation because it
|
||||
references symbols in system libraries that are only available on Vista
|
||||
and Server 2008 or later versions. */
|
||||
|
||||
/* Get the out-of-line version of the inline routines. */
|
||||
|
||||
#if _WIN32_WINNT < 0x0600
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
|
||||
#define __GTHREAD_WIN32_COND_INLINE
|
||||
|
||||
#define __gthread_cond_init_function __gthr_win32_cond_init_function
|
||||
#define __gthread_cond_broadcast __gthr_win32_cond_broadcast
|
||||
#define __gthread_cond_signal __gthr_win32_cond_signal
|
||||
#define __gthread_cond_wait __gthr_win32_cond_wait
|
||||
#define __gthread_cond_timedwait __gthr_win32_cond_timedwait
|
||||
|
||||
#include "gthr-win32.h"
|
||||
|
||||
/* The number of 100-nanoseconds between 1/1/1601 and 1/1/1970. */
|
||||
#define FILETIME_1970 116444736000000000ULL
|
||||
|
||||
/* The number of 100-nanoseconds per second. */
|
||||
#define NSEC100_PER_SEC (1000000000ULL / 100)
|
||||
|
||||
/* The number of 100-nanoseconds per millisecond. */
|
||||
#define NSEC100_PER_MSEC (NSEC100_PER_SEC / 1000)
|
||||
|
||||
/* The ceiling division of X by Y. */
|
||||
#define CEIL_DIV(X, Y) (((X) + (Y) - 1) / (Y))
|
||||
|
||||
/* Convert absolute thread time to relative time in millisecond. */
|
||||
|
||||
DWORD
|
||||
__gthr_win32_abs_to_rel_time (const __gthread_time_t *abs_time)
|
||||
{
|
||||
union {
|
||||
ULONGLONG nsec100;
|
||||
FILETIME ft;
|
||||
} now;
|
||||
ULONGLONG abs_time_nsec100;
|
||||
|
||||
/* The Windows epoch is 1/1/1601 while the Unix epoch is 1/1/1970. */
|
||||
GetSystemTimeAsFileTime (&now.ft);
|
||||
now.nsec100 -= FILETIME_1970;
|
||||
|
||||
abs_time_nsec100
|
||||
= (ULONGLONG) abs_time->tv_sec * NSEC100_PER_SEC
|
||||
+ CEIL_DIV (abs_time->tv_nsec, 100);
|
||||
|
||||
if (abs_time_nsec100 < now.nsec100)
|
||||
return 0;
|
||||
|
||||
return (DWORD) CEIL_DIV (abs_time_nsec100 - now.nsec100, NSEC100_PER_SEC);
|
||||
}
|
||||
|
||||
/* Check the sizes of the local version of the Win32 types. */
|
||||
|
||||
#define CHECK_SIZE_OF(TYPE) \
|
||||
typedef int assertion[sizeof(__gthr_win32_##TYPE) == sizeof(TYPE) ? 1 : -1];
|
||||
|
||||
CHECK_SIZE_OF (CONDITION_VARIABLE)
|
162
libgcc/config/i386/gthr-win32-thread.c
Normal file
162
libgcc/config/i386/gthr-win32-thread.c
Normal file
@ -0,0 +1,162 @@
|
||||
/* Implementation of threads compatibility routines for libgcc2. */
|
||||
|
||||
/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This module is separate from the rest of the implementation because only
|
||||
one copy of it ought to be linked. */
|
||||
|
||||
/* The implementation strategy for the c++0x thread support is as follows.
|
||||
|
||||
A GNU thread is represented by a Win32 HANDLE that is obtained when the
|
||||
Win32 thread is created, except of course for the initial thread. This
|
||||
Win32 HANDLE is stored in a descriptor keyed from TLS memory for every
|
||||
thread, so the self routine can return it instead of having to duplicate
|
||||
the pseudo-handle returned by GetCurrentThread each time it is invoked.
|
||||
For the initial thread, this Win32 HANDLE is created during the first
|
||||
call to the self routine using the aforementioned technique.
|
||||
|
||||
Note that the equal routine compares the identifier of threads instead
|
||||
of their Win32 HANDLE, which will give the correct positive answer even
|
||||
in the case where distinct Win32 HANDLEs have been created for the same
|
||||
thread by multiple instances of libgcc included in the link. */
|
||||
|
||||
#include "gthr-win32.h"
|
||||
|
||||
/* The thread descriptor keyed from TLS memory. */
|
||||
struct __gthr_win32_thr_desc
|
||||
{
|
||||
void *(*func) (void*);
|
||||
void *args;
|
||||
HANDLE h;
|
||||
};
|
||||
|
||||
/* The TLS key used by one instance of the library. */
|
||||
static __gthread_key_t __gthr_win32_tls = TLS_OUT_OF_INDEXES;
|
||||
|
||||
/* The initialization device for the TLS key. */
|
||||
static __gthread_once_t __gthr_win32_tls_once = __GTHREAD_ONCE_INIT;
|
||||
|
||||
/* Initialize the TLS key. */
|
||||
|
||||
static void
|
||||
__gthr_win32_tls_init (void)
|
||||
{
|
||||
if (__gthread_key_create (&__gthr_win32_tls, free))
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Wrapper routine around thread functions. */
|
||||
|
||||
static DWORD
|
||||
__gthr_win32_thread_wrapper (void *args)
|
||||
{
|
||||
struct __gthr_win32_thr_desc *td = (struct __gthr_win32_thr_desc *) args;
|
||||
|
||||
__gthread_setspecific (__gthr_win32_tls, td);
|
||||
|
||||
DWORD exit_code = (DWORD) (ULONG_PTR) (*td->func) (td->args);
|
||||
|
||||
ExitThread (exit_code);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
/* Implement the __gthread_create routine. */
|
||||
|
||||
int
|
||||
__gthr_win32_create (__gthread_t *thr, void *(*func) (void*), void *args)
|
||||
{
|
||||
struct __gthr_win32_thr_desc *td;
|
||||
|
||||
__gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init);
|
||||
|
||||
td = malloc (sizeof (struct __gthr_win32_thr_desc));
|
||||
td->func = func;
|
||||
td->args = args;
|
||||
td->h = CreateThread (NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) __gthr_win32_thread_wrapper,
|
||||
(LPVOID) td, CREATE_SUSPENDED, NULL);
|
||||
if (td->h)
|
||||
{
|
||||
ResumeThread (td->h);
|
||||
*thr = (__gthread_t) td->h;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (td);
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement the __gthread_join routine. */
|
||||
|
||||
int
|
||||
__gthr_win32_join (__gthread_t thr, void **value_ptr)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (GetThreadId ((HANDLE) thr) == GetCurrentThreadId ())
|
||||
return 1;
|
||||
|
||||
if (WaitForSingleObject ((HANDLE) thr, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (value_ptr)
|
||||
{
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeThread ((HANDLE) thr, &exit_code))
|
||||
*value_ptr = (void *) (ULONG_PTR) exit_code;
|
||||
else
|
||||
status = (int) GetLastError ();
|
||||
}
|
||||
}
|
||||
else
|
||||
status = (int) GetLastError ();
|
||||
|
||||
CloseHandle ((HANDLE) thr);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Implement the __gthread_self routine. */
|
||||
|
||||
__gthread_t
|
||||
__gthr_win32_self (void)
|
||||
{
|
||||
struct __gthr_win32_thr_desc *td;
|
||||
|
||||
__gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init);
|
||||
|
||||
if (!(td = __gthread_getspecific (__gthr_win32_tls)))
|
||||
{
|
||||
HANDLE proc = GetCurrentProcess ();
|
||||
td = malloc (sizeof (struct __gthr_win32_thr_desc));
|
||||
td->func = NULL;
|
||||
td->args = NULL;
|
||||
if (!DuplicateHandle (proc, GetCurrentThread(), proc, &td->h, 0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
abort ();
|
||||
__gthread_setspecific (__gthr_win32_tls, td);
|
||||
}
|
||||
|
||||
return td->h;
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
/* Implementation of W32-specific threads compatibility routines for
|
||||
libgcc2. */
|
||||
/* Implementation of threads compatibility routines for libgcc2. */
|
||||
|
||||
/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
||||
Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
|
||||
Modified and moved to separate file by Danny Smith
|
||||
<dannysmith@users.sourceforge.net>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
@ -27,239 +23,33 @@ 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 <windows.h>
|
||||
#ifndef __GTHREAD_HIDE_WIN32API
|
||||
# define __GTHREAD_HIDE_WIN32API 1
|
||||
#endif
|
||||
/* Get the out-of-line version of the inline routines. */
|
||||
|
||||
#define __GTHREAD_WIN32_ACTIVE_P() 1
|
||||
#define __GTHREAD_WIN32_INLINE
|
||||
|
||||
#define __gthread_detach __gthr_win32_detach
|
||||
#define __gthread_equal __gthr_win32_equal
|
||||
#define __gthread_yield __gthr_win32_yield
|
||||
#define __gthread_once __gthr_win32_once
|
||||
#define __gthread_key_create __gthr_win32_key_create
|
||||
#define __gthread_key_delete __gthr_win32_key_delete
|
||||
#define __gthread_getspecific __gthr_win32_getspecific
|
||||
#define __gthread_setspecific __gthr_win32_setspecific
|
||||
#define __gthread_mutex_init_function __gthr_win32_mutex_init_function
|
||||
#define __gthread_mutex_destroy __gthr_win32_mutex_destroy
|
||||
#define __gthread_mutex_lock __gthr_win32_mutex_lock
|
||||
#define __gthread_mutex_trylock __gthr_win32_mutex_trylock
|
||||
#define __gthread_mutex_unlock __gthr_win32_mutex_unlock
|
||||
#define __gthread_recursive_mutex_trylock __gthr_win32_recursive_mutex_trylock
|
||||
|
||||
#include "gthr-win32.h"
|
||||
|
||||
/* Windows32 threads specific definitions. The windows32 threading model
|
||||
does not map well into pthread-inspired gcc's threading model, and so
|
||||
there are caveats one needs to be aware of.
|
||||
/* Check the sizes of the local version of the Win32 types. */
|
||||
|
||||
1. The destructor supplied to __gthread_key_create is ignored for
|
||||
generic x86-win32 ports. This will certainly cause memory leaks
|
||||
due to unreclaimed eh contexts (sizeof (eh_context) is at least
|
||||
24 bytes for x86 currently).
|
||||
#define CHECK_SIZE_OF(TYPE) \
|
||||
typedef int assertion[sizeof(__gthr_win32_##TYPE) == sizeof(TYPE) ? 1 : -1];
|
||||
|
||||
This memory leak may be significant for long-running applications
|
||||
that make heavy use of C++ EH.
|
||||
|
||||
However, Mingw runtime (version 0.3 or newer) provides a mechanism
|
||||
to emulate pthreads key dtors; the runtime provides a special DLL,
|
||||
linked in if -mthreads option is specified, that runs the dtors in
|
||||
the reverse order of registration when each thread exits. If
|
||||
-mthreads option is not given, a stub is linked in instead of the
|
||||
DLL, which results in memory leak. Other x86-win32 ports can use
|
||||
the same technique of course to avoid the leak.
|
||||
|
||||
2. The error codes returned are non-POSIX like, and cast into ints.
|
||||
This may cause incorrect error return due to truncation values on
|
||||
hw where sizeof (DWORD) > sizeof (int).
|
||||
|
||||
3. We are currently using a special mutex instead of the Critical
|
||||
Sections, since Win9x does not support TryEnterCriticalSection
|
||||
(while NT does).
|
||||
|
||||
The basic framework should work well enough. In the long term, GCC
|
||||
needs to use Structured Exception Handling on Windows32. */
|
||||
|
||||
int
|
||||
__gthr_win32_once (__gthread_once_t *once, void (*func) (void))
|
||||
{
|
||||
if (once == NULL || func == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (! once->done)
|
||||
{
|
||||
if (InterlockedIncrement (&(once->started)) == 0)
|
||||
{
|
||||
(*func) ();
|
||||
once->done = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Another thread is currently executing the code, so wait for it
|
||||
to finish; yield the CPU in the meantime. If performance
|
||||
does become an issue, the solution is to use an Event that
|
||||
we wait on here (and set above), but that implies a place to
|
||||
create the event before this routine is called. */
|
||||
while (! once->done)
|
||||
Sleep (0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Windows32 thread local keys don't support destructors; this leads to
|
||||
leaks, especially in threaded applications making extensive use of
|
||||
C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
|
||||
|
||||
int
|
||||
__gthr_win32_key_create (__gthread_key_t *key,
|
||||
void (*dtor) (void *) __attribute__((unused)))
|
||||
{
|
||||
int status = 0;
|
||||
DWORD tls_index = TlsAlloc ();
|
||||
if (tls_index != 0xFFFFFFFF)
|
||||
{
|
||||
*key = tls_index;
|
||||
#ifdef MINGW32_SUPPORTS_MT_EH
|
||||
/* Mingw runtime will run the dtors in reverse order for each thread
|
||||
when the thread exits. */
|
||||
status = __mingwthr_key_dtor (*key, dtor);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
status = (int) GetLastError ();
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_key_delete (__gthread_key_t key)
|
||||
{
|
||||
return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
|
||||
}
|
||||
|
||||
void *
|
||||
__gthr_win32_getspecific (__gthread_key_t key)
|
||||
{
|
||||
DWORD lasterror;
|
||||
void *ptr;
|
||||
lasterror = GetLastError();
|
||||
ptr = TlsGetValue(key);
|
||||
SetLastError( lasterror );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_setspecific (__gthread_key_t key, const void *ptr)
|
||||
{
|
||||
if (TlsSetValue (key, CONST_CAST2(void *, const void *, ptr)) != 0)
|
||||
return 0;
|
||||
else
|
||||
return GetLastError ();
|
||||
}
|
||||
|
||||
void
|
||||
__gthr_win32_mutex_init_function (__gthread_mutex_t *mutex)
|
||||
{
|
||||
mutex->counter = -1;
|
||||
mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
__gthr_win32_mutex_destroy (__gthread_mutex_t *mutex)
|
||||
{
|
||||
CloseHandle ((HANDLE) mutex->sema);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_mutex_lock (__gthread_mutex_t *mutex)
|
||||
{
|
||||
if (InterlockedIncrement (&mutex->counter) == 0 ||
|
||||
WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
/* WaitForSingleObject returns WAIT_FAILED, and we can only do
|
||||
some best-effort cleanup here. */
|
||||
InterlockedDecrement (&mutex->counter);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_mutex_trylock (__gthread_mutex_t *mutex)
|
||||
{
|
||||
if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_mutex_unlock (__gthread_mutex_t *mutex)
|
||||
{
|
||||
if (InterlockedDecrement (&mutex->counter) >= 0)
|
||||
return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
__gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
|
||||
{
|
||||
mutex->counter = -1;
|
||||
mutex->depth = 0;
|
||||
mutex->owner = 0;
|
||||
mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
|
||||
{
|
||||
DWORD me = GetCurrentThreadId();
|
||||
if (InterlockedIncrement (&mutex->counter) == 0)
|
||||
{
|
||||
mutex->depth = 1;
|
||||
mutex->owner = me;
|
||||
}
|
||||
else if (mutex->owner == me)
|
||||
{
|
||||
InterlockedDecrement (&mutex->counter);
|
||||
++(mutex->depth);
|
||||
}
|
||||
else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
mutex->depth = 1;
|
||||
mutex->owner = me;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* WaitForSingleObject returns WAIT_FAILED, and we can only do
|
||||
some best-effort cleanup here. */
|
||||
InterlockedDecrement (&mutex->counter);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
|
||||
{
|
||||
DWORD me = GetCurrentThreadId();
|
||||
if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
|
||||
{
|
||||
mutex->depth = 1;
|
||||
mutex->owner = me;
|
||||
}
|
||||
else if (mutex->owner == me)
|
||||
++(mutex->depth);
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
|
||||
{
|
||||
--(mutex->depth);
|
||||
if (mutex->depth == 0)
|
||||
{
|
||||
mutex->owner = 0;
|
||||
|
||||
if (InterlockedDecrement (&mutex->counter) >= 0)
|
||||
return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
|
||||
{
|
||||
CloseHandle ((HANDLE) mutex->sema);
|
||||
return 0;
|
||||
}
|
||||
CHECK_SIZE_OF (DWORD)
|
||||
CHECK_SIZE_OF (HANDLE)
|
||||
CHECK_SIZE_OF (CRITICAL_SECTION)
|
||||
|
@ -28,18 +28,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#ifndef GCC_GTHR_WIN32_H
|
||||
#define GCC_GTHR_WIN32_H
|
||||
|
||||
/* Make sure CONST_CAST2 (origin in system.h) is declared. */
|
||||
#ifndef CONST_CAST2
|
||||
#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
|
||||
#endif
|
||||
/* So we can test Windows version numbers. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Windows32 threads specific definitions. The windows32 threading model
|
||||
does not map well into pthread-inspired gcc's threading model, and so
|
||||
there are caveats one needs to be aware of.
|
||||
/* The Windows threading model does not map well into the POSIX inspired
|
||||
GCC threading model, so there are caveats one needs to be aware of.
|
||||
|
||||
1. The destructor supplied to __gthread_key_create is ignored for
|
||||
generic x86-win32 ports. This will certainly cause memory leaks
|
||||
due to unreclaimed eh contexts (sizeof (eh_context) is at least
|
||||
generic Windows ports. This will certainly cause memory leaks
|
||||
due to unreclaimed EH contexts (sizeof (eh_context) is at least
|
||||
24 bytes for x86 currently).
|
||||
|
||||
This memory leak may be significant for long-running applications
|
||||
@ -50,29 +47,41 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
linked in if -mthreads option is specified, that runs the dtors in
|
||||
the reverse order of registration when each thread exits. If
|
||||
-mthreads option is not given, a stub is linked in instead of the
|
||||
DLL, which results in memory leak. Other x86-win32 ports can use
|
||||
DLL, which results in memory leak. Other Windows ports can use
|
||||
the same technique of course to avoid the leak.
|
||||
|
||||
2. The error codes returned are non-POSIX like, and cast into ints.
|
||||
This may cause incorrect error return due to truncation values on
|
||||
hw where sizeof (DWORD) > sizeof (int).
|
||||
|
||||
3. We are currently using a special mutex instead of the Critical
|
||||
Sections, since Win9x does not support TryEnterCriticalSection
|
||||
(while NT does).
|
||||
3. POSIX-like condition variables are supported, but only on Vista and
|
||||
Server 2008 or later versions.
|
||||
|
||||
The basic framework should work well enough. In the long term, GCC
|
||||
needs to use Structured Exception Handling on Windows32. */
|
||||
4. Timed lock primitives are not supported. */
|
||||
|
||||
#define __GTHREADS 1
|
||||
|
||||
#include <errno.h>
|
||||
#ifdef __MINGW32__
|
||||
#include <_mingw.h>
|
||||
/* Condition variables are supported on Vista and Server 2008 or later. */
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
#define __GTHREAD_HAS_COND 1
|
||||
#define __GTHREADS_CXX0X 1
|
||||
#endif
|
||||
|
||||
#ifndef __UNUSED_PARAM
|
||||
#define __UNUSED_PARAM(x) x
|
||||
#if _GTHREAD_USE_MUTEX_TIMEDLOCK
|
||||
#error Timed lock primitives are not supported on Windows targets
|
||||
#endif
|
||||
|
||||
/* Make sure CONST_CAST2 (origin in system.h) is declared. */
|
||||
#ifndef CONST_CAST2
|
||||
#ifdef __cplusplus
|
||||
#define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
|
||||
#else
|
||||
#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
||||
#ifdef _LIBOBJC
|
||||
@ -82,12 +91,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#ifndef __OBJC__
|
||||
#define __OBJC__
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
/* Now undef the windows BOOL. */
|
||||
#undef BOOL
|
||||
|
||||
/* Key structure for maintaining thread specific storage */
|
||||
static DWORD __gthread_objc_data_tls = (DWORD) -1;
|
||||
static DWORD __gthread_objc_data_tls = TLS_OUT_OF_INDEXES;
|
||||
|
||||
/* Backend initialization functions */
|
||||
|
||||
@ -96,7 +106,7 @@ int
|
||||
__gthread_objc_init_thread_system (void)
|
||||
{
|
||||
/* Initialize the thread storage key. */
|
||||
if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
|
||||
if ((__gthread_objc_data_tls = TlsAlloc ()) != TLS_OUT_OF_INDEXES)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
@ -106,7 +116,7 @@ __gthread_objc_init_thread_system (void)
|
||||
int
|
||||
__gthread_objc_close_thread_system (void)
|
||||
{
|
||||
if (__gthread_objc_data_tls != (DWORD) -1)
|
||||
if (__gthread_objc_data_tls != TLS_OUT_OF_INDEXES)
|
||||
TlsFree (__gthread_objc_data_tls);
|
||||
return 0;
|
||||
}
|
||||
@ -222,15 +232,9 @@ __gthread_objc_thread_set_data (void *value)
|
||||
void *
|
||||
__gthread_objc_thread_get_data (void)
|
||||
{
|
||||
DWORD lasterror;
|
||||
void *ptr;
|
||||
|
||||
lasterror = GetLastError ();
|
||||
|
||||
ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
|
||||
|
||||
DWORD lasterror = GetLastError ();
|
||||
void * ptr = TlsGetValue (__gthread_objc_data_tls);
|
||||
SetLastError (lasterror);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -294,7 +298,7 @@ __gthread_objc_mutex_unlock (objc_mutex_t mutex)
|
||||
|
||||
/* Allocate a condition. */
|
||||
int
|
||||
__gthread_objc_condition_allocate (objc_condition_t __UNUSED_PARAM(condition))
|
||||
__gthread_objc_condition_allocate (objc_condition_t condition ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
return -1;
|
||||
@ -302,7 +306,7 @@ __gthread_objc_condition_allocate (objc_condition_t __UNUSED_PARAM(condition))
|
||||
|
||||
/* Deallocate a condition. */
|
||||
int
|
||||
__gthread_objc_condition_deallocate (objc_condition_t __UNUSED_PARAM(condition))
|
||||
__gthread_objc_condition_deallocate (objc_condition_t condition ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
return -1;
|
||||
@ -310,8 +314,8 @@ __gthread_objc_condition_deallocate (objc_condition_t __UNUSED_PARAM(condition))
|
||||
|
||||
/* Wait on the condition */
|
||||
int
|
||||
__gthread_objc_condition_wait (objc_condition_t __UNUSED_PARAM(condition),
|
||||
objc_mutex_t __UNUSED_PARAM(mutex))
|
||||
__gthread_objc_condition_wait (objc_condition_t condition ATTRIBUTE_UNUSED,
|
||||
objc_mutex_t mutex ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
return -1;
|
||||
@ -319,7 +323,7 @@ __gthread_objc_condition_wait (objc_condition_t __UNUSED_PARAM(condition),
|
||||
|
||||
/* Wake up all threads waiting on this condition. */
|
||||
int
|
||||
__gthread_objc_condition_broadcast (objc_condition_t __UNUSED_PARAM(condition))
|
||||
__gthread_objc_condition_broadcast (objc_condition_t condition ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
return -1;
|
||||
@ -327,7 +331,7 @@ __gthread_objc_condition_broadcast (objc_condition_t __UNUSED_PARAM(condition))
|
||||
|
||||
/* Wake up one thread waiting on this condition. */
|
||||
int
|
||||
__gthread_objc_condition_signal (objc_condition_t __UNUSED_PARAM(condition))
|
||||
__gthread_objc_condition_signal (objc_condition_t condition ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* Unimplemented. */
|
||||
return -1;
|
||||
@ -335,35 +339,46 @@ __gthread_objc_condition_signal (objc_condition_t __UNUSED_PARAM(condition))
|
||||
|
||||
#else /* _LIBOBJC */
|
||||
|
||||
/* For struct timespec. Do not include <sys/time.h> here since Gnulib provides
|
||||
its own version which drags the Win32 API definitions. */
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned long __gthread_key_t;
|
||||
typedef unsigned int __gthr_win32_DWORD;
|
||||
typedef void *__gthr_win32_HANDLE;
|
||||
|
||||
typedef struct {
|
||||
int done;
|
||||
long started;
|
||||
} __gthread_once_t;
|
||||
void *DebugInfo;
|
||||
int LockCount;
|
||||
int RecursionCount;
|
||||
__gthr_win32_HANDLE OwningThread;
|
||||
__gthr_win32_HANDLE LockSemaphore;
|
||||
void *SpinCount;
|
||||
} __gthr_win32_CRITICAL_SECTION;
|
||||
|
||||
typedef struct {
|
||||
long counter;
|
||||
void *sema;
|
||||
} __gthread_mutex_t;
|
||||
void *Ptr;
|
||||
} __gthr_win32_CONDITION_VARIABLE;
|
||||
|
||||
typedef struct {
|
||||
long counter;
|
||||
long depth;
|
||||
unsigned long owner;
|
||||
void *sema;
|
||||
} __gthread_recursive_mutex_t;
|
||||
typedef __gthr_win32_HANDLE __gthread_t;
|
||||
typedef __gthr_win32_DWORD __gthread_key_t;
|
||||
typedef struct { int done; long started; } __gthread_once_t;
|
||||
typedef __gthr_win32_CRITICAL_SECTION __gthread_mutex_t;
|
||||
typedef __gthr_win32_CRITICAL_SECTION __gthread_recursive_mutex_t;
|
||||
#if __GTHREAD_HAS_COND
|
||||
typedef __gthr_win32_CONDITION_VARIABLE __gthread_cond_t;
|
||||
#endif
|
||||
typedef struct timespec __gthread_time_t;
|
||||
|
||||
#define __GTHREAD_ONCE_INIT {0, -1}
|
||||
#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
|
||||
#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
|
||||
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
|
||||
__gthread_recursive_mutex_init_function
|
||||
#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
|
||||
#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
|
||||
#define __GTHREAD_TIME_INIT {0, 0}
|
||||
|
||||
#if defined (_WIN32) && !defined(__CYGWIN__)
|
||||
#define MINGW32_SUPPORTS_MT_EH 1
|
||||
@ -388,30 +403,74 @@ __gthread_active_p (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __GTHREAD_HIDE_WIN32API
|
||||
|
||||
/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
|
||||
Only stubs are exposed to avoid polluting the C++ namespace with
|
||||
windows api definitions. */
|
||||
|
||||
extern int __gthr_win32_create (__gthread_t *, void *(*) (void*), void *);
|
||||
extern int __gthr_win32_join (__gthread_t, void **);
|
||||
extern __gthread_t __gthr_win32_self (void);
|
||||
extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
|
||||
extern int __gthr_win32_detach (__gthread_t);
|
||||
extern int __gthr_win32_equal (__gthread_t, __gthread_t);
|
||||
extern int __gthr_win32_yield (void);
|
||||
extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
|
||||
extern int __gthr_win32_key_delete (__gthread_key_t);
|
||||
extern void * __gthr_win32_getspecific (__gthread_key_t);
|
||||
extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
|
||||
extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
|
||||
extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
|
||||
extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
|
||||
extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
|
||||
extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
|
||||
extern void
|
||||
__gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
|
||||
extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
|
||||
extern int
|
||||
__gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
|
||||
extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
|
||||
extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
|
||||
extern int
|
||||
__gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *);
|
||||
extern int __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
|
||||
#if __GTHREAD_HAS_COND
|
||||
extern void __gthr_win32_cond_init_function (__gthread_cond_t *);
|
||||
extern int __gthr_win32_cond_broadcast (__gthread_cond_t *);
|
||||
extern int __gthr_win32_cond_signal (__gthread_cond_t *);
|
||||
extern int __gthr_win32_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
|
||||
extern int __gthr_win32_cond_timedwait (__gthread_cond_t *, __gthread_mutex_t *,
|
||||
const __gthread_time_t *);
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
__gthread_create (__gthread_t *__thr, void *(*__func) (void*),
|
||||
void *__args)
|
||||
{
|
||||
return __gthr_win32_create (__thr, __func, __args);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_join (__gthread_t __thr, void **__value_ptr)
|
||||
{
|
||||
return __gthr_win32_join (__thr, __value_ptr);
|
||||
}
|
||||
|
||||
static inline __gthread_t
|
||||
__gthread_self (void)
|
||||
{
|
||||
return __gthr_win32_self ();
|
||||
}
|
||||
|
||||
#if __GTHREAD_HIDE_WIN32API
|
||||
|
||||
/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
|
||||
Only stubs are exposed to avoid polluting the C++ namespace with
|
||||
Win32 API definitions. */
|
||||
|
||||
static inline int
|
||||
__gthread_detach (__gthread_t __thr)
|
||||
{
|
||||
return __gthr_win32_detach (__thr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_equal (__gthread_t __thr1, __gthread_t __thr2)
|
||||
{
|
||||
return __gthr_win32_equal (__thr1, __thr2);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_yield (void)
|
||||
{
|
||||
return __gthr_win32_yield ();
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
|
||||
@ -485,21 +544,6 @@ __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
__gthr_win32_recursive_mutex_init_function (__mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
return __gthr_win32_recursive_mutex_lock (__mutex);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
@ -509,255 +553,311 @@ __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
|
||||
#if __GTHREAD_HAS_COND
|
||||
|
||||
static inline void
|
||||
__gthread_cond_init_function (__gthread_cond_t *__cond)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
return __gthr_win32_recursive_mutex_unlock (__mutex);
|
||||
else
|
||||
return 0;
|
||||
__gthr_win32_cond_init_function (__cond);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
|
||||
__gthread_cond_broadcast (__gthread_cond_t *__cond)
|
||||
{
|
||||
return __gthr_win32_recursive_mutex_destroy (__mutex);
|
||||
return __gthr_win32_cond_broadcast (__cond);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_signal (__gthread_cond_t *__cond)
|
||||
{
|
||||
return __gthr_win32_cond_signal (__cond);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __gthr_win32_cond_wait (__cond, __mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
|
||||
const __gthread_time_t *__abs_time)
|
||||
{
|
||||
return __gthr_win32_cond_timedwait (__cond, __mutex, __abs_time);
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_HAS_COND */
|
||||
|
||||
#else /* ! __GTHREAD_HIDE_WIN32API */
|
||||
|
||||
#define NOGDI
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
#ifndef __GTHREAD_WIN32_INLINE
|
||||
#define __GTHREAD_WIN32_INLINE static inline
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
#ifndef __GTHREAD_WIN32_COND_INLINE
|
||||
#define __GTHREAD_WIN32_COND_INLINE static inline
|
||||
#endif
|
||||
|
||||
#ifndef __GTHREAD_WIN32_ACTIVE_P
|
||||
#define __GTHREAD_WIN32_ACTIVE_P __gthread_active_p
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_detach (__gthread_t __thr)
|
||||
{
|
||||
CloseHandle ((HANDLE) __thr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_equal (__gthread_t __t1, __gthread_t __t2)
|
||||
{
|
||||
return GetThreadId ((HANDLE) __t1) == GetThreadId ((HANDLE) __t2);
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_yield (void)
|
||||
{
|
||||
Sleep (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
|
||||
{
|
||||
if (! __gthread_active_p ())
|
||||
if (!__GTHREAD_WIN32_ACTIVE_P ())
|
||||
return -1;
|
||||
else if (__once == NULL || __func == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (! __once->done)
|
||||
if (__builtin_expect (!__once->done, 0))
|
||||
{
|
||||
if (InterlockedIncrement (&(__once->started)) == 0)
|
||||
/* We rely on the memory model of the x86 architecture where every load
|
||||
has acquire semantics and every store has release semantics. */
|
||||
if (__atomic_add_fetch (&__once->started, 1, __ATOMIC_ACQ_REL) == 0)
|
||||
{
|
||||
(*__func) ();
|
||||
__once->done = TRUE;
|
||||
__once->done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Another thread is currently executing the code, so wait for it
|
||||
to finish; yield the CPU in the meantime. If performance
|
||||
to finish and yield the CPU in the meantime. If performance
|
||||
does become an issue, the solution is to use an Event that
|
||||
we wait on here (and set above), but that implies a place to
|
||||
create the event before this routine is called. */
|
||||
while (! __once->done)
|
||||
Sleep (0);
|
||||
while (!__once->done)
|
||||
__gthread_yield ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Windows32 thread local keys don't support destructors; this leads to
|
||||
/* Windows thread local keys don't support destructors; this leads to
|
||||
leaks, especially in threaded applications making extensive use of
|
||||
C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
|
||||
static inline int
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_key_create (__gthread_key_t *__key,
|
||||
void (*__dtor) (void *) __attribute__((__unused__)))
|
||||
void (*__dtor) (void *) ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int __status = 0;
|
||||
DWORD __tls_index = TlsAlloc ();
|
||||
if (__tls_index != 0xFFFFFFFF)
|
||||
if (__tls_index != TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
*__key = __tls_index;
|
||||
#ifdef MINGW32_SUPPORTS_MT_EH
|
||||
/* Mingw runtime will run the dtors in reverse order for each thread
|
||||
when the thread exits. */
|
||||
__status = __mingwthr_key_dtor (*__key, __dtor);
|
||||
return __mingwthr_key_dtor (*__key, __dtor);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
__status = (int) GetLastError ();
|
||||
return __status;
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
|
||||
static inline int
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_key_delete (__gthread_key_t __key)
|
||||
{
|
||||
return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
|
||||
if (TlsFree (__key))
|
||||
return 0;
|
||||
else
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
|
||||
static inline void *
|
||||
__GTHREAD_WIN32_INLINE void *
|
||||
__gthread_getspecific (__gthread_key_t __key)
|
||||
{
|
||||
DWORD __lasterror;
|
||||
void *__ptr;
|
||||
|
||||
__lasterror = GetLastError ();
|
||||
|
||||
__ptr = TlsGetValue (__key);
|
||||
|
||||
DWORD __lasterror = GetLastError ();
|
||||
void *__ptr = TlsGetValue (__key);
|
||||
SetLastError (__lasterror);
|
||||
|
||||
return __ptr;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
|
||||
{
|
||||
if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
|
||||
if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)))
|
||||
return 0;
|
||||
else
|
||||
return GetLastError ();
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
__GTHREAD_WIN32_INLINE void
|
||||
__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
__mutex->counter = -1;
|
||||
__mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
|
||||
InitializeCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__GTHREAD_WIN32_INLINE void
|
||||
__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
CloseHandle ((HANDLE) __mutex->sema);
|
||||
DeleteCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
int __status = 0;
|
||||
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
if (InterlockedIncrement (&__mutex->counter) == 0 ||
|
||||
WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
|
||||
__status = 0;
|
||||
else
|
||||
{
|
||||
/* WaitForSingleObject returns WAIT_FAILED, and we can only do
|
||||
some best-effort cleanup here. */
|
||||
InterlockedDecrement (&__mutex->counter);
|
||||
__status = 1;
|
||||
}
|
||||
}
|
||||
return __status;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
int __status = 0;
|
||||
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
|
||||
__status = 0;
|
||||
else
|
||||
__status = 1;
|
||||
}
|
||||
return __status;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
if (InterlockedDecrement (&__mutex->counter) >= 0)
|
||||
return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
|
||||
}
|
||||
if (__GTHREAD_WIN32_ACTIVE_P ())
|
||||
EnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
if (__GTHREAD_WIN32_ACTIVE_P ())
|
||||
{
|
||||
BOOL __ret = TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
if (__ret)
|
||||
{
|
||||
if (__mutex->RecursionCount > 1)
|
||||
{
|
||||
LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
|
||||
{
|
||||
if (__GTHREAD_WIN32_ACTIVE_P ())
|
||||
LeaveCriticalSection ((LPCRITICAL_SECTION) __mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_INLINE int
|
||||
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (__GTHREAD_WIN32_ACTIVE_P ())
|
||||
return TryEnterCriticalSection ((LPCRITICAL_SECTION) __mutex) ? 0 : 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __GTHREAD_HAS_COND
|
||||
|
||||
__GTHREAD_WIN32_COND_INLINE void
|
||||
__gthread_cond_init_function (__gthread_cond_t *__cond)
|
||||
{
|
||||
InitializeConditionVariable ((PCONDITION_VARIABLE) __cond);
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_COND_INLINE int
|
||||
__gthread_cond_broadcast (__gthread_cond_t *__cond)
|
||||
{
|
||||
WakeAllConditionVariable ((PCONDITION_VARIABLE) __cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_COND_INLINE int
|
||||
__gthread_cond_signal (__gthread_cond_t *__cond)
|
||||
{
|
||||
WakeConditionVariable ((PCONDITION_VARIABLE) __cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__GTHREAD_WIN32_COND_INLINE int
|
||||
__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
|
||||
{
|
||||
if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
|
||||
(PCRITICAL_SECTION) __mutex,
|
||||
INFINITE))
|
||||
return 0;
|
||||
else
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
|
||||
extern DWORD __gthr_win32_abs_to_rel_time (const __gthread_time_t *);
|
||||
|
||||
__GTHREAD_WIN32_COND_INLINE int
|
||||
__gthread_cond_timedwait (__gthread_cond_t *__cond,
|
||||
__gthread_mutex_t *__mutex,
|
||||
const __gthread_time_t *__abs_time)
|
||||
{
|
||||
DWORD __rel_time = __gthr_win32_abs_to_rel_time (__abs_time);
|
||||
if (SleepConditionVariableCS ((PCONDITION_VARIABLE) __cond,
|
||||
(PCRITICAL_SECTION) __mutex,
|
||||
__rel_time))
|
||||
return 0;
|
||||
else
|
||||
return (int) GetLastError ();
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_HAS_COND */
|
||||
|
||||
#endif /* __GTHREAD_HIDE_WIN32API */
|
||||
|
||||
static inline void
|
||||
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
__mutex->counter = -1;
|
||||
__mutex->depth = 0;
|
||||
__mutex->owner = 0;
|
||||
__mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
|
||||
__gthread_mutex_init_function (__mutex);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
__gthread_mutex_destroy (__mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
DWORD __me = GetCurrentThreadId();
|
||||
if (InterlockedIncrement (&__mutex->counter) == 0)
|
||||
{
|
||||
__mutex->depth = 1;
|
||||
__mutex->owner = __me;
|
||||
}
|
||||
else if (__mutex->owner == __me)
|
||||
{
|
||||
InterlockedDecrement (&__mutex->counter);
|
||||
++(__mutex->depth);
|
||||
}
|
||||
else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
|
||||
{
|
||||
__mutex->depth = 1;
|
||||
__mutex->owner = __me;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* WaitForSingleObject returns WAIT_FAILED, and we can only do
|
||||
some best-effort cleanup here. */
|
||||
InterlockedDecrement (&__mutex->counter);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
DWORD __me = GetCurrentThreadId();
|
||||
if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
|
||||
{
|
||||
__mutex->depth = 1;
|
||||
__mutex->owner = __me;
|
||||
}
|
||||
else if (__mutex->owner == __me)
|
||||
++(__mutex->depth);
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return __gthread_mutex_lock (__mutex);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
if (__gthread_active_p ())
|
||||
{
|
||||
--(__mutex->depth);
|
||||
if (__mutex->depth == 0)
|
||||
{
|
||||
__mutex->owner = 0;
|
||||
return __gthread_mutex_unlock (__mutex);
|
||||
}
|
||||
|
||||
if (InterlockedDecrement (&__mutex->counter) >= 0)
|
||||
return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
#if __GTHREAD_HAS_COND
|
||||
|
||||
static inline int
|
||||
__gthread_cond_destroy (__gthread_cond_t *__cond ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
|
||||
__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
|
||||
__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
CloseHandle ((HANDLE) __mutex->sema);
|
||||
return 0;
|
||||
return __gthread_cond_wait (__cond, __mutex);
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_HIDE_WIN32API */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
23
libgcc/config/i386/libgcc-mingw.ver
Normal file
23
libgcc/config/i386/libgcc-mingw.ver
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GCC.
|
||||
#
|
||||
# GCC is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GCC is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
GCC_13 {
|
||||
__gthr_win32_create
|
||||
__gthr_win32_join
|
||||
__gthr_win32_self
|
||||
}
|
@ -1,2 +1,6 @@
|
||||
# We hide calls to w32api needed for w32 thread support here:
|
||||
LIB2ADD = $(srcdir)/config/i386/gthr-win32.c
|
||||
# We need a unique module interfacing with the Win32 API for thread support.
|
||||
LIB2ADDEH += $(srcdir)/config/i386/gthr-win32-thread.c
|
||||
# We hide calls to the Win32 API needed for condition variable support here.
|
||||
LIB2ADD_ST += $(srcdir)/config/i386/gthr-win32-cond.c
|
||||
# We hide calls to the Win32 API needed for the rest here.
|
||||
LIB2ADD_ST += $(srcdir)/config/i386/gthr-win32.c
|
||||
|
1
libgcc/config/i386/t-slibgcc-mingw
Normal file
1
libgcc/config/i386/t-slibgcc-mingw
Normal file
@ -0,0 +1 @@
|
||||
SHLIB_MAPFILES += $(srcdir)/config/i386/libgcc-mingw.ver
|
@ -678,10 +678,13 @@ dnl Set up *_FLAGS and *FLAGS variables for all sundry Makefile.am's.
|
||||
dnl (SECTION_FLAGS is done under CHECK_COMPILER_FEATURES.)
|
||||
dnl
|
||||
dnl Substs:
|
||||
dnl CPPFLAGS
|
||||
dnl OPTIMIZE_CXXFLAGS
|
||||
dnl WARN_FLAGS
|
||||
dnl
|
||||
AC_DEFUN([GLIBCXX_EXPORT_FLAGS], [
|
||||
AC_SUBST(CPPFLAGS)
|
||||
|
||||
# Optimization flags that are probably a good idea for thrill-seekers. Just
|
||||
# uncomment the lines below and make, everything else is ready to go...
|
||||
# Alternatively OPTIMIZE_CXXFLAGS can be set in configure.host.
|
||||
@ -1352,6 +1355,10 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_TIME], [
|
||||
cygwin*)
|
||||
ac_has_nanosleep=yes
|
||||
;;
|
||||
mingw*)
|
||||
ac_has_win32_sleep=yes
|
||||
ac_has_sched_yield=yes
|
||||
;;
|
||||
darwin*)
|
||||
ac_has_nanosleep=yes
|
||||
ac_has_sched_yield=yes
|
||||
@ -1537,6 +1544,9 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_TIME], [
|
||||
if test x"$ac_has_nanosleep" = x"yes"; then
|
||||
AC_DEFINE(_GLIBCXX_USE_NANOSLEEP, 1,
|
||||
[ Defined if nanosleep is available. ])
|
||||
elif test x"$ac_has_win32_sleep" = x"yes"; then
|
||||
AC_DEFINE(_GLIBCXX_USE_WIN32_SLEEP, 1,
|
||||
[Defined if Sleep exists.])
|
||||
else
|
||||
AC_MSG_CHECKING([for sleep])
|
||||
AC_TRY_COMPILE([#include <unistd.h>],
|
||||
@ -1557,20 +1567,7 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_TIME], [
|
||||
AC_MSG_RESULT($ac_has_usleep)
|
||||
fi
|
||||
|
||||
if test x"$ac_has_nanosleep$ac_has_sleep" = x"nono"; then
|
||||
ac_no_sleep=yes
|
||||
AC_MSG_CHECKING([for Sleep])
|
||||
AC_TRY_COMPILE([#include <windows.h>],
|
||||
[Sleep(1)],
|
||||
[ac_has_win32_sleep=yes],[ac_has_win32_sleep=no])
|
||||
if test x"$ac_has_win32_sleep" = x"yes"; then
|
||||
AC_DEFINE(HAVE_WIN32_SLEEP,1, [Defined if Sleep exists.])
|
||||
ac_no_sleep=no
|
||||
fi
|
||||
AC_MSG_RESULT($ac_has_win32_sleep)
|
||||
fi
|
||||
|
||||
if test x"$ac_no_sleep" = x"yes"; then
|
||||
if test x"$ac_has_nanosleep$ac_has_win32_sleep$ac_has_sleep" = x"nonono"; then
|
||||
AC_DEFINE(_GLIBCXX_NO_SLEEP,1, [Defined if no way to sleep is available.])
|
||||
fi
|
||||
|
||||
@ -3987,6 +3984,15 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [
|
||||
case $target_thread_file in
|
||||
posix)
|
||||
CXXFLAGS="$CXXFLAGS -DSUPPORTS_WEAK -DGTHREAD_USE_WEAK -D_PTHREADS"
|
||||
;;
|
||||
win32)
|
||||
CXXFLAGS="$CXXFLAGS -D_WIN32_THREADS"
|
||||
# The support of condition variables is disabled by default in
|
||||
# the Win32 gthreads library, so enable it on explicit request.
|
||||
if test x$enable_libstdcxx_threads = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS -D_WIN32_WINNT=0x0600"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_MSG_CHECKING([whether it can be safely assumed that mutex_timedlock is available])
|
||||
@ -3997,6 +4003,9 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [
|
||||
#if (defined(_PTHREADS) \
|
||||
&& (!defined(_POSIX_TIMEOUTS) || _POSIX_TIMEOUTS <= 0))
|
||||
#error
|
||||
// In case of Win32 threads there is no support.
|
||||
#elif defined(_WIN32_THREADS)
|
||||
#error
|
||||
#endif
|
||||
], [ac_gthread_use_mutex_timedlock=1], [ac_gthread_use_mutex_timedlock=0])
|
||||
|
||||
@ -4043,6 +4052,11 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [
|
||||
[],
|
||||
[#include "gthr.h"])
|
||||
fi
|
||||
|
||||
# See above for the rationale.
|
||||
if test $target_thread_file = win32; then
|
||||
CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(semaphore.h, [
|
||||
|
@ -525,9 +525,6 @@
|
||||
/* Define to 1 if you have the <wctype.h> header file. */
|
||||
#undef HAVE_WCTYPE_H
|
||||
|
||||
/* Defined if Sleep exists. */
|
||||
#undef HAVE_WIN32_SLEEP
|
||||
|
||||
/* Define if writev is available in <sys/uio.h>. */
|
||||
#undef HAVE_WRITEV
|
||||
|
||||
@ -1028,6 +1025,9 @@
|
||||
/* Define if code specialized for wchar_t should be used. */
|
||||
#undef _GLIBCXX_USE_WCHAR_T
|
||||
|
||||
/* Defined if Sleep exists. */
|
||||
#undef _GLIBCXX_USE_WIN32_SLEEP
|
||||
|
||||
/* Define to 1 if a verbose library is built, or 0 otherwise. */
|
||||
#undef _GLIBCXX_VERBOSE
|
||||
|
||||
|
@ -85,6 +85,9 @@
|
||||
// their dtors are called
|
||||
#define _GLIBCXX_THREAD_ATEXIT_WIN32 1
|
||||
|
||||
// Enable use of GetSystemInfo to implement get_nprocs
|
||||
#define _GLIBCXX_USE_GET_NPROCS_WIN32 1
|
||||
|
||||
// See libstdc++/59807
|
||||
#define _GTHREAD_USE_MUTEX_INIT_FUNC 1
|
||||
|
||||
|
@ -75,6 +75,9 @@
|
||||
#define _GLIBCXX_LLP64 1
|
||||
#endif
|
||||
|
||||
// Enable use of GetSystemInfo to implement get_nprocs
|
||||
#define _GLIBCXX_USE_GET_NPROCS_WIN32 1
|
||||
|
||||
// See libstdc++/59807
|
||||
#define _GTHREAD_USE_MUTEX_INIT_FUNC 1
|
||||
|
||||
|
60
libstdc++-v3/configure
vendored
60
libstdc++-v3/configure
vendored
@ -20523,6 +20523,10 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
cygwin*)
|
||||
ac_has_nanosleep=yes
|
||||
;;
|
||||
mingw*)
|
||||
ac_has_win32_sleep=yes
|
||||
ac_has_sched_yield=yes
|
||||
;;
|
||||
darwin*)
|
||||
ac_has_nanosleep=yes
|
||||
ac_has_sched_yield=yes
|
||||
@ -21056,6 +21060,10 @@ $as_echo "#define _GLIBCXX_USE_SCHED_YIELD 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define _GLIBCXX_USE_NANOSLEEP 1" >>confdefs.h
|
||||
|
||||
elif test x"$ac_has_win32_sleep" = x"yes"; then
|
||||
|
||||
$as_echo "#define _GLIBCXX_USE_WIN32_SLEEP 1" >>confdefs.h
|
||||
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sleep" >&5
|
||||
$as_echo_n "checking for sleep... " >&6; }
|
||||
@ -21112,38 +21120,7 @@ $as_echo "#define HAVE_USLEEP 1" >>confdefs.h
|
||||
$as_echo "$ac_has_usleep" >&6; }
|
||||
fi
|
||||
|
||||
if test x"$ac_has_nanosleep$ac_has_sleep" = x"nono"; then
|
||||
ac_no_sleep=yes
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Sleep" >&5
|
||||
$as_echo_n "checking for Sleep... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <windows.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
Sleep(1)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ac_has_win32_sleep=yes
|
||||
else
|
||||
ac_has_win32_sleep=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
if test x"$ac_has_win32_sleep" = x"yes"; then
|
||||
|
||||
$as_echo "#define HAVE_WIN32_SLEEP 1" >>confdefs.h
|
||||
|
||||
ac_no_sleep=no
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_has_win32_sleep" >&5
|
||||
$as_echo "$ac_has_win32_sleep" >&6; }
|
||||
fi
|
||||
|
||||
if test x"$ac_no_sleep" = x"yes"; then
|
||||
if test x"$ac_has_nanosleep$ac_has_win32_sleep$ac_has_sleep" = x"nonono"; then
|
||||
|
||||
$as_echo "#define _GLIBCXX_NO_SLEEP 1" >>confdefs.h
|
||||
|
||||
@ -69715,6 +69692,15 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
case $target_thread_file in
|
||||
posix)
|
||||
CXXFLAGS="$CXXFLAGS -DSUPPORTS_WEAK -DGTHREAD_USE_WEAK -D_PTHREADS"
|
||||
;;
|
||||
win32)
|
||||
CXXFLAGS="$CXXFLAGS -D_WIN32_THREADS"
|
||||
# The support of condition variables is disabled by default in
|
||||
# the Win32 gthreads library, so enable it on explicit request.
|
||||
if test x$enable_libstdcxx_threads = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS -D_WIN32_WINNT=0x0600"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it can be safely assumed that mutex_timedlock is available" >&5
|
||||
@ -69731,6 +69717,9 @@ main ()
|
||||
#if (defined(_PTHREADS) \
|
||||
&& (!defined(_POSIX_TIMEOUTS) || _POSIX_TIMEOUTS <= 0))
|
||||
#error
|
||||
// In case of Win32 threads there is no support.
|
||||
#elif defined(_WIN32_THREADS)
|
||||
#error
|
||||
#endif
|
||||
|
||||
;
|
||||
@ -69827,6 +69816,11 @@ $as_echo "#define _GLIBCXX_USE_PTHREAD_RWLOCK_T 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# See above for the rationale.
|
||||
if test $target_thread_file = win32; then
|
||||
CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
|
||||
fi
|
||||
fi
|
||||
|
||||
ac_fn_cxx_check_header_mongrel "$LINENO" "semaphore.h" "ac_cv_header_semaphore_h" "$ac_includes_default"
|
||||
@ -72603,6 +72597,8 @@ $as_echo "$gxx_include_dir" >&6; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Optimization flags that are probably a good idea for thrill-seekers. Just
|
||||
# uncomment the lines below and make, everything else is ready to go...
|
||||
# Alternatively OPTIMIZE_CXXFLAGS can be set in configure.host.
|
||||
|
@ -34,7 +34,7 @@
|
||||
#ifndef _GLIBCXX_USE_NANOSLEEP
|
||||
# ifdef _GLIBCXX_HAVE_SLEEP
|
||||
# include <unistd.h>
|
||||
# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
|
||||
# elif defined(_GLIBCXX_USE_WIN32_SLEEP)
|
||||
# include <windows.h>
|
||||
# elif defined _GLIBCXX_NO_SLEEP && defined _GLIBCXX_HAS_GTHREADS
|
||||
// We expect to be able to sleep for targets that support multiple threads:
|
||||
@ -62,6 +62,16 @@ static inline int get_nprocs()
|
||||
return 0;
|
||||
}
|
||||
# define _GLIBCXX_NPROCS get_nprocs()
|
||||
#elif defined(_GLIBCXX_USE_GET_NPROCS_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
static inline int get_nprocs()
|
||||
{
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo (&sysinfo);
|
||||
return (int)sysinfo.dwNumberOfProcessors;
|
||||
}
|
||||
# define _GLIBCXX_NPROCS get_nprocs()
|
||||
#elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
|
||||
# include <unistd.h>
|
||||
# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
|
||||
@ -254,7 +264,7 @@ namespace this_thread
|
||||
__s = chrono::duration_cast<chrono::seconds>(target - now);
|
||||
__ns = chrono::duration_cast<chrono::nanoseconds>(target - (now + __s));
|
||||
}
|
||||
#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
|
||||
#elif defined(_GLIBCXX_USE_WIN32_SLEEP)
|
||||
unsigned long ms = __ns.count() / 1000000;
|
||||
if (__ns.count() > 0 && ms == 0)
|
||||
ms = 1;
|
||||
|
@ -70,7 +70,10 @@ void test01()
|
||||
TEST_ERRC(network_reset);
|
||||
TEST_ERRC(network_unreachable);
|
||||
TEST_ERRC(no_buffer_space);
|
||||
|
||||
#ifdef ECHILD
|
||||
TEST_ERRC(no_child_process);
|
||||
#endif
|
||||
|
||||
#ifdef ENOLINK
|
||||
TEST_ERRC(no_link);
|
||||
@ -86,7 +89,10 @@ void test01()
|
||||
TEST_ERRC(no_message);
|
||||
#endif
|
||||
TEST_ERRC(no_protocol_option);
|
||||
|
||||
#ifdef ENOSPC
|
||||
TEST_ERRC(no_space_on_device);
|
||||
#endif
|
||||
|
||||
#ifdef ENOSR
|
||||
TEST_ERRC(no_stream_resources);
|
||||
@ -105,16 +111,26 @@ void test01()
|
||||
|
||||
TEST_ERRC(not_connected);
|
||||
TEST_ERRC(not_enough_memory);
|
||||
|
||||
#ifdef ENOTSUP
|
||||
TEST_ERRC(not_supported);
|
||||
#endif
|
||||
|
||||
#ifdef ECANCELED
|
||||
TEST_ERRC(operation_canceled);
|
||||
#endif
|
||||
|
||||
TEST_ERRC(operation_in_progress);
|
||||
|
||||
#ifdef EPERM
|
||||
TEST_ERRC(operation_not_permitted);
|
||||
#endif
|
||||
|
||||
TEST_ERRC(operation_not_supported);
|
||||
|
||||
#ifdef EWOULDBLOCK
|
||||
TEST_ERRC(operation_would_block);
|
||||
#endif
|
||||
|
||||
#ifdef EOWNERDEAD
|
||||
TEST_ERRC(owner_dead);
|
||||
@ -144,7 +160,10 @@ void test01()
|
||||
TEST_ERRC(text_file_busy);
|
||||
#endif
|
||||
|
||||
#ifdef ETIMEDOUT
|
||||
TEST_ERRC(timed_out);
|
||||
#endif
|
||||
|
||||
TEST_ERRC(too_many_files_open_in_system);
|
||||
TEST_ERRC(too_many_files_open);
|
||||
TEST_ERRC(too_many_links);
|
||||
|
@ -510,6 +510,15 @@ proc v3_target_compile { source dest type options } {
|
||||
}
|
||||
}
|
||||
|
||||
# Small adjustment for MinGW hosts.
|
||||
if { $dest == "/dev/null" && [ishost "*-*-mingw*"] } {
|
||||
if { $type == "executable" } {
|
||||
set dest "x.exe"
|
||||
} else {
|
||||
set dest "nul"
|
||||
}
|
||||
}
|
||||
|
||||
lappend options "compiler=$cxx_final"
|
||||
lappend options "timeout=[timeout_value]"
|
||||
|
||||
@ -1147,7 +1156,9 @@ proc check_effective_target_gthreads_timed { } {
|
||||
# Return 1 if either nanosleep or sleep is available, 0 otherwise.
|
||||
proc check_v3_target_sleep { } {
|
||||
return [check_v3_target_prop_cached et_sleep {
|
||||
set cond "defined _GLIBCXX_USE_NANOSLEEP || defined _GLIBCXX_HAVE_SLEEP"
|
||||
set cond "defined _GLIBCXX_USE_NANOSLEEP"
|
||||
set cond "$cond || defined _GLIBCXX_USE_WIN32_SLEEP"
|
||||
set cond "$cond || defined _GLIBCXX_HAVE_SLEEP"
|
||||
return [v3_check_preprocessor_condition sleep $cond]
|
||||
}]
|
||||
}
|
||||
@ -1191,6 +1202,7 @@ proc check_v3_target_binary_io { } {
|
||||
proc check_v3_target_nprocs { } {
|
||||
return [check_v3_target_prop_cached et_nprocs {
|
||||
set cond "defined _GLIBCXX_USE_GET_NPROCS"
|
||||
set cond "$cond || defined _GLIBCXX_USE_GET_NPROCS_WIN32"
|
||||
set cond "$cond || defined _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP"
|
||||
set cond "$cond || defined _GLIBCXX_USE_SYSCTL_HW_NCPU"
|
||||
set cond "$cond || defined _GLIBCXX_USE_SC_NPROCESSORS_ONLN"
|
||||
|
Loading…
x
Reference in New Issue
Block a user