Easily switchable threading system at compile time

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

Easily switchable threading system at compile time

Postby jay3d » Sat Apr 02, 2011 3:25 pm

4 file changes in Newton core and containers to support switching the threading system for MingW32/64 compilers:

The default will use Win32 Threads, and defining _POSIX_THREADS along with _MINGW_32_VER or _MINGW_64_VER will enable using POSIX Threads instead

source\core\dgThreads.cpp :
Code: Select all
/* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

#include "dgStdafx.h"
#include "dgTypes.h"
#include "dgThreads.h"


static inline void dgThreadYield()
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    Sleep(0);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
#ifndef _MAC_IPHONE
    sched_yield();
#endif
#endif
}


static inline void dgSpinLock (dgInt32 *spin)
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    while (InterlockedExchange((long*) spin, 1))
    {
        Sleep(0);
    }
#endif
#endif

#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    while(! __sync_bool_compare_and_swap((int32_t*)spin, 0, 1) )
    {
        sched_yield();
    }
#endif

#if (defined (_MAC_VER))
#ifndef _MAC_IPHONE
    while( ! OSAtomicCompareAndSwap32(0, 1, (int32_t*) spin) )
    {
        sched_yield();
    }
#endif
#endif
}


inline void dgSpinUnlock (dgInt32 *spin)
{
    *spin = 0;
}


static inline void dgInterlockedIncrement (dgInt32* Addend )
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    InterlockedIncrement((long*) Addend);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    __sync_fetch_and_add ((int32_t*)Addend, 1 );
#endif

#if (defined (_MAC_VER))
    OSAtomicAdd32 (1, (int32_t*)Addend);
#endif
}



static inline void dgInterlockedDecrement(dgInt32* Addend)
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    InterlockedDecrement((long*) Addend);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    __sync_fetch_and_sub ((int32_t*)Addend, 1 );
#endif

#if (defined (_MAC_VER))
    OSAtomicAdd32 (-1, (int32_t*)Addend);
#endif
}



dgThreads::dgThreads()
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    m_numberOfCPUCores = dgInt32 (sysInfo.dwNumberOfProcessors);

    m_numOfThreads = 0;
    m_exit = NULL;
    m_workToDo = NULL;
    m_emptySlot = NULL;

    m_topIndex = 0;
    m_bottomIndex = 0;
    m_workInProgress = 0;
    m_globalSpinLock = 0;

    memset (m_threadhandles, 0, sizeof (m_threadhandles));
#endif
#endif

#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
#ifndef _WIN_POSIX_VER
    m_numberOfCPUCores = sysconf(_SC_NPROCESSORS_ONLN);
#else
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    m_numberOfCPUCores = dgInt32 (sysInfo.dwNumberOfProcessors);
#endif

    m_numOfThreads = 0;
    m_exit = false;

    memset (m_threadhandles, 0, sizeof (m_threadhandles));
    m_topIndex = 0;
    m_bottomIndex = 0;
    m_workInProgress = 0;
    m_globalSpinLock = 0;
    m_workToDoSpinLock = 0;
#endif

#if (defined (_MAC_VER))
    int mib[2];
    size_t len;
    int procesorcount;

    mib[0] = CTL_HW;
    mib[1] = HW_NCPU;
    len = sizeof (procesorcount);
    procesorcount = 0;
    m_numberOfCPUCores = sysctl(mib, 2, &procesorcount, &len, NULL, 0);
    m_numberOfCPUCores =  procesorcount;

    m_numOfThreads = 0;
    m_exit = false;

    memset (m_threadhandles, 0, sizeof (m_threadhandles));

    m_topIndex = 0;
    m_bottomIndex = 0;
    m_workInProgress = 0;
    m_globalSpinLock = 0;
    m_workToDoSpinLock = 0;
#endif

    m_getPerformanceCount = NULL;
    for (dgInt32 i = 0; i < DG_MAXIMUN_THREADS; i ++)
    {
        m_localData[i].m_ticks = 0;
        m_localData[i].m_threadIndex = i;
        m_localData[i].m_manager = this;
    }
}

dgThreads::~dgThreads()
{
    if (m_numOfThreads)
    {
        DestroydgThreads();
    }
}


dgInt32 dgThreads::GetThreadCount() const
{
    return (m_numOfThreads == 0) ? 1 : m_numOfThreads;
}

void dgThreads::ClearTimers()
{
    for (dgInt32 i = 0; i < m_numOfThreads; i ++)
    {
        m_localData[i].m_ticks = 0;
    }
}


void dgThreads::SetPerfomanceCounter(OnGetPerformanceCountCallback callback)
{
    m_getPerformanceCount = callback;
}

dgUnsigned32 dgThreads::GetPerfomanceTicks (dgUnsigned32 threadIndex) const
{

    if (dgInt32 (threadIndex) <= m_numOfThreads)
    {
        return dgUnsigned32 (m_localData[threadIndex].m_ticks);
    }
    else
    {
        return 0;
    }
}

void dgThreads::CreateThreaded (dgInt32 threads)
{
    if (m_numOfThreads)
    {
        DestroydgThreads();
    }

#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    if ((threads > 1) && (m_numberOfCPUCores > 1))
    {
        m_numOfThreads = GetMin (threads, m_numberOfCPUCores);

        m_emptySlot = CreateSemaphoreA(NULL, DG_MAXQUEUE, DG_MAXQUEUE, NULL);
        m_workToDo = CreateSemaphoreA(NULL,0, DG_MAXQUEUE, NULL);
        m_exit = CreateEventA(NULL, TRUE, FALSE, NULL);

        InitializeCriticalSection(&m_criticalSection);

        m_topIndex = 0;
        m_bottomIndex = 0;
        m_workInProgress = 0;
        for(dgInt32 i=0; i < m_numOfThreads; i++)
        {
            m_threadhandles[i] = (HANDLE) _beginthreadex( NULL, 0, ThreadExecute, &m_localData[i], 0, NULL);
        }
    }
#endif
#endif


#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    if ((threads > 1) && (m_numberOfCPUCores > 1))
    {
#ifdef _MAC_IPHONE
        m_numOfThreads = 0;
#else
        m_numOfThreads = (threads<m_numberOfCPUCores ? threads : m_numberOfCPUCores);
#endif

        m_emptySlot = DG_MAXQUEUE;
        m_workToDo = 0;
        m_workToDoSpinLock = 0;
        m_exit = false;
        m_criticalSection = 0;

        m_topIndex = 0;
        m_bottomIndex = 0;
        m_workInProgress = 0;

#ifndef _MAC_IPHONE
        for(dgInt32 i=0; i < m_numOfThreads; i++)
        {
            pthread_create( &m_threadhandles[i], NULL, ThreadExecute, &m_localData[i]);
        }
#endif
    }
#endif
}


void dgThreads::DestroydgThreads()
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    _ASSERTE (m_workInProgress == 0);

    while(m_workInProgress > 0)
    {
        Sleep(10);
    }
    SetEvent(m_exit);
    DeleteCriticalSection(&m_criticalSection);
    WaitForMultipleObjects(DWORD(m_numOfThreads), m_threadhandles, TRUE, INFINITE);

    for(dgInt32 i=0; i< m_numOfThreads; i++)
    {
        CloseHandle(m_threadhandles[i]);
    }

    CloseHandle (m_exit);
    CloseHandle (m_emptySlot);
    CloseHandle (m_workToDo);

    m_exit = NULL;
    m_emptySlot = NULL;
    m_workToDo = NULL;
    memset (&m_criticalSection, 0, sizeof (CRITICAL_SECTION));
    for(dgInt32 i=0; i < m_numOfThreads; i++)
    {
        m_threadhandles[i] = NULL;
    }

    m_topIndex = 0;
    m_bottomIndex = 0;
    m_workInProgress = 0;
    m_numOfThreads = 0;
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))

    while(m_workInProgress > 0)
    {
        usleep(100000);
    }
    dgSpinLock( &m_criticalSection );
    m_exit = true;
    m_workToDo = DG_MAXQUEUE+1;
    dgSpinUnlock( &m_criticalSection );

#ifndef _MAC_IPHONE
    for(dgInt32 i=0; i<m_numOfThreads; i++ )
    {
        pthread_join( m_threadhandles[i], NULL );
    }
#endif

    m_exit = false;
    m_emptySlot = 0;
    m_workToDo = 0;
    m_workToDoSpinLock = 0;

    m_topIndex = 0;
    m_bottomIndex = 0;
    m_workInProgress = 0;
    m_numOfThreads = 0;
#endif
}



//Queues up another to work
dgInt32 dgThreads::SubmitJob(dgWorkerThread* const job)
{
    if (!m_numOfThreads)
    {
        _ASSERTE (job->m_threadIndex != -1);
        job->ThreadExecute();
    }
    else
    {

#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
        dgInterlockedIncrement(&m_workInProgress);
        if(WaitForSingleObject(m_emptySlot,INFINITE) != WAIT_OBJECT_0)
        {
            return(0);
        }

        EnterCriticalSection(&m_criticalSection);
        m_queue[m_topIndex] = job;
        m_topIndex = (m_topIndex + 1) % DG_MAXQUEUE;
        ReleaseSemaphore(m_workToDo,1,NULL);
        LeaveCriticalSection(&m_criticalSection);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
        dgInterlockedIncrement(&m_workInProgress);
        while ( m_emptySlot == 0 )
        {
            dgThreadYield();
        }
        dgInterlockedDecrement( &m_emptySlot );

        dgSpinLock(&m_criticalSection);
        m_queue[m_topIndex] = job;
        m_topIndex = (m_topIndex + 1) % DG_MAXQUEUE;
        dgInterlockedIncrement( &m_workToDo );
        dgSpinUnlock( &m_criticalSection );
#endif
    }
    return 1;
}



#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
dgUnsigned32 _stdcall dgThreads::ThreadExecute(void *param)
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
void* dgThreads::ThreadExecute(void *param)
#endif
{
    dgLocadData& data = *(dgLocadData*) param;
    data.m_manager->DoWork(data.m_threadIndex);
    return 0;
}


dgInt32  dgThreads::GetWork(dgWorkerThread** job)
{
#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    HANDLE hWaitHandles[2];
    hWaitHandles[0] = m_workToDo;
    hWaitHandles[1] = m_exit;

    if((WaitForMultipleObjects(2, hWaitHandles, FALSE,INFINITE) - WAIT_OBJECT_0) == 1)
    {
        return 0;
    }

    EnterCriticalSection(&m_criticalSection);
    *job = m_queue[m_bottomIndex];
    m_bottomIndex = (m_bottomIndex + 1) % DG_MAXQUEUE;
    ReleaseSemaphore(m_emptySlot,1,NULL);
    LeaveCriticalSection(&m_criticalSection);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    for (;;)
    {
        while ( m_workToDo == 0 )
        {
            dgThreadYield();
        }
        dgSpinLock( &m_workToDoSpinLock );
        if ( m_workToDo > 0 )
        {
            break;
        }
        dgSpinUnlock( &m_workToDoSpinLock );
    }
    dgInterlockedDecrement( &m_workToDo );
    dgSpinUnlock( &m_workToDoSpinLock );
    if ( m_exit )
    {
        return 0;
    }

    dgSpinLock( &m_criticalSection );
    dgWorkerThread* cWorker = m_queue[m_bottomIndex];
    *job = cWorker;

    m_bottomIndex = (m_bottomIndex+1) % (DG_MAXQUEUE);
    dgInterlockedIncrement( &m_emptySlot );
    dgSpinUnlock( &m_criticalSection );
#endif

    return 1;
}


void dgThreads::DoWork(dgInt32 mythreadIndex)
{
    dgWorkerThread* job;


#if (defined (_WIN_32_VER) || defined (_WIN_64_VER))
#ifndef __USE_DOUBLE_PRECISION__
    dgUnsigned32 controlWorld;
    controlWorld = dgControlFP (0xffffffff, 0);
    dgControlFP (_PC_53, _MCW_PC);
#endif
#endif

    if (!m_getPerformanceCount)
    {
        while(GetWork(&job))
        {
            job->ThreadExecute();
            dgInterlockedDecrement(&m_workInProgress);
        }
    }
    else
    {
        while(GetWork(&job))
        {
            dgUnsigned32 ticks = m_getPerformanceCount();

            job->ThreadExecute();
            dgInterlockedDecrement(&m_workInProgress);

            m_localData[mythreadIndex].m_ticks += (m_getPerformanceCount() - ticks);
        }
    }

#if (defined (_WIN_32_VER) || defined (_WIN_64_VER))
#ifndef __USE_DOUBLE_PRECISION__
    dgControlFP (controlWorld, _MCW_PC);
#endif
#endif

}


void dgThreads::SynchronizationBarrier ()
{
    while(m_workInProgress)
    {
        dgThreadYield();
    }
}


void dgThreads::CalculateChunkSizes (dgInt32 elements, dgInt32* const chunkSizes) const
{
    dgInt32 step;
    dgInt32 fraction;

    if (m_numOfThreads)
    {
        step = elements / m_numOfThreads;
        fraction = elements - step * m_numOfThreads;
        for (dgInt32 i = 0 ; i < m_numOfThreads; i ++)
        {
            chunkSizes[i] = step + (fraction > 0);
            fraction --;
        }
    }
    else
    {
        chunkSizes[0] = elements;
    }
}


void dgThreads::dgGetLock() const
{
    _ASSERTE (sizeof (dgInt32) == sizeof (long));
    dgSpinLock( &m_globalSpinLock );

    //spinLock( &m_globalSpinLock );
// linux and mac may need to yeald time
//   while(! __sync_bool_compare_and_swap(&m_globalSpinLock, 0, 1) ) {
//      ThreadYield();
//   }
}

void dgThreads::dgReleaseLock() const
{
    dgSpinUnlock (&m_globalSpinLock);
}

void dgThreads::dgGetIndirectLock(dgInt32* lockVar)
{
    _ASSERTE (sizeof (dgInt32) == sizeof (long));
    dgSpinLock(lockVar);
}

void dgThreads::dgReleaseIndirectLock(dgInt32* lockVar)
{
    _ASSERTE (sizeof (dgInt32) == sizeof (long));
    dgSpinUnlock (lockVar);
}



source\core\dgThreads.h :
Code: Select all
/* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

#if !defined(AFX_DG_THREADS_42YH_HY78GT_YHJ63Y__INCLUDED_)
#define AFX_DG_THREADS_42YH_HY78GT_YHJ63Y__INCLUDED_

#define DG_MAXQUEUE      16

#if (defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
#ifdef _POSIX_THREADS
#define _WIN_POSIX_VER
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#endif
#endif


class dgWorkerThread
{
public:
    dgWorkerThread()
    {
        m_threadIndex = -1;
    }
    virtual void ThreadExecute() = 0;
    virtual ~dgWorkerThread () {}

    dgInt32 m_threadIndex;
};


class dgThreads
{
public:
    dgThreads();
    ~dgThreads();

    void CreateThreaded (dgInt32 threadCount);
    void DestroydgThreads();

    void ClearTimers();
    void SetPerfomanceCounter(OnGetPerformanceCountCallback callback);
    dgUnsigned32 GetPerfomanceTicks (dgUnsigned32 threadIndex) const;

    dgInt32 GetThreadCount() const ;
    dgInt32 SubmitJob(dgWorkerThread* const job);
    void SynchronizationBarrier ();
    void CalculateChunkSizes (dgInt32 elements, dgInt32* const chunkSizes) const;

    void dgGetLock() const;
    void dgReleaseLock() const;

    void dgGetIndirectLock(dgInt32* lockVar);
    void dgReleaseIndirectLock(dgInt32* lockVar);

private:
    struct dgLocadData
    {
        dgInt32 m_ticks;
        dgInt32 m_threadIndex;
        dgThreads* m_manager;
    };

    void DoWork(dgInt32 threadIndex);
    dgInt32 GetWork(dgWorkerThread** cWork);

#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    static dgUnsigned32 _stdcall ThreadExecute(void *Param);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    static void* ThreadExecute(void *Param);
#endif

    dgInt32 m_numOfThreads;
    dgInt32 m_numberOfCPUCores;
    dgInt32 m_topIndex;
    dgInt32 m_bottomIndex;
    dgInt32 m_workInProgress;
    mutable dgInt32 m_globalSpinLock;

#ifndef _WIN_POSIX_VER
#if (defined (_WIN_32_VER) || defined (_WIN_64_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    HANDLE m_exit;
    HANDLE m_workToDo;
    HANDLE m_emptySlot;
    CRITICAL_SECTION m_criticalSection;
    dgWorkerThread* m_queue[DG_MAXQUEUE];
    HANDLE m_threadhandles[DG_MAXIMUN_THREADS];
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    bool m_exit;
    dgInt32 m_emptySlot;
    dgInt32 m_workToDo;
    dgInt32 m_criticalSection;
    dgInt32 m_workToDoSpinLock;
    dgWorkerThread* m_queue[DG_MAXQUEUE];
    pthread_t m_threadhandles[DG_MAXIMUN_THREADS];
#endif

    OnGetPerformanceCountCallback m_getPerformanceCount;
    dgLocadData m_localData[DG_MAXIMUN_THREADS];
};



#endif



packages\dContainers\dThread.cpp :
Code: Select all
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/

#include "dContainersStdAfx.h"
#include "dThread.h"


#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
#include <process.h>
#include <Windows.h>
#include <crtdbg.h>
#endif


static inline void dInterlockedIncrement (int* const Addend )
{
#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    __sync_fetch_and_add ((int32_t*)Addend, 1 );
#endif

#if (defined (_MAC_VER))
    OSAtomicAdd32 (1, (int32_t*)Addend);
#endif

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    InterlockedIncrement((long*) Addend);
#endif
#endif
}


static inline void dInterlockedDecrement(int* const Addend)
{
#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    __sync_fetch_and_sub ((int32_t*)Addend, 1 );
#endif

#if (defined (_MAC_VER))
    OSAtomicAdd32 (-1, (int32_t*)Addend);
#endif

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    InterlockedDecrement((long*) Addend);
#endif
#endif
}


static inline int dInterlockedExchange (int* spin, int testValue)
{
#if (defined (_LINUX_VER) || defined (_WIN_POSIX_VER))
    return __sync_val_compare_and_swap((int32_t*)spin, !testValue, testValue);
#endif

#if (defined (_MAC_VER))
    return !OSAtomicCompareAndSwap32(!testValue, testValue, (int32_t*) spin);
#endif

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    return InterlockedExchange ((long*) spin, testValue);
#endif
#endif
}


dThread::dThread(void)
    :m_taskSuspendedCount (1), m_taskExecuting (1), m_terminated(0)
{
//m_taskSuspendedCount = 1;

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    m_threadhandle = _beginthreadex( NULL, 0, TaskCallback, this, 0, NULL);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    pthread_create( &m_threadhandle, NULL, TaskCallback, this);
#endif
}

dThread::~dThread(void)
{
    if (!m_terminated)
    {
        TerminateTask ();
    }
}

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
unsigned _stdcall dThread::TaskCallback(void *param)
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
void* dThread::TaskCallback(void *param)
#endif
{
    dThread* const me = (dThread*) param;
    me->ExcuteTask();
    return 0;
}


void dThread::TerminateTask ()
{
    dInterlockedExchange((int*) &m_terminated, 1);
    while (m_taskExecuting)
    {
        YieldTime();
    }
}


void dThread::ContinueExecution ()
{
    dInterlockedDecrement((int*) &m_taskSuspendedCount);
    _ASSERTE (!(m_taskSuspendedCount & 0x80000000));
}


void dThread::StopsExecution ()
{
    dInterlockedIncrement((int*) &m_taskSuspendedCount);
    _ASSERTE (!(m_taskSuspendedCount & 0x80000000));
    while (m_taskExecuting)
    {
        YieldTime();
    }
}


void dThread::ExcuteTask()
{
    while (!m_terminated)
    {
        if (m_taskSuspendedCount)
        {
            dInterlockedExchange((int*) &m_taskExecuting, 0);
            //WaitForSingleObject(m_controlKey, INFINITE);
            while (m_taskSuspendedCount)
            {
                if (m_terminated)
                {
                    break;
                }
                YieldTime();
            }
        }
        dInterlockedExchange((int*) &m_taskExecuting, 1);
        RunMyTask ();
        YieldTime();
    }
    dInterlockedExchange((int*) &m_taskExecuting, 0);
}


void dThread::YieldTime()
{
#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    Sleep(0);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    sched_yield();
#endif
}


void dThread::Lock(unsigned& lockVar)
{
    _ASSERTE (sizeof (unsigned) == sizeof (long));
    while (dInterlockedExchange((int*) &lockVar, 1))
    {
        YieldTime();
    }
}


void dThread::Unlock(unsigned& lockVar)
{
    _ASSERTE (sizeof (unsigned) == sizeof (long));
    lockVar = 0;
}



packages\dContainers\dThread.h :
Code: Select all
/* Copyright (c) <2009> <Newton Game Dynamics>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely
*/


