mthread.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 810 行 · 第 1/2 页

C
810
字号
        if(0 != (ccode = NXKeyGetValue(__NXSlotID, (void **) &tdata)))
            tdata = NULL;

        if( tdata == NULL )
        {
            tdata = __GetThreadData();
        }
        else if( tdata->__resize )
        {
            tdata = __ReallocThreadData();
        }
        SetLastError(old);
        return( tdata );
    #elif defined( __WARP__ )
        // 32 bit OS/2
        TID tid;
        thread_data *tdata = NULL;
        tid = GetCurrentThreadId();
        if( tid <= __MaxThreads ) {
            tdata = __ThreadData[tid].data;
        }
        if( tdata == NULL ) {
            tdata = __GetThreadData();
        } else if( tdata->__resize ) {
            tdata = __ReallocThreadData();
        }
        return( tdata );
    #elif defined( __OS2_286__ )
        // 16 bit OS/2
        return( __ThreadData[GetCurrentThreadId()] );
    #elif defined( __QNX__ )
        void *tdata;
        __getmagicvar( &tdata, _m_thread_data );
        if( tdata == NULL ) {
            tdata = __QNXAddThread( tdata );
        }
        return( tdata );
    #elif defined( __LINUX__ )
        // TODO: Init multiple threads for Linux!
        return( NULL );
    #else
        return( __ThreadData[GetCurrentThreadId()].data );
    #endif
}

#if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )

thread_data *__AllocInitThreadData( thread_data *tdata )
/******************************************************/
{
    if( tdata == NULL ) {
        tdata = lib_calloc( 1, __ThreadDataSize );
        if( tdata != NULL ) {
            tdata->__allocated = 1;
            tdata->__data_size = __ThreadDataSize;
        }
    }
    __InitThreadData( tdata );
    return( tdata );
}

void __FreeInitThreadData( thread_data *tdata )
/******************************************************/
{
    if( tdata != NULL ) {
        if( tdata->__allocated == 1 )
            lib_free( tdata );
    }
}

#if defined( __NT__ )

BOOL __NTThreadInit( void )
/*************************/
{
    if( __TlsIndex == NO_INDEX ) {
        __TlsIndex = TlsAlloc();
        // avoid Win32s bug (0-2 are assumed to be reserved by Win32s)
        if( WIN32_IS_WIN32S ) {
            while( (__TlsIndex != NO_INDEX) && (__TlsIndex <= 2) ) {
                __TlsIndex = TlsAlloc();
            }
        }
    }
    if( __TlsIndex == NO_INDEX ) {
        return( FALSE );
    }
    return( TRUE );
}


static void __NTThreadFini( void )
/********************************/
{
    if( __TlsIndex != NO_INDEX ) {
        TlsFree( __TlsIndex );
        __TlsIndex = NO_INDEX;
    }
}


BOOL __NTAddThread( thread_data *tdata )
/**************************************/
{
    if( __TlsIndex == NO_INDEX ) {
        return( FALSE );
    }

    tdata = __AllocInitThreadData( tdata );
    if( tdata == NULL ) {
        return( FALSE );
    }
    if( !__AddThreadData( tdata->thread_id, tdata ) ) {
        lib_free( tdata );
        return( FALSE );
    }
    TlsSetValue( __TlsIndex, tdata );

    return( TRUE );
}


void __NTRemoveThread( int close_handle )
/***************************************/
{
    thread_data *tdata;
    HANDLE      thread_handle;

    if( __TlsIndex != NO_INDEX ) {
        tdata = TlsGetValue( __TlsIndex );
        #if defined( __RUNTIME_CHECKS__ ) && defined( _M_IX86 )
            if( tdata == (thread_data *)2 ) return;
        #else
            if( tdata == NULL ) return;
        #endif
        thread_handle = tdata->thread_handle;
        __RemoveThreadData( tdata->thread_id );
        #if defined( __RUNTIME_CHECKS__ ) && defined( _M_IX86 )
            TlsSetValue( __TlsIndex, (void*)2 );
        #else
            TlsSetValue( __TlsIndex, NULL );
        #endif
        if( thread_handle != 0 && close_handle ) {
            CloseHandle( thread_handle );
        }
    }
}

static void __ThreadExit( void )
/******************************/
{
    __NTRemoveThread( TRUE );
    __NTThreadFini();
}

#elif defined( __OS2__ )

