home *** CD-ROM | disk | FTP | other *** search
- /***
- *mtlock.c - Multi-thread locking routines
- *
- * Copyright (c) 1987-1997, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- * Contains definitions for general-purpose multithread locking functions.
- * _mtlockinit()
- * _mtlock()
- * _mtunlock()
- *
- *******************************************************************************/
-
- #include <cruntime.h>
- #include <oscalls.h>
- #include <internal.h>
- #include <mtdll.h>
- #include <rterr.h>
- #include <stddef.h>
- #include <limits.h>
-
- #ifdef _MT
-
- void __cdecl _mtlockinit( PRTL_CRITICAL_SECTION pLk)
- {
- /*
- * Initialize the critical section.
- */
- InitializeCriticalSection( pLk );
- }
-
- void __cdecl _mtlockterm( PRTL_CRITICAL_SECTION pLk)
- {
- /*
- * Initialize the critical section.
- */
- DeleteCriticalSection( pLk );
- }
-
- _CRTIMP1 void __cdecl _mtlock ( PRTL_CRITICAL_SECTION pLk)
- {
- /*
- * Enter the critical section.
- */
- EnterCriticalSection( pLk );
- }
-
- _CRTIMP1 void __cdecl _mtunlock ( PRTL_CRITICAL_SECTION pLk)
- {
- /*
- * leave the critical section.
- */
- LeaveCriticalSection( pLk );
- }
-
- #endif /* _MT */
-
-
-
-
-
-
-
-
-
-
-
- /* history: mlock.c */
-
- #ifdef _IOSDEBUG
- #include <dbgint.h>
-
- /*
- * Local routines
- */
-
- static void __cdecl _lock_create (unsigned);
-
- #ifdef _IOSDEBUG
- static struct _debug_lock * __cdecl _lock_validate(int);
- #endif /* _IOSDEBUG */
-
-
- /*
- * Global Data
- */
-
- /*
- * Lock Table
- * This table contains the critical section management structure of each
- * lock.
- */
-
- RTL_CRITICAL_SECTION _locktable[_TOTAL_LOCKS]; /* array of locks */
-
- /*
- * Lock Bit Map
- * This table contains one bit for each lock (i.e., each entry in the
- * _locktable[] array).
- *
- * If bit = 0, lock has not been created/opened
- * If bit = 1, lock has been created/opened
- */
-
- char _lockmap[(_TOTAL_LOCKS/CHAR_BIT)+1]; /* lock bit map */
-
-
-
-
- #ifdef _IOSDEBUG
- /*
- * Lock Debug Data Table Segment
- * Contains debugging data for each lock.
- */
-
- struct _debug_lock _debug_locktable[_TOTAL_LOCKS];
-
- #endif /* _IOSDEBUG */
-
- #define _FATAL _amsg_exit(_RT_LOCK)
-
- /***
- * Bit map macros
- *
- *Purpose:
- * _CLEARBIT() - Clear the specified bit
- * _SETBIT() - Set the specified bit
- * _TESTBIT() - Test the specified bit
- *
- *Entry:
- * char a[] = character array
- * unsigned b = bit number (0-based, range from 0 to whatever)
- * unsigned x = bit number (0-based, range from 0 to 31)
- *
- *Exit:
- * _CLEARBIT() = void
- * _SETBIT() = void
- * _TESTBIT() = 0 or 1
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- /*
- * Macros for use when managing a bit in a character array (e.g., _lockmap)
- * a = character array
- * b = bit number (0-based)
- */
-
- #define _CLEARBIT(a,b) \
- ( a[b>>3] &= (~(1<<(b&7))) )
-
- #define _SETBIT(a,b) \
- ( a[b>>3] |= (1<<(b&7)) )
-
- #define _TESTBIT(a,b) \
- ( a[b>>3] & (1<<(b&7)) )
-
- /*
- * Macros for use when managing a bit in an unsigned int
- * x = bit number (0-31)
- */
-
- #define _BIT_INDEX(x) (1 << (x & 0x1F))
-
-
- /***
- *_mtinitlocks() - Initialize the semaphore lock data base
- *
- *Purpose:
- * Initialize the mthread semaphore lock data base.
- *
- * NOTES:
- * (1) Only to be called ONCE at startup
- * (2) Must be called BEFORE any mthread requests are made
- *
- * Schemes for creating the mthread locks:
- *
- * Create the locks one at a time on demand the first
- * time the lock is attempted. This is more complicated but
- * is much faster than creating them all at startup time.
- * These is currently the default scheme.
- *
- * Create and open the semaphore that protects the lock data
- * base.
- *
- *Entry:
- * <none>
- *
- *Exit:
- * returns on success
- * calls _amsg_exit on failure
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void __cdecl _mtinitlocks (
- void
- )
- {
-
- /*
- * All we need to do is create the lock table lock
- */
-
- _lock_create(_LOCKTAB_LOCK);
-
- /*
- * Make sure the assumptions we make in this source are correct.
- * The following is a tricky way to validate sizeof() assumptions
- * at compile time without generating any runtime code (can't
- * use sizeof() in an #ifdef). If the assumption fails, the
- * compiler will generate a divide by 0 error.
- *
- * This here only because it must be inside a subroutine.
- */
-
- ( (sizeof(char) == 1) ? 1 : (1/0) );
- ( (sizeof(int) == 4) ? 1 : (1/0) );
-
- }
-
-
- /***
- *_lock_create() - Create and open a lock
- *
- *Purpose:
- * Create and open a mthread lock.
- *
- * NOTES:
- *
- * (1) The caller must have previously determined that the lock
- * needs to be created/opened (and this hasn't already been done).
- *
- * (2) The caller must have aquired the _LOCKTAB_LOCK, if needed.
- * (The only time this isn't required is at init time.)
- *
- *Entry:
- * unsigned locknum = lock to create
- *
- *Exit:
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- static void __cdecl _lock_create (
- unsigned locknum
- )
- {
-
- #ifdef _IOSDEBUG
- /*
- * See if the lock already exists; if so, die.
- */
-
- if (_TESTBIT(_lockmap, locknum))
- _FATAL;
- #endif /* _IOSDEBUG */
-
- /*
- * Convert the lock number into a lock address
- * and create the semaphore.
- */
-
- /*
- * Convert the lock number into a lock address
- * and initialize the critical section.
- */
- InitializeCriticalSection( &_locktable[locknum] );
-
- /*
- * Set the appropriate bit in the lock bit map.
- */
-
- _SETBIT(_lockmap, locknum);
-
- }
-
-
- /***
- * _lock_stream, etc. - Routines to lock/unlock streams, files, etc.
- *
- *Purpose:
- * _lock_stream = Lock a stdio stream
- * _unlock_stream = Unlock a stdio stream
- * _lock_file = Lock a lowio file
- * _unlock_file = Unlock a lowio file
- *
- *Entry:
- * stream/file identifier
- *
- *Exit:
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void __cdecl _lock_stream (
- int stream_id
- )
- {
- _lock(stream_id+_STREAM_LOCKS);
- }
-
- void __cdecl _unlock_stream (
- int stream_id
- )
- {
- _unlock(stream_id+_STREAM_LOCKS);
- }
-
- void __cdecl _lock_file (
- int fh
- )
- {
- _lock(fh+_FH_LOCKS);
- }
-
- void __cdecl _unlock_file (
- int fh
- )
- {
- _unlock(fh+_FH_LOCKS);
- }
-
-
- /***
- * _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 __cdecl _lock (
- int locknum
- )
- {
-
- #ifdef _IOSDEBUG
- struct _debug_lock *deblock;
- unsigned tidbit;
- #endif /* _IOSDEBUG */
-
- /*
- * Create/open the lock, if necessary
- */
-
- if (!_TESTBIT(_lockmap, locknum)) {
-
- _mlock(_LOCKTAB_LOCK); /*** WARNING: Recursive lock call ***/
-
- /* if lock still doesn't exist, create it */
-
- if (!_TESTBIT(_lockmap, locknum))
- _lock_create(locknum);
-
- _munlock(_LOCKTAB_LOCK);
-
- }
-
- #ifdef _IOSDEBUG
- /*
- * Validate the lock and get pointer to debug lock structure, etc.
- */
-
- deblock = _lock_validate(locknum);
-
- /*
- * Set tidbit to 2**(index of ptd[] entry).
- *
- * call non-locking form of _getptd to avoid recursing
- */
- tidbit = _getptd_lk() - _ptd; /* index of _ptd[] entry */
-
- tidbit = _BIT_INDEX(tidbit);
-
- /*
- * Make sure we're not trying to get lock we already have
- * (except for _EXIT_LOCK1).
- */
-
- if (locknum != _EXIT_LOCK1)
- if ((deblock->holder) & tidbit)
- _FATAL;
-
- /*
- * Set waiter bit for this thread
- */
-
- deblock->waiters |= tidbit;
-
- #endif /* _IOSDEBUG */
-
- /*
- * Get the lock
- */
-
-
- /*
- * Enter the critical section.
- */
- EnterCriticalSection( &_locktable[locknum] );
-
- #ifdef _IOSDEBUG
- /*
- * Clear waiter bit
- */
-
- deblock->waiters &= (~tidbit);
-
- /*
- * Make sure there are no lock holders (unless this is
- * _EXIT_LOCK1); then set holder bit and bump lock count.
- */
-
- _ASSERTE(THREADINTS==1);
-
- if (locknum != _EXIT_LOCK1)
- if ( (unsigned) deblock->holder != 0)
- _FATAL;
-
- deblock->holder &= tidbit;
- deblock->lockcnt++;
-
- #endif /* _IOSDEBUG */
-
- }
-
-
- /***
- * _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 __cdecl _unlock (
- int locknum
- )
- {
- #ifdef _IOSDEBUG
- struct _debug_lock *deblock;
- unsigned tidbit;
- #endif /* _IOSDEBUG */
-
- #ifdef _IOSDEBUG
- /*
- * Validate the lock and get pointer to debug lock structure, etc.
- */
-
- deblock = _lock_validate(locknum);
-
- /*
- * Set tidbit to 2**(index of ptd[] entry).
- */
- tidbit = _getptd_lk() - _ptd; /* index of _ptd[] entry */
-
- tidbit = _BIT_INDEX(tidbit);
-
- /*
- * Make sure we hold this lock then clear holder bit.
- * [Note: Since it is legal to aquire _EXIT_LOCK1 several times,
- * it's possible the holder bit is already clear.]
- */
-
- if (locknum != _EXIT_LOCK1)
- if (!((deblock->holder) & tidbit))
- _FATAL;
-
- deblock->holder &= (~tidbit);
-
- /*
- * See if anyone else is waiting for this lock.
- */
-
- _ASSERTE(THREADINTS==1);
-
- if ((unsigned) deblock->waiters != 0)
- deblock->collcnt++;
-
- #endif /* _IOSDEBUG */
-
- /*
- * leave the critical section.
- */
- LeaveCriticalSection( &_locktable[locknum] );
-
-
- }
-
-
- /*
- * Debugging code
- */
-
- #ifdef _IOSDEBUG
-
- /***
- *_lock_validate() - Validate a lock
- *
- *Purpose:
- * Debug lock validations common to both lock and unlock.
- *
- *Entry:
- * lock number
- *
- *Exit:
- * ptr to lock's debug structure
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- static struct _debug_lock * __cdecl _lock_validate (
- int locknum
- )
- {
- /*
- * Make sure lock is legal
- */
-
- if (locknum > _TOTAL_LOCKS)
- _FATAL;
-
- /*
- * Return pointer to this lock's debug structure
- */
-
- return(&_debug_locktable[locknum]);
-
- }
-
-
- /***
- *_fh_locknum() - Return the lock number for a file handle
- *
- *Purpose:
- *
- *Entry:
- * int fh = file handle
- *
- *Exit:
- * int locknum = corresponding lock number
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- int __cdecl _fh_locknum (
- int fh
- )
- {
- return(fh+_FH_LOCKS);
- }
-
-
- /***
- *_stream_locknum() - Return the lock number for a stream
- *
- *Purpose:
- *
- *Entry:
- * int stream = stream number (i.e., offset of the stream
- * in the _iob table)
- *
- *Exit:
- * int locknum = corresponding lock number
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- int __cdecl _stream_locknum (
- int stream
- )
- {
- return(stream+_STREAM_LOCKS);
- }
-
-
- /***
- *_collide_cnt() - Return the collision count for a lock
- *
- *Purpose:
- *
- *Entry:
- * int lock = lock number
- *
- *Exit:
- * int count = collision count
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- int __cdecl _collide_cnt (
- int locknum
- )
- {
- return(_debug_locktable[locknum].collcnt);
- }
-
-
- /***
- *_lock_cnt() - Return the lock count for a lock
- *
- *Purpose:
- *
- *Entry:
- * int lock = lock number
- *
- *Exit:
- * int count = lock count
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- int __cdecl _lock_cnt (
- int locknum
- )
- {
- return(_debug_locktable[locknum].lockcnt);
- }
-
-
- /***
- *_lock_exist() - Check to see if a lock exists
- *
- *Purpose:
- * Test lock bit map to see if the lock has
- * been created or not.
- *
- *Entry:
- * int lock = lock number
- *
- *Exit:
- * int 0 = lock has NOT been created
- * 1 = lock HAS been created
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- int __cdecl _lock_exist (
- int locknum
- )
- {
- if (_TESTBIT(_lockmap, locknum))
- return(1);
- else
- return(0);
- }
-
- #endif /* _IOSDEBUG */
- #endif /* _IOSDEBUG */
-