#ifndef __DTHREAD_H__
#define __DTHREAD_H__


#if (defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
#ifdef _POSIX_THREADS
#define _WIN_POSIX_VER
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#endif
#endif


class dThread
{
public:
    dThread(void);
    virtual ~dThread(void);

    virtual unsigned RunMyTask ()
    {
        return 1;
    }

    void ContinueExecution ();
    void StopsExecution ();
    void TerminateTask ();

    void YieldTime();
    void Lock(unsigned& lockVar);
    void Unlock(unsigned& lockVar);

private:
    void ExcuteTask();

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    static unsigned _stdcall TaskCallback(void *param);
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    static void* TaskCallback(void *Param);
#endif


    unsigned m_taskSuspendedCount;
    unsigned m_taskExecuting;
    unsigned m_terminated;

#ifndef _WIN_POSIX_VER
#if (defined (_MSC_VER) || defined (_MINGW_32_VER) || defined (_MINGW_64_VER))
    uintptr_t m_threadhandle;
#endif
#endif

#if (defined (_LINUX_VER) || defined (_MAC_VER) || defined (_WIN_POSIX_VER))
    pthread_t m_threadhandle;
#endif
};

#endif



Cheers!
Jay
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Easily switchable threading system at compile time

Postby Julio Jerez » Sat Apr 02, 2011 3:30 pm

