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