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 + -
显示快捷键?