int __OS2AddThread( TID tid, thread_data *tdata )
/***********************************************/
{
    tdata = __AllocInitThreadData( tdata );
    if( tdata == NULL ) return( 0 );
    if( tid <= __MaxThreads ) {
        if( __initthread( tdata ) ) {
            lib_free( tdata );
            return( 0 );
        } else {
            __ThreadData[tid].data = tdata;
            __ThreadData[tid].allocated_entry = tdata->__allocated;
        }
    } else {
        if( !__AddThreadData( tid, tdata ) ) {
            // unable to setup storage
            lib_free( tdata );
            return( 0 );
        }
    }
    return( 1 );
}

void __OS2RemoveThread( void )
/****************************/
{
    TID tid;
    tid = *_threadid;
    if( tid <= __MaxThreads ) {
        if( __ThreadData[tid].allocated_entry ) {
            lib_free( __ThreadData[tid].data );
        }
        __ThreadData[tid].data = NULL;
    } else {
        __RemoveThreadData( tid );
    }
}

#elif defined( __QNX__ )

thread_data *__QNXAddThread( thread_data *tdata )
/***********************************************/
{
    void *tmp;
    tdata = __AllocInitThreadData( tdata );
    // if tdata is NULL it doesn't matter what we do with it
    tmp = (void *)tdata;
    __setmagicvar( &tmp, _m_thread_data );
    return( tdata );
}

void __QNXRemoveThread( void )
/****************************/
{
    void *tmp;
    thread_data *tdata;

    __getmagicvar( &tmp, _m_thread_data );
    if( tmp != NULL ) {
        tdata = tmp;
        if( tdata->__allocated ) {
            lib_free( tdata );
        }
        tmp = 0;
        __setmagicvar( &tmp, _m_thread_data );
    }
}

#elif defined( __LINUX__ )

thread_data *__LinuxAddThread( thread_data *tdata )
/***********************************************/
{
    // TODO: Implement this for Linux!
    return( NULL );
}

void __LinuxRemoveThread( void )
/****************************/
{
    // TODO: Implement this for Linux!
}

#endif

void __InitMultipleThread( void )
/*******************************/
{
    if( __GetThreadPtr != &__MultipleThread ) {
        #if defined( _NETWARE_CLIB )
        {
        /* __ThreadData[ 0 ] is used whenever GetThreadID() returns a pointer
           not in our __ThreadIDs list - ie. whenever it returns NULL, a
           pointer to a thread we didn't create, or an invalid pointer */
            void *ptr;
            ptr = lib_calloc( 1, __ThreadDataSize );
            if( ptr == NULL ) {
                __fatal_runtime_error(
                    "Unable to allocate thread-specific data\r\n", 1 );
            }
            __ThreadData[ 0 ].data = ptr;
            __ThreadData[ 0 ].allocated_entry = 1;
            __ThreadData[ 0 ].data->__allocated = 1;
            __ThreadData[ 0 ].data->__randnext = 1;
            __ThreadData[ 0 ].data->__data_size = __ThreadDataSize;
            if( __initthread( ptr ) ) {
                lib_free( ptr );
                __fatal_runtime_error(
                    "Unable to initialize thread-specific data\r\n", 1 );
            }
            ptr = lib_calloc( 1, __ThreadDataSize );
            if( ptr == NULL ) {
                __fatal_runtime_error(
                    "Unable to allocate thread-specific data\r\n", 1 );
            }
            __FirstThreadData = ptr;
            __FirstThreadData->__allocated = 1;
            __FirstThreadData->__randnext = 1;
            __FirstThreadData->__data_size = __ThreadDataSize;
            __ThreadData[ 1 ].data = __FirstThreadData;
            __ThreadData[ 1 ].allocated_entry = __FirstThreadData->__allocated;
            __ThreadIDs[ 1 ] = GetThreadID();
            if( __initthread( ptr ) ) {
                lib_free( ptr );
                __fatal_runtime_error(
                    "Unable to initialize thread-specific data\r\n", 1 );
            }
        }
        #elif defined (_NETWARE_LIBC)
            InitSemaphore.semaphore     = 0;    /* sema4 is mutex in this case */
            InitSemaphore.initialized   = 1;
            //_ThreadExitRtn = &__ThreadExit;   - might need this at some point??
            // Note: __AddThreadData uses the InitSemaphore, _AccessTDList & _ReleaseTDList

            __FirstThreadData->thread_id = GetCurrentThreadId();

            __AddThreadData( __FirstThreadData->thread_id, __FirstThreadData );
            if(0 != NXKeySetValue(__NXSlotID, __FirstThreadData))
            {
                __fatal_runtime_error(
                    "Unable to initialize thread-specific data\r\n", 1 );
            }
        #elif defined( __NT__ )
            InitSemaphore.semaphore = __NTGetCriticalSection();
            InitSemaphore.initialized = 1;
            _ThreadExitRtn = &__ThreadExit;
            // Note: __AddThreadData uses the InitSemaphore, _AccessTDList & _ReleaseTDList
            __AddThreadData( __FirstThreadData->thread_id, __FirstThreadData );
            TlsSetValue( __TlsIndex, __FirstThreadData );
        #elif defined( __QNX__ )
            __qsem_init( &InitSemaphore.semaphore, 1, 1 );
            InitSemaphore.initialized = 1;
            // first thread data already in magic memory
        #elif defined( __LINUX__ )
            // TODO: Init semaphores for Linux
        #else
            DosCreateMutexSem( NULL, &InitSemaphore.semaphore, 0, FALSE );
            InitSemaphore.initialized = 1;
            __ThreadData[1].data = __FirstThreadData;
            __ThreadData[1].allocated_entry = __FirstThreadData->__allocated;
        #endif

        // Set these up after we have created the InitSemaphore
        #if !defined (_THIN_LIB)
        _AccessFileH      = &__AccessFileH;
        _ReleaseFileH     = &__ReleaseFileH;
        _AccessIOB        = &__AccessIOB;
        _ReleaseIOB       = &__ReleaseIOB;
        #endif
        _AccessTDList     = &__AccessTDList;
        _ReleaseTDList    = &__ReleaseTDList;
        __AccessSema4     = &__AccessSemaphore;
        __ReleaseSema4    = &__ReleaseSemaphore;
        __CloseSema4      = &__CloseSemaphore;
        #if !defined( __NETWARE__ )
        _AccessNHeap  = &__AccessNHeap;
        _AccessFHeap  = &__AccessFHeap;
        _ReleaseNHeap = &__ReleaseNHeap;
        _ReleaseFHeap = &__ReleaseFHeap;
        #endif
        #if defined( __NT__ )
        _AccessFList  = &__AccessFList;
        _ReleaseFList = &__ReleaseFList;
        #endif
        __GetThreadPtr  = &__MultipleThread;
    }
}
#endif