is that a Pacth? or how to I use the files do I have ot merge then by hand?
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Easily switchable threading system at compile time

Postby jay3d » Sat Apr 02, 2011 3:54 pm

Julio Jerez wrote:is that a Pacth? or how to I use the files do I have ot merge then by hand?


U can replace the files, or use diff tool fo find what changed ;)

Sorry if it make additional trouble i though this way is easier to apply without errors

Cheers!
Jay
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Cleaning up patch

Postby jay3d » Thu Nov 03, 2011 8:16 am

Dear Julio :)

I got a pretty big patch right now, and here's what's going on with it, and what changed:

- Cleaned up the conditional compilation macros to take advantage as much as possible of the built in platform and compiler defined symbols as follows:
Eliminate all *_VER defines (except _MSC_VER of course) with built in defines:
__x86_64__ is defined in all GCC based compilers (Linux, OS X, MinGW) for 64-bit platforms
_WIN32 is defined in MSVC and MinGW compilers for both 32-bit and 64-bit Windows platforms, with the additional _WIN64 to indicate compiling for Windows 64-bit
__APPLE__ is defined when compiling for OS X platforms (10.6+), with the additional TARGET_OS_IPHONE when compiling for iOS devices

- Fixed the cpuid function to work under Linux and MinGW compilers for both 32-bit and 64-bit
- Using _MSC_VER instead for MSVC specific compiler features instead of platform conditional macros (solves MinGW compatibility and makes it smarter to be detected, re-enabled __forceinline)
- Newton will be built as a shared library for all platforms by default (DLL in Windows, and .so or .dylib for Linux and OS X respectively) without the need for a special compiler symbol, to build a static library on all platforms the _NEWTON_STATIC_LIB has to be defined
- Many other minor fixes and code formatting

Please review the patch and see if it can be merged into the code if u see it's fine, and if u like the code formatting introduced in dgTypes.h header

I moved my development to Eclipse CDT IDE, because it was the superior IDE with better code completion and debugging features, and will contribute the eclipse project or makefile for MinGW compilers

I'm trying to make comments in Newton compatible with Doxygen so we can get a nice documentation file in the end ;)

Cheers!
Jay
Attachments
NGD.7z
(100.39 KiB) Downloaded 324 times
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Easily switchable threading system at compile time

Postby Julio Jerez » Thu Nov 03, 2011 12:04 pm

I like that It will deal with the issues with ming winG.

Ok I tried to apply the patch, but I made some changes that are giving me ton of merging errors (red file that need to be merge manually).
I do not think you made that many changes, must liketly I made the changes after the patch, It will be eassier for me if you sync to SVN and make the patch again.
I will not check it more code for today.

[quote="I'm trying to make comments in Newton compatible with Doxygen so we can get a nice documentation file in the end ;)Jay[/quote]
That will be so awesome, :D
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Easily switchable threading system at compile time

Postby jay3d » Fri Nov 04, 2011 2:03 am

The patch now synced to the latest revision, hope it will merge without problem :)

I will put here, because there's some limitation on file size in phpBB

http://www.mediafire.com/?0anoakmmavnejlc
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Cleaning up patch

