mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-09 07:40:39 -08:00
* mps/code/w3i6gc.gmk: * mps/code/w3i3gc.gmk: * mps/code/mingw.gmk: New files, for the MinGW build. * mps/code/ss.c (StackHot) [__MINGW32__ && __GNUC__ >= 12]: Ignore dangling-pointer warnings. * mps/code/global.c (ArenaFinalize): Avoid compiler warnings. * mps/code/thw3.c (ThreadScan): Avoid compilation errors due to prototype mismatch. * mps/code/testlib.h (alloca): Don't redefine for MinGW. (setenv): Don't redefine for mingw.org's MinGW. (ulongest_t, longest_t): Separate definitions for MinGW64. * mps/code/testlib.c (sizelog2) [__MINGW32__]: Fix comparison. (rnd_align): Avoid name clashes with 'min' and 'max'. * mps/code/spw3i3.c (StackProbe) [__GNUC__]: Implementation for MinGW. * mps/code/protw3.c: Avoid compiler warning. * mps/code/mpstd.h: Define MinGW (_X86_) and MinGW64 (__X86_64) configurations. * mps/code/mpsiw3.c (mps_SEH_filter, mps_SEH_handler): Add prototypes. * mps/code/mps.c [MPS_PF_W3I3GC]: Define 32-bit MinGW stuff. [MPS_PF_W3I6GC]: Define 64-bit MinGW64 stuff. * mps/code/lockw3.c (RTL_RUN_ONCE, PRTL_RUN_ONCE_INIT_FN) (RTL_RUN_ONCE_INIT, INIT_ONCE_STATIC_INIT, RTL_RUN_ONCE INIT_ONCE) (PRTL_RUN_ONCE PINIT_ONCE, PINIT_ONCE_FN, InitOnceExecuteOnce): Define for mingw.org's MinGW. * mps/code/comm.gmk (EVENT_TARGETS, EXTRA_TARGETS, TEST_TARGETS) (UNBUILDABLE_TARGETS): Add $(EXEEXT) to program names. (TESTTHR): Define correct test for MS-Windows. Don't fail the build if the *.d dependency files don't exist.
251 lines
7 KiB
C
251 lines
7 KiB
C
/* lockw3.c: RECURSIVE LOCKS IN WIN32
|
|
*
|
|
* $Id$
|
|
* Copyright (c) 2001-2020 Ravenbrook Limited. See end of file for license.
|
|
*
|
|
* .design: These are implemented using critical sections.
|
|
* See the section titled "Synchronization functions" in the Groups
|
|
* chapter of the Microsoft Win32 API Programmer's Reference.
|
|
* The "Synchronization" section of the Overview is also relevant.
|
|
*
|
|
* Critical sections support recursive locking, so the implementation
|
|
* could be trivial. This implementation counts the claims to provide
|
|
* extra checking.
|
|
*
|
|
* The limit on the number of recursive claims is the max of
|
|
* ULONG_MAX and the limit imposed by critical sections, which
|
|
* is believed to be about UCHAR_MAX.
|
|
*
|
|
* During use the claims field is updated to remember the number of
|
|
* claims acquired on a lock. This field must only be modified
|
|
* while we are inside the critical section.
|
|
*/
|
|
|
|
#include "mpm.h"
|
|
|
|
#if !defined(MPS_OS_W3)
|
|
#error "lockw3.c is specific to MPS_OS_W3"
|
|
#endif
|
|
|
|
#include "mpswin.h"
|
|
|
|
SRCID(lockw3, "$Id$");
|
|
|
|
#if defined(LOCK)
|
|
|
|
#ifdef __MINGW32__
|
|
# if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000000L
|
|
|
|
/* mingw.org's MinGW doesn't have this stuff in its headers. */
|
|
typedef struct _RTL_RUN_ONCE { PVOID Ptr; } RTL_RUN_ONCE, *PRTL_RUN_ONCE;
|
|
typedef DWORD (WINAPI *PRTL_RUN_ONCE_INIT_FN)(PRTL_RUN_ONCE, PVOID, PVOID *);
|
|
|
|
# define RTL_RUN_ONCE_INIT {0}
|
|
# define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
|
|
|
|
typedef RTL_RUN_ONCE INIT_ONCE;
|
|
typedef PRTL_RUN_ONCE PINIT_ONCE;
|
|
typedef WINBOOL (WINAPI *PINIT_ONCE_FN) (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
|
|
|
|
WINBASEAPI WINBOOL WINAPI InitOnceExecuteOnce (PINIT_ONCE InitOnce, PINIT_ONCE_FN InitFn, PVOID Parameter, LPVOID *Context);
|
|
|
|
# endif /* __MINGW32_VERSION >= 5000000L */
|
|
#endif /* __MINGW32__ */
|
|
|
|
/* .lock.win32: Win32 lock structure; uses CRITICAL_SECTION */
|
|
typedef struct LockStruct {
|
|
Sig sig; /* design.mps.sig.field */
|
|
unsigned long claims; /* # claims held by the owning thread */
|
|
CRITICAL_SECTION cs; /* Win32's recursive lock thing */
|
|
} LockStruct;
|
|
|
|
|
|
size_t (LockSize)(void)
|
|
{
|
|
return sizeof(LockStruct);
|
|
}
|
|
|
|
Bool (LockCheck)(Lock lock)
|
|
{
|
|
CHECKS(Lock, lock);
|
|
return TRUE;
|
|
}
|
|
|
|
void (LockInit)(Lock lock)
|
|
{
|
|
AVER(lock != NULL);
|
|
lock->claims = 0;
|
|
InitializeCriticalSection(&lock->cs);
|
|
lock->sig = LockSig;
|
|
AVERT(Lock, lock);
|
|
}
|
|
|
|
void (LockFinish)(Lock lock)
|
|
{
|
|
AVERT(Lock, lock);
|
|
/* Lock should not be finished while held */
|
|
AVER(lock->claims == 0);
|
|
DeleteCriticalSection(&lock->cs);
|
|
lock->sig = SigInvalid;
|
|
}
|
|
|
|
void (LockClaim)(Lock lock)
|
|
{
|
|
AVERT(Lock, lock);
|
|
EnterCriticalSection(&lock->cs);
|
|
/* This should be the first claim. Now we are inside the
|
|
* critical section it is ok to check this. */
|
|
AVER(lock->claims == 0); /* <design/check/#.common> */
|
|
lock->claims = 1;
|
|
}
|
|
|
|
void (LockRelease)(Lock lock)
|
|
{
|
|
AVERT(Lock, lock);
|
|
AVER(lock->claims == 1); /* The lock should only be held once */
|
|
lock->claims = 0; /* Must set this before leaving CS */
|
|
LeaveCriticalSection(&lock->cs);
|
|
}
|
|
|
|
void (LockClaimRecursive)(Lock lock)
|
|
{
|
|
AVERT(Lock, lock);
|
|
EnterCriticalSection(&lock->cs);
|
|
++lock->claims;
|
|
AVER(lock->claims > 0);
|
|
}
|
|
|
|
void (LockReleaseRecursive)(Lock lock)
|
|
{
|
|
AVERT(Lock, lock);
|
|
AVER(lock->claims > 0);
|
|
--lock->claims;
|
|
LeaveCriticalSection(&lock->cs);
|
|
}
|
|
|
|
Bool (LockIsHeld)(Lock lock)
|
|
{
|
|
if (TryEnterCriticalSection(&lock->cs)) {
|
|
Bool claimed = lock->claims > 0;
|
|
LeaveCriticalSection(&lock->cs);
|
|
return claimed;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Global locking is performed by normal locks.
|
|
* A separate lock structure is used for recursive and
|
|
* non-recursive locks so that each may be differently ordered
|
|
* with respect to client-allocated locks.
|
|
*/
|
|
|
|
static LockStruct globalLockStruct;
|
|
static LockStruct globalRecLockStruct;
|
|
static Lock globalLock = &globalLockStruct;
|
|
static Lock globalRecLock = &globalRecLockStruct;
|
|
static Bool globalLockInit = FALSE; /* TRUE iff initialized */
|
|
|
|
void LockInitGlobal(void)
|
|
{
|
|
globalLock->claims = 0;
|
|
LockInit(globalLock);
|
|
globalRecLock->claims = 0;
|
|
LockInit(globalRecLock);
|
|
globalLockInit = TRUE;
|
|
}
|
|
|
|
/* lockEnsureGlobalLock -- one-time initialization of global locks
|
|
*
|
|
* InitOnceExecuteOnce ensures that only one thread can be running the
|
|
* callback at a time, which allows to safely check globalLockInit. See
|
|
* <https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-initonceexecuteonce>
|
|
* but note that at time of writing (2018-06-27) the documentation has
|
|
* the arguments the wrong way round (parameter comes before context).
|
|
*/
|
|
|
|
static BOOL CALLBACK lockEnsureGlobalLockCallback(INIT_ONCE *init_once, void *parameter, void **context)
|
|
{
|
|
UNUSED(init_once);
|
|
AVER(parameter == UNUSED_POINTER);
|
|
UNUSED(context);
|
|
if (!globalLockInit) {
|
|
LockInitGlobal();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void lockEnsureGlobalLock(void)
|
|
{
|
|
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
|
|
BOOL b = InitOnceExecuteOnce(&init_once, lockEnsureGlobalLockCallback,
|
|
UNUSED_POINTER, NULL);
|
|
AVER(b);
|
|
}
|
|
|
|
void (LockClaimGlobalRecursive)(void)
|
|
{
|
|
lockEnsureGlobalLock();
|
|
AVER(globalLockInit);
|
|
LockClaimRecursive(globalRecLock);
|
|
}
|
|
|
|
void (LockReleaseGlobalRecursive)(void)
|
|
{
|
|
AVER(globalLockInit);
|
|
LockReleaseRecursive(globalRecLock);
|
|
}
|
|
|
|
void (LockClaimGlobal)(void)
|
|
{
|
|
lockEnsureGlobalLock();
|
|
AVER(globalLockInit);
|
|
LockClaim(globalLock);
|
|
}
|
|
|
|
void (LockReleaseGlobal)(void)
|
|
{
|
|
AVER(globalLockInit);
|
|
LockRelease(globalLock);
|
|
}
|
|
|
|
void LockSetup(void)
|
|
{
|
|
/* Nothing to do as MPS does not support fork() on Windows. */
|
|
}
|
|
|
|
#elif defined(LOCK_NONE)
|
|
#include "lockan.c"
|
|
#else
|
|
#error "No lock configuration."
|
|
#endif
|
|
|
|
|
|
/* C. COPYRIGHT AND LICENSE
|
|
*
|
|
* Copyright (C) 2001-2020 Ravenbrook Limited <https://www.ravenbrook.com/>.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|