include/foundation/PxThread.h

File members: include/foundation/PxThread.h

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2024 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.

#ifndef PX_THREAD_H
#define PX_THREAD_H

#include "foundation/PxUserAllocated.h"

// todo: these need to go somewhere else
// PT: looks like this is still used on some platforms

#if PX_WINDOWS_FAMILY
#define PxSpinLockPause() __asm pause
#elif PX_LINUX || PX_APPLE_FAMILY || PX_SWITCH
#define PxSpinLockPause() asm("nop")
#else
#error "Platform not supported!"
#endif

#if !PX_DOXYGEN
namespace physx
{
#endif

struct PxThreadPriority
{
    enum Enum
    {
        eHIGH         = 0,
        eABOVE_NORMAL = 1,
        eNORMAL       = 2,
        eBELOW_NORMAL = 3,
        eLOW          = 4,
        eFORCE_DWORD  = 0xffFFffFF
    };
};

class PxRunnable
{
  public:
            PxRunnable()    {}
    virtual ~PxRunnable()   {}
    virtual void execute()  {}
};

class PX_FOUNDATION_API PxThreadImpl
{
  public:
    typedef size_t Id; // space for a pointer or an integer
    typedef void* (*ExecuteFn)(void*);

    static PxU32 getDefaultStackSize();
    static Id getId();

    PxThreadImpl();

    PxThreadImpl(ExecuteFn fn, void* arg, const char* name);

    ~PxThreadImpl();

    void start(PxU32 stackSize, PxRunnable* r);

    void kill();

    void signalQuit();

    bool waitForQuit();

    bool quitIsSignalled();

    void quit();

    PxU32 setAffinityMask(PxU32 mask);

    static PxThreadPriority::Enum getPriority(Id threadId);

    void setPriority(PxThreadPriority::Enum prio);

    void setName(const char* name);

    static void sleep(PxU32 ms);

    static void yield();

    static void yieldProcessor();

    static PxU32 getNbPhysicalCores();

    static PxU32 getSize();
};

template <typename Alloc = PxReflectionAllocator<PxThreadImpl> >
class PxThreadT : protected Alloc, public PxUserAllocated, public PxRunnable
{
  public:
    typedef PxThreadImpl::Id Id; // space for a pointer or an integer

    PxThreadT(const Alloc& alloc = Alloc()) : Alloc(alloc)
    {
        mImpl = reinterpret_cast<PxThreadImpl*>(Alloc::allocate(PxThreadImpl::getSize(), PX_FL));
        PX_PLACEMENT_NEW(mImpl, PxThreadImpl)();
    }

    PxThreadT(PxThreadImpl::ExecuteFn fn, void* arg, const char* name, const Alloc& alloc = Alloc()) : Alloc(alloc)
    {
        mImpl = reinterpret_cast<PxThreadImpl*>(Alloc::allocate(PxThreadImpl::getSize(), PX_FL));
        PX_PLACEMENT_NEW(mImpl, PxThreadImpl)(fn, arg, name);
    }

    virtual ~PxThreadT()
    {
        mImpl->~PxThreadImpl();
        Alloc::deallocate(mImpl);
    }

    void start(PxU32 stackSize = PxThreadImpl::getDefaultStackSize())
    {
        mImpl->start(stackSize, this);
    }

    void kill()
    {
        mImpl->kill();
    }

    virtual void execute(void)
    {
    }

    void signalQuit()
    {
        mImpl->signalQuit();
    }

    bool waitForQuit()
    {
        return mImpl->waitForQuit();
    }

    bool quitIsSignalled()
    {
        return mImpl->quitIsSignalled();
    }

    void quit()
    {
        mImpl->quit();
    }

    PxU32 setAffinityMask(PxU32 mask)
    {
        return mImpl->setAffinityMask(mask);
    }

    static PxThreadPriority::Enum getPriority(PxThreadImpl::Id threadId)
    {
        return PxThreadImpl::getPriority(threadId);
    }

    void setPriority(PxThreadPriority::Enum prio)
    {
        mImpl->setPriority(prio);
    }

    void setName(const char* name)
    {
        mImpl->setName(name);
    }

    static void sleep(PxU32 ms)
    {
        PxThreadImpl::sleep(ms);
    }

    static void yield()
    {
        PxThreadImpl::yield();
    }

    static void yieldProcesor()
    {
        PxThreadImpl::yieldProcessor();
    }

    static PxU32 getDefaultStackSize()
    {
        return PxThreadImpl::getDefaultStackSize();
    }

    static PxThreadImpl::Id getId()
    {
        return PxThreadImpl::getId();
    }

    static PxU32 getNbPhysicalCores()
    {
        return PxThreadImpl::getNbPhysicalCores();
    }

  private:
    class PxThreadImpl* mImpl;
};

typedef PxThreadT<> PxThread;

PX_FOUNDATION_API PxU32 PxTlsAlloc();
PX_FOUNDATION_API void PxTlsFree(PxU32 index);
PX_FOUNDATION_API void* PxTlsGet(PxU32 index);
PX_FOUNDATION_API size_t PxTlsGetValue(PxU32 index);
PX_FOUNDATION_API PxU32 PxTlsSet(PxU32 index, void* value);
PX_FOUNDATION_API PxU32 PxTlsSetValue(PxU32 index, size_t value);

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif