2020-09-30 17:12:29 +02:00

383 lines
9.9 KiB
C

#ifdef MTHREAD
/***
*mlock.c - Multi-thread locking routines
*
* Copyright (c) 1987-1993, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*Revision History:
* 05-07-90 JCR Module created.
* 06-04-90 GJF Changed error message interface.
* 08-08-90 GJF Removed 32 from API names.
* 08-08-90 SBM _lockmap no longer 8 times required size
* 10-08-90 GJF New-style function declarators. Removed questionable
* return statements from void functions (weren't needed
* and the compiler was bitching).
* 10-09-90 GJF Thread ids are unsigned longs.
* 06-06-91 GJF Adapted for Win32 [_WIN32_].
* 09-29-91 GJF Fixed infinite recursion problem with DEBUG version
* of _lock [_WIN32_].
* 03-06-92 GJF Removed _[un]lock_fh() and _[un]lock_stream for Win32
* targets.
* 05-28-92 GJF Added _mtdeletelocks() for Win32 for DLLs with contain
* the C runtime (e.g., crtdll.dll).
* 10-06-92 SRW Make _locktable an array of PCRITICAL_SECTION pointers
* instead of structures. Allocate each critical section
* as it is needed.
* 02-25-93 GJF Substantially revised. Restored static critical section
* structures for some locks. Replaced bit-array scheme
* of keeping track of locks. Removed Cruiser support and
* replaced obsolete DEBUG code.
* 03-03-93 GJF Made CRITICAL_SECTION structure for _HEAP_LOCK static.
* 03-08-93 SKS Fix ptr use error in DEBUG version of _mtdeletelocks
* 03-08-93 SKS Fix deletion of the special critical sections,
* especially the heap lock.
* 05-05-93 GJF Turned DEBUG code off.
* 06-03-93 SRW Disable FPO optimizations for this file so it can call
* CriticalSection routines on a checked build even though
* the C Runtimes are compiled free.
*
*******************************************************************************/
#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <os2dll.h>
#include <rterr.h>
#include <stddef.h>
#include <malloc.h>
#include <limits.h>
/*
* Local routines
*/
void _CRTAPI3 _lockerr_exit(char *);
/*
* Global Data
*/
/*
* Statically allocated critical section structures for _LOCKTAB_LOCK,
* _EXIT_LOCK1 and _HEAP_LOCK.
*/
static CRITICAL_SECTION ltlcritsect;
static CRITICAL_SECTION xlcritsect;
static CRITICAL_SECTION hlcritsect;
/*
* Lock Table
* This table contains a pointer to the critical section management structure
* for each lock.
*/
PCRITICAL_SECTION _locktable[_TOTAL_LOCKS] = {
NULL, /* 0 == no lock defined *** OBSOLETE *** */
NULL, /* 1 == _SIGNAL_LOCK */
NULL, /* 2 == _IOB_SCAN_LOCK */
NULL, /* 3 == _TMPNAM_LOCK */
NULL, /* 4 == _INPUT_LOCK */
NULL, /* 5 == _OUTPUT_LOCK */
NULL, /* 6 == _CSCANF_LOCK */
NULL, /* 7 == _CPRINTF_LOCK */
NULL, /* 8 == _CONIO_LOCK */
&hlcritsect, /* 9 == _HEAP_LOCK */
NULL, /* 10 == _BHEAP_LOCK *** OBSOLETE *** */
NULL, /* 11 == _TIME_LOCK */
NULL, /* 12 == _ENV_LOCK */
&xlcritsect, /* 13 == _EXIT_LOCK1 */
NULL, /* 14 == _EXIT_LOCK2 *** OBSOLETE *** */
NULL, /* 15 == _THREADDATA_LOCK *** OBSOLETE *** */
NULL, /* 16 == _POPEN_LOCK */
&ltlcritsect, /* 17 == _LOCKTAB_LOCK */
NULL, /* 18 == _OSFHND_LOCK */
NULL, /* 19 == _SETLOCALE_LOCK */
NULL, /* 20 == _LC_COLLATE_LOCK */
NULL, /* 21 == _LC_CTYPE_LOCK */
NULL, /* 22 == _LC_MONETARY_LOCK */
NULL, /* 23 == _LC_NUMERIC_LOCK */
NULL, /* 24 == _LC_TIME_LOCK */
NULL, /* 25 == _STREAM_LOCKS */
NULL /* ... */
};
#define _FATAL _amsg_exit(_RT_LOCK)
#pragma optimize("y",off)
/***
*_mtinitlocks() - Initialize multi-thread lock scheme
*
*Purpose:
* Perform whatever initialization is required for the multi-thread
* locking (synchronization) scheme. This routine should be called
* exactly once, during startup, and this must be before any requests
* are made to assert locks.
*
* NOTES: In Win32, the multi-thread locks are created individually,
* each upon its first use. That is when any particular lock is asserted
* for the first time, the underlying critical section is then allocated,
* initialized and (finally) entered. This allocation and initialization
* is protected under _LOCKTAB_LOCK. It is _mtinitlocks' job to set up
* _LOCKTAB_LOCK. _EXIT_LOCK1 is also set up by _mtinitlock
*
*Entry:
* <none>
*
*Exit:
* returns on success
* calls _amsg_exit on failure
*
*Exceptions:
*
*******************************************************************************/
void _CRTAPI1 _mtinitlocks (
void
)
{
#ifdef DEBUG
int i;
/*
* Scan _locktable[] and make sure everything was initialized properly
*/
for ( i = 0 ; i < _TOTAL_LOCKS ; i++ ) {
if ( i == _LOCKTAB_LOCK ) {
if ( _locktable[i] != &ltlcritsect )
_lockerr_exit("fatal error in _mtinitlocks #1\n");
}
else if ( i == _EXIT_LOCK1 ) {
if ( _locktable[i] != &xlcritsect )
_lockerr_exit("fatal error in _mtinitlocks #2\n");
}
else if ( i == _HEAP_LOCK ) {
if ( _locktable[i] != &hlcritsect )
_lockerr_exit("fatal error in _mtinitlocks #3\n");
}
else if ( _locktable[i] != NULL )
_lockerr_exit("fatal error in _mtinitlocks #3\n");
}
#endif /* DEBUG */
/*
* All we need to do is initialize _LOCKTAB_LOCK and _EXIT_LOCK1.
*/
InitializeCriticalSection( _locktable[_LOCKTAB_LOCK] );
InitializeCriticalSection( _locktable[_EXIT_LOCK1] );
InitializeCriticalSection( _locktable[_HEAP_LOCK] );
}
/***
*_mtdeletelocks() - Delete all initialized locks
*
*Purpose:
* Walks _locktable[] and _lockmap, and deletes every 'lock' (i.e.,
* critical section) which has been initialized.
*
* This function is intended for use in DLLs containing the C runtime
* (i.e., crtdll.dll and user DLLs built using libcmt.lib and the
* special startup objects). It is to be called from within the DLL's
* entrypoint function when that function is called with
* DLL_PROCESS_DETACH.
*
*Entry:
* <none>
*
*Exit:
*
*Exceptions:
* behavior undefined/unknown if a lock is being held when this routine
* is called.
*
*******************************************************************************/
void _CRTAPI1 _mtdeletelocks(
void
)
{
int locknum;
for ( locknum = 0 ; locknum < _TOTAL_LOCKS ; locknum++ ) {
/*
* If the 'lock' has been created, delete it
*/
#ifdef DEBUG
/*
* See if the lock has already been deleted.
*/
if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
_lockerr_exit("fatal error in _mtdeletelocks #1\n");
/*
* Delete the lock if it had been created.
*/
if ( _locktable[locknum] != NULL ) {
if ( (locknum != _LOCKTAB_LOCK) && (locknum !=
_EXIT_LOCK1) && (locknum != _HEAP_LOCK) )
{
PCRITICAL_SECTION pcs = _locktable[locknum];
/* mark as deleted */
_locktable[locknum] = (PCRITICAL_SECTION)(-1L);
/* double check that it wasn't already deleted */
if ( pcs == (PCRITICAL_SECTION)(-1L) )
_lockerr_exit("fatal error in _mtdeletelocks #2\n");
DeleteCriticalSection(pcs);
free(pcs);
}
}
#else /* non DEBUG */
/*
* Delete the lock if it had been created
*/
if ( _locktable[locknum] != NULL ) {
if ( (locknum != _LOCKTAB_LOCK) && (locknum !=
_EXIT_LOCK1) && (locknum != _HEAP_LOCK) )
{
/*
* Free the memory for the CritSect after deleting
* it. It is okay to call free() if the heap lock
* is kept valid until after all calls to the heap.
*/
DeleteCriticalSection(_locktable[locknum]);
free(_locktable[locknum]);
}
}
#endif /* DEBUG */
}
/*
* Finally, clean up the special locks
*/
DeleteCriticalSection( _locktable[_HEAP_LOCK] );
DeleteCriticalSection( _locktable[_EXIT_LOCK1] );
DeleteCriticalSection( _locktable[_LOCKTAB_LOCK] );
}
/***
* _lock - Acquire a multi-thread lock
*
*Purpose:
* Note that it is legal for a thread to aquire _EXIT_LOCK1
* multiple times.
*
*Entry:
* locknum = number of the lock to aquire
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _CRTAPI1 _lock (
int locknum
)
{
PCRITICAL_SECTION pcs;
#ifdef DEBUG
if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
_lockerr_exit("fatal error in _lock #1\n");
#endif /* DEBUG */
/*
* Create/open the lock, if necessary
*/
if ( _locktable[locknum] == NULL ) {
if ( (pcs = malloc(sizeof(CRITICAL_SECTION))) == NULL )
_amsg_exit(_RT_LOCK);
_mlock(_LOCKTAB_LOCK); /*** WARNING: Recursive lock call ***/
if ( _locktable[locknum] == NULL ) {
InitializeCriticalSection(pcs);
_locktable[locknum] = pcs;
}
else {
#ifdef DEBUG
if ( _locktable[locknum] == (PCRITICAL_SECTION)(-1L) )
_lockerr_exit("fatal error in _lock #2\n");
#endif /* DEBUG */
free(pcs);
}
_munlock(_LOCKTAB_LOCK);
}
/*
* Enter the critical section.
*/
EnterCriticalSection( _locktable[locknum] );
}
/***
* _unlock - Release multi-thread lock
*
*Purpose:
* Note that it is legal for a thread to aquire _EXIT_LOCK1
* multiple times.
*
*Entry:
* locknum = number of the lock to release
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _CRTAPI1 _unlock (
int locknum
)
{
/*
* leave the critical section.
*/
LeaveCriticalSection( _locktable[locknum] );
}
#pragma optimize("y",)
/***
*_lockerr_exit() - Write error message and die
*
*Purpose:
* Attempt to write out the unexpected lock error message, then terminate
* the program by a direct API call. This function is used in place of
* amsg_exit(_RT_LOCK) when it is judged unsafe to allow further lock
* or unlock calls.
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
void _CRTAPI3 _lockerr_exit (
char *msg
)
{
FatalAppExit(0, msg); /* Die with message box */
ExitProcess(255); /* Just die */
}
#endif /* MTHREAD */