mthread.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 810 行 · 第 1/2 页
C
810 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Core functions of the C runtime multithread support.
*
****************************************************************************/
#include "variety.h"
#include "stacklow.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "liballoc.h"
#include "thread.h"
#include "trdlist.h"
#include "mthread.h"
#include "rtdata.h"
#include "rtinit.h"
#include "exitwmsg.h"
#include "osver.h"
#if defined (_NETWARE_LIBC)
#include "nw_libc.h"
#endif
#if defined( __QNX__ )
#include "semaqnx.h"
#include <sys/magic.h>
extern thread_data *__QNXAddThread( thread_data *tdata );
#endif
extern void __FiniThreadProcessing( void );
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
extern void (*_AccessFileH)( int );
extern void (*_ReleaseFileH)( int );
extern void (*_AccessIOB)( void );
extern void (*_ReleaseIOB)( void );
extern void (*_AccessTDList)( void );
extern void (*_ReleaseTDList)( void );
#if !defined( __NETWARE__ )
extern void (*_AccessNHeap)( void );
extern void (*_AccessFHeap)( void );
extern void (*_ReleaseNHeap)( void );
extern void (*_ReleaseFHeap)( void );
#endif
#if defined( __NT__ )
extern void (*_AccessFList)( void );
extern void (*_ReleaseFList)( void );
extern void (*_ThreadExitRtn)( void );
static semaphore_object FListSemaphore;
#endif
#endif
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
void static nullSema4Rtn( semaphore_object *p ) { p = p; }
_WCRTDATA void (*__AccessSema4)( semaphore_object *) = &nullSema4Rtn;
_WCRTDATA void (*__ReleaseSema4)( semaphore_object *) = &nullSema4Rtn;
_WCRTDATA void (*__CloseSema4)( semaphore_object *) = &nullSema4Rtn;
#if !defined( __NETWARE__ )
static void __NullAccHeapRtn( void ) {}
#endif
#endif
extern int __Sema4Fini; // in finalizer segment
#ifdef _M_IX86
#pragma aux __Sema4Fini "_*";
#endif
extern unsigned __MaxThreads;
extern thread_data *__FirstThreadData;
extern void **__ThreadIDs;
#define MAX_SEMAPHORE 16
static semaphore_object FileSemaphores[ MAX_SEMAPHORE ];
#if !defined( __NETWARE__ )
static semaphore_object FHeapSemaphore;
static semaphore_object NHeapSemaphore;
#endif
static semaphore_object IOBSemaphore;
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
static semaphore_object InitSemaphore;
static semaphore_object TDListSemaphore;
#endif
#if defined( __NT__ )
#define MAX_CRITICAL_SECTION 64
static CRITICAL_SECTION critsect_cache[MAX_CRITICAL_SECTION];
static int critsect_next;
static CRITICAL_SECTION **critsect_vector;
static int critsect_vectornext;
static CRITICAL_SECTION *__NTGetCriticalSection( void )
{
CRITICAL_SECTION *ptr;
if( critsect_next < MAX_CRITICAL_SECTION ) {
ptr = &(critsect_cache[critsect_next]);
critsect_next++;
} else {
ptr = lib_calloc( 1, sizeof( *ptr ) );
if( ptr == NULL ) {
__fatal_runtime_error(
"Unable to allocate semaphore data\r\n", 1 );
}
critsect_vector = lib_realloc( critsect_vector,
(critsect_vectornext+1)*sizeof(CRITICAL_SECTION*));
if( critsect_vector == NULL ) {
__fatal_runtime_error(
"Unable to allocate semaphore data\r\n", 1 );
}
critsect_vector[critsect_vectornext] = ptr;
critsect_vectornext++;
}
InitializeCriticalSection( ptr );
return( ptr );
}
static void __NTDeleteCriticalSection( void ) {
int i;
for( i = 0 ; i < critsect_next ; i++ ) {
DeleteCriticalSection( &(critsect_cache[i]) );
}
}
static void __NTFreeCriticalSection( void ) {
int i;
for( i = 0 ; i < critsect_vectornext ; i++ ) {
DeleteCriticalSection( critsect_vector[i] );
lib_free( critsect_vector[i] );
}
if( critsect_vector ) {
lib_free( critsect_vector );
}
}
#endif
_WCRTLINK void __CloseSemaphore( semaphore_object *obj )
{
#if defined( __RUNTIME_CHECKS__ ) && defined( _M_IX86 )
// 0 is ok
// 1 is ok // JBS I don't think so. I would mean a critical section is active.
// JBS For every lock, there should be an unlock.
// if( obj->count >= 2 ) {
// __fatal_runtime_error( "Semaphore locked too many times\r\n", 1 );
// }
if( obj->count >= 1 ) {
__fatal_runtime_error( "Semaphore not unlocked\r\n", 1 );
}
#endif
#if !defined( __NT__ )
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
if( obj->initialized != 0 ) {
#if defined( __NETWARE__ )
obj->semaphore = 0;
#elif defined( __QNX__ )
__qsem_destroy( &obj->semaphore );
#elif defined( __LINUX__ )
// TODO: Close the semaphore for Linux!
#else
DosCloseMutexSem( obj->semaphore );
#endif
}
#else
if( obj->count > 0 ) {
DosSemClear( &obj->semaphore );
}
#endif
obj->initialized = 0;
obj->owner = 0;
obj->count = 0;
#endif
}
_WCRTLINK void __AccessSemaphore( semaphore_object *obj )
{
TID tid;
tid = GetCurrentThreadId();
#if defined( _NETWARE_CLIB )
if( tid == 0 ) return;
#endif
if( obj->owner != tid ) {
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
#if !defined( __NETWARE__ )
if( obj->initialized == 0 ) {
#if defined( __RUNTIME_CHECKS__ ) && defined( _M_IX86 )
if( obj == &InitSemaphore ) {
__fatal_runtime_error( "Bad semaphore lock\r\n", 1 );
}
#endif
__AccessSemaphore( &InitSemaphore );
if( obj->initialized == 0 ) {
#if defined( __NT__ )
obj->semaphore = __NTGetCriticalSection();
#elif defined( __QNX__ )
__qsem_init( &obj->semaphore, 1, 1 );
#elif defined( __LINUX__ )
// TODO: Access semaphore under Linux!
#else
DosCreateMutexSem( NULL, &obj->semaphore, 0, FALSE );
#endif
obj->initialized = 1;
}
__ReleaseSemaphore( &InitSemaphore );
}
#endif
#if defined( __NETWARE__ )
while( obj->semaphore != 0 )
#if defined (_NETWARE_CLIB)
ThreadSwitch();
#else
NXThreadYield();
#endif
obj->semaphore = 1;
obj->initialized = 1;
#elif defined( __NT__ )
EnterCriticalSection( obj->semaphore );
#elif defined( __QNX__ )
__qsem_wait( &obj->semaphore );
#elif defined( __LINUX__ )
// TODO: Wait for semaphore under Linux!
#else
DosRequestMutexSem( obj->semaphore, SEM_INDEFINITE_WAIT );
#endif
#else
DosSemRequest( &obj->semaphore, -1L );
#endif
obj->owner = tid;
}
obj->count++;
}
_WCRTLINK void __ReleaseSemaphore( semaphore_object *obj )
{
TID tid;
tid = GetCurrentThreadId();
#if defined( _NETWARE_CLIB )
if( tid == 0 ) return;
#endif
if( obj->count > 0 ) {
if( obj->owner != tid ) {
__fatal_runtime_error( "Semaphore unlocked by wrong owner\r\n", 1 );
}
if( --obj->count == 0 ) {
obj->owner = 0;
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
#if defined( __NETWARE__ )
obj->semaphore = 0;
#elif defined( __NT__ )
LeaveCriticalSection( obj->semaphore );
#elif defined( __QNX__ )
__qsem_post( &obj->semaphore );
#elif defined( __LINUX__ )
// TODO: Relase semaphore under Linux!
#else
DosReleaseMutexSem( obj->semaphore );
#endif
#else
DosSemClear( &obj->semaphore );
#endif
}
}
}
void __AccessIOB( void )
/*************************/
{
__AccessSemaphore( &IOBSemaphore );
}
void __ReleaseIOB( void )
/**************************/
{
__ReleaseSemaphore( &IOBSemaphore );
}
void __AccessFileH( int handle )
/******************************/
{
__AccessSemaphore( &FileSemaphores[ (unsigned)handle % MAX_SEMAPHORE ] );
}
void __ReleaseFileH( int handle )
/*******************************/
{
__ReleaseSemaphore( &FileSemaphores[ (unsigned)handle % MAX_SEMAPHORE ] );
}
#if !defined( __NETWARE__ )
void __AccessNHeap( void )
/***************************/
{
__AccessSemaphore( &NHeapSemaphore );
}
void __ReleaseNHeap( void )
/****************************/
{
__ReleaseSemaphore( &NHeapSemaphore );
}
void __AccessFHeap( void )
/***************************/
{
__AccessSemaphore( &FHeapSemaphore );
}
void __ReleaseFHeap( void )
/****************************/
{
__ReleaseSemaphore( &FHeapSemaphore );
}
#endif
#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
void __AccessTDList( void )
/****************************/
{
__AccessSemaphore( &TDListSemaphore );
}
void __ReleaseTDList( void )
/*****************************/
{
__ReleaseSemaphore( &TDListSemaphore );
}
#if defined( __NT__ )
void __AccessFList( void )
/***************************/
{
__AccessSemaphore( &FListSemaphore );
}
void __ReleaseFList( void )
/****************************/
{
__ReleaseSemaphore( &FListSemaphore );
}
#endif
#endif
struct thread_data *__MultipleThread( void )
{
#if defined( __NT__ )
/*
* Preserve old error code -- important because this code can get
* called from _STK.
*/
DWORD old = GetLastError();
thread_data *tdata;
tdata = (thread_data *)TlsGetValue( __TlsIndex );
if( tdata == NULL ) {
tdata = __GetThreadData();
} else if( tdata->__resize ) {
tdata = __ReallocThreadData();
}
SetLastError(old);
return( tdata );
#elif defined (_NETWARE_LIBC)
/*
* Preserve old error code -- important because this code can get
* called from _STK.
*/
int old = GetLastError();
int ccode = 0;
thread_data *tdata = NULL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?