Postby Julio Jerez » Fri Nov 04, 2011 8:26 am

done, it went without a hitch.
That was a bit patch thank you

on this
jay3d wrote:- Newton will be built as a shared library for all platforms by default (DLL in Windows, and .so or .dylib for Linux and OS X respectively) without the need for a special compiler symbol, to build a static library on all platforms the _NEWTON_STATIC_LIB has to be defined
Jay


did you change the Linux makefile and the Mac projects as well?

I believe these changes have to be made for core 300 as well, I am focusing more in that, than with core 200
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Cleaning up patch

Postby jay3d » Fri Nov 04, 2011 8:35 am

Julio Jerez wrote:did you change the Linux makefile and the Mac projects as well?


Not yet, will do it.

I will check out the 300 sources to apply those changes

Cheers!
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Cleaning up patch

Postby Julio Jerez » Fri Nov 04, 2011 10:16 am

jay3d wrote:I will check out the 300 sources to apply those changesCheers!

that will be awesome.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Easily switchable threading system at compile time

Postby jay3d » Fri Nov 04, 2011 10:46 am

:)

As a coding style suggestion: can we use 2 spaces instead of tabs with 4 spaces for indenting code?
and indenting macros as this:

Code: Select all
#if A
#  define B
#  if C
#    define D
#  else
#    define E
#  endif // C
#endif // A


