123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /* Implementation of W32-specific 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.
- 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/>. */
- #include <windows.h>
- #ifndef __GTHREAD_HIDE_WIN32API
- # define __GTHREAD_HIDE_WIN32API 1
- #endif
- #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.
- 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).
- 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;
- }
|