You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
11 KiB
C++
260 lines
11 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// NOTE: INTERNAL HEADER NOT FOR PUBLIC USE
|
|
// This header should only be include by SystemThreading.cpp only
|
|
// It provides an interface for PThread intrinsics
|
|
// It's only client should be CThreadManager which should manage all thread interaction
|
|
#if !defined(INCLUDED_FROM_SYSTEM_THREADING_CPP)
|
|
# error "CRYTEK INTERNAL HEADER. ONLY INCLUDE FROM SYSTEMTHRADING.CPP."
|
|
#endif
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#define DEFAULT_THREAD_STACK_SIZE_KB 0
|
|
#define CRY_PTHREAD_THREAD_NAME_MAX 16
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// THREAD CREATION AND MANAGMENT
|
|
//////////////////////////////////////////////////////////////////////////
|
|
namespace CryThreadUtil
|
|
{
|
|
// Define type for platform specific thread handle
|
|
typedef pthread_t TThreadHandle;
|
|
|
|
struct SThreadCreationDesc
|
|
{
|
|
// Define platform specific thread entry function functor type
|
|
typedef void* (* EntryFunc)(void*);
|
|
|
|
const char* szThreadName;
|
|
EntryFunc fpEntryFunc;
|
|
void* pArgList;
|
|
uint32 nStackSizeInBytes;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TThreadHandle CryGetCurrentThreadHandle()
|
|
{
|
|
return (TThreadHandle)pthread_self();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Note: Handle must be closed lated via CryCloseThreadHandle()
|
|
TThreadHandle CryDuplicateThreadHandle(const TThreadHandle& hThreadHandle)
|
|
{
|
|
// Do not do anything
|
|
// If you add a new platform which duplicates handles make sure to mirror the change in CryCloseThreadHandle(..)
|
|
return hThreadHandle;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CryCloseThreadHandle(TThreadHandle& hThreadHandle)
|
|
{
|
|
pthread_detach(hThreadHandle);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
threadID CryGetCurrentThreadId()
|
|
{
|
|
return threadID(pthread_self());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
threadID CryGetThreadId(TThreadHandle hThreadHandle)
|
|
{
|
|
return threadID(hThreadHandle);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Note: On OSX the thread name can only be set by the thread itself.
|
|
void CrySetThreadName(TThreadHandle pThreadHandle, const char* sThreadName)
|
|
{
|
|
char threadName[CRY_PTHREAD_THREAD_NAME_MAX];
|
|
if (!cry_strcpy(threadName, sThreadName))
|
|
{
|
|
CryLog("<ThreadInfo> CrySetThreadName: input thread name '%s' truncated to '%s'", sThreadName, threadName);
|
|
}
|
|
#if AZ_TRAIT_OS_PLATFORM_APPLE
|
|
// On OSX the thread name can only be set by the thread itself.
|
|
assert(pthread_equal(pthread_self(), (pthread_t )pThreadHandle));
|
|
|
|
if (pthread_setname_np(threadName) != 0)
|
|
#else
|
|
if (pthread_setname_np(pThreadHandle, threadName) != 0)
|
|
#endif
|
|
{
|
|
switch (errno)
|
|
{
|
|
case ERANGE:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadName: Unable to rename thread \"%s\". Error Msg: \"Name to long. Exceeds %d bytes.\"", sThreadName, CRY_PTHREAD_THREAD_NAME_MAX);
|
|
break;
|
|
default:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadName: Unsupported error code: %i", errno);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CrySetThreadAffinityMask(TThreadHandle pThreadHandle, DWORD dwAffinityMask)
|
|
{
|
|
#if defined(AZ_PLATFORM_ANDROID)
|
|
// Not supported on ANDROID
|
|
// Alternative solution
|
|
// Watch out that android will clear the mask after a core has been switched off hence loosing the affinity mask setting!
|
|
// http://stackoverflow.com/questions/16319725/android-set-thread-affinity
|
|
#elif AZ_TRAIT_OS_PLATFORM_APPLE
|
|
# pragma message "Warning: <ThreadInfo> CrySetThreadAffinityMask not implemented for platform"
|
|
// Implementation details can be found here
|
|
// https://developer.apple.com/library/mac/releasenotes/Performance/RN-AffinityAPI/
|
|
#else
|
|
cpu_set_t cpu_mask;
|
|
CPU_ZERO(&cpu_mask);
|
|
for (int cpu = 0; cpu < sizeof(cpu_mask) * 8; ++cpu)
|
|
{
|
|
if (dwAffinityMask & (1 << cpu))
|
|
{
|
|
CPU_SET(cpu, &cpu_mask);
|
|
}
|
|
}
|
|
|
|
if (sched_setaffinity(0, sizeof(cpu_mask), &cpu_mask) != 0)
|
|
{
|
|
switch (errno)
|
|
{
|
|
case EFAULT:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: Supplied memory address was invalid.");
|
|
break;
|
|
case EINVAL:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The affinity bit mask [%u] contains no processors that are currently physically on the system and permitted to the process .", dwAffinityMask);
|
|
break;
|
|
case EPERM:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The calling process does not have appropriate privileges. Mask [%u].", dwAffinityMask);
|
|
break;
|
|
case ESRCH:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The process whose ID is pid could not be found.");
|
|
break;
|
|
default:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: Unsupported error code: %i", errno);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CrySetThreadPriority(TThreadHandle pThreadHandle, DWORD dwPriority)
|
|
{
|
|
int policy;
|
|
struct sched_param param;
|
|
|
|
pthread_getschedparam(pThreadHandle, &policy, ¶m);
|
|
param.sched_priority = sched_get_priority_max(dwPriority);
|
|
pthread_setschedparam(pThreadHandle, policy, ¶m);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CrySetThreadPriorityBoost(TThreadHandle pThreadHandle, bool bEnabled)
|
|
{
|
|
// Not supported
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CryCreateThread(TThreadHandle* pThreadHandle, const SThreadCreationDesc& threadDesc)
|
|
{
|
|
uint32 nStackSize = threadDesc.nStackSizeInBytes != 0 ? threadDesc.nStackSizeInBytes : DEFAULT_THREAD_STACK_SIZE_KB * 1024;
|
|
|
|
assert(pThreadHandle != reinterpret_cast<TThreadHandle*>(THREADID_NULL));
|
|
pthread_attr_t threadAttr;
|
|
sched_param schedParam;
|
|
pthread_attr_init(&threadAttr);
|
|
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_JOINABLE);
|
|
pthread_attr_setstacksize(&threadAttr, nStackSize);
|
|
|
|
const int err = pthread_create(
|
|
pThreadHandle,
|
|
&threadAttr,
|
|
threadDesc.fpEntryFunc,
|
|
threadDesc.pArgList);
|
|
|
|
// Handle error on thread creation
|
|
switch (err)
|
|
{
|
|
case 0:
|
|
// No error
|
|
break;
|
|
case EAGAIN:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"Insufficient resources to create another thread, or a system-imposed limit on the number of threads was encountered.\"", threadDesc.szThreadName);
|
|
return false;
|
|
case EINVAL:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"Invalid attribute setting for thread creation.\"", threadDesc.szThreadName);
|
|
return false;
|
|
case EPERM:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"No permission to set the scheduling policy and parameters specified in attribute setting\"", threadDesc.szThreadName);
|
|
return false;
|
|
default:
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Unknown error message. Error code %i", threadDesc.szThreadName, err);
|
|
break;
|
|
}
|
|
|
|
// Print info to log
|
|
CryComment("<ThreadInfo>: New thread \"%s\" | StackSize: %u(KB)", threadDesc.szThreadName, threadDesc.nStackSizeInBytes / 1024);
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CryThreadExitCall()
|
|
{
|
|
// Notes on: pthread_exit
|
|
// A thread that was create with pthread_create implicitly calls pthread_exit when the thread returns from its start routine (the function that was first called after a thread was created).
|
|
// pthread_exit(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FLOATING POINT EXCEPTIONS
|
|
//////////////////////////////////////////////////////////////////////////
|
|
namespace CryThreadUtil
|
|
{
|
|
///////////////////////////////////////////////////////////////////////////
|
|
void EnableFloatExceptions(EFPE_Severity eFPESeverity)
|
|
{
|
|
// TODO:
|
|
// Not implemented
|
|
// for potential implementation see http://linux.die.net/man/3/feenableexcept
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void EnableFloatExceptions(threadID nThreadId, EFPE_Severity eFPESeverity)
|
|
{
|
|
// TODO:
|
|
// Not implemented
|
|
// for potential implementation see http://linux.die.net/man/3/feenableexcept
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint GetFloatingPointExceptionMask()
|
|
{
|
|
// Not implemented
|
|
return ~0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SetFloatingPointExceptionMask(uint nMask)
|
|
{
|
|
// Not implemented
|
|
}
|
|
}
|