static void __FiniSema4s( void )              // called from finalizer
/******************************/
{
    int         i;

    _CloseSemaphore( &IOBSemaphore );
    for( i = 0; i < MAX_SEMAPHORE; i++ )
    {              /* 17-feb-93 */
        _CloseSemaphore( &FileSemaphores[ i ] );
    }
    #if defined( __NT__ )
    _CloseSemaphore( &FListSemaphore );
    __NTFreeCriticalSection();
    #endif
    #if !defined( __QNX__ )
    __FiniThreadProcessing();
        #if !defined( __OS2_286__ )
        // All thread data areas freed, including main process thread data
        // so mark first thread data pointer null. Note that OS/2 1.x does
        // not have __FirstThreadData at all.
        __FirstThreadData = NULL;
        #endif
    #endif
    #if !defined( __NETWARE__ )
    _heapshrink();
    _CloseSemaphore( &NHeapSemaphore );
    _CloseSemaphore( &FHeapSemaphore );
    #endif
    #if defined( __386__ ) || defined( __AXP__ ) || defined( __PPC__ ) || defined( __MIPS__ )
    _CloseSemaphore( &TDListSemaphore );
    _CloseSemaphore( &InitSemaphore );

    // After closing InitSemaphore, we need to reset the sem access routines to
    // the dummy ones; someone may still want semaphore protection during shutdown
    // processing but since threading is gone now, there should be no reentrancy
    // problems
    __AccessSema4  = &nullSema4Rtn;
    __ReleaseSema4 = &nullSema4Rtn;
    __CloseSema4   = &nullSema4Rtn;
    #if !defined( __NETWARE__ )
        _AccessNHeap  = &__NullAccHeapRtn;
        _AccessFHeap  = &__NullAccHeapRtn;
        _ReleaseNHeap = &__NullAccHeapRtn;
        _ReleaseFHeap = &__NullAccHeapRtn;
    #endif

        #if defined( __NT__ )
        __NTDeleteCriticalSection();
        __NTThreadFini();
        #endif
        #if defined (_NETWARE_LIBC)
        __LibCThreadFini();
        #endif
    #endif
}

AYI( __FiniSema4s, INIT_PRIORITY_RUNTIME )

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?