instead of

Code: Select all
#if A
  #define B
  #if C
    #define D
  #else
    #define E
  #endif
#endif
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Easily switchable threading system at compile time

Postby Julio Jerez » Fri Nov 04, 2011 11:07 am

we can, but why?
any particular reason?
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Easily switchable threading system at compile time

Postby jay3d » Fri Nov 04, 2011 1:00 pm

Julio Jerez wrote:we can, but why?
any particular reason?


1. Tab spaces differences on many code editors

2. For macros using this style of indenting will protect the code formatting of macros and yields clearer macros code without the cluttering # symbol

this is just a suggestion though :)
jay3d
 
Posts: 33
Joined: Sun Jul 13, 2008 11:51 am

Re: Easily switchable threading system at compile time

Postby Julio Jerez » Fri Nov 04, 2011 1:42 pm

Ok let us do that.

I do not promise I will avide by it, I have being coding for too long usin tabs so it is hard fo rme to follow,
but I am very flexibvel on teh format stuff.

In fact itis my exprecend that is large team imposing a file format si teh primary cause of conflit amoun member of teh gruos.
In general code stile is the result of teh ego or few member of eth team that are imcamopale of adapting to teh stule of oethe people.

coding styile do not really add or remove anything to the code, so I do not care about code stype.

spaces is fine with me.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 11 guests