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.
o3de/Code/CryEngine/CrySystem/SyncLock.cpp

247 lines
5.0 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.
#include "CrySystem_precompiled.h"
#include "ProjectDefines.h"
#if defined(MAP_LOADING_SLICING)
#include "SyncLock.h"
SSyncLock::SSyncLock(const char* name, int id, bool own)
{
stack_string ss;
ss.Format("%s_%d", name, id);
Open(ss);
if (own)
{
if (!IsValid())
{
Create(ss);
number = id;
}
else
{
Close();
}
}
else
{
number = id;
}
}
SSyncLock::SSyncLock(const char* name, int minId, int maxId)
{
ev = 0;
stack_string ss;
for (int i = minId; i < maxId; ++i)
{
ss.Format("%s_%d", name, i);
if (Open(ss))
{
Close();
continue;
}
if (Create(ss))
{
number = i;
}
break;
}
}
SSyncLock::~SSyncLock()
{
Close();
}
void SSyncLock::Own(const char* name)
{
o_name.Format("%s_%d", name, number);
}
#if defined(LINUX) || defined(APPLE)
bool SSyncLock::Open(const char* name)
{
ev = sem_open(name, 0);
if (ev != SEM_FAILED)
{
CryLogAlways("Opened semaphore %p %s", ev, name);
}
return IsValid();
}
bool SSyncLock::Create(const char* name)
{
ev = sem_open(name, O_CREAT | O_EXCL, 0777, 0);
if (ev != SEM_FAILED)
{
CryLogAlways("Created semaphore %p %s", ev, name);
}
else
{
CryLogAlways("Failed to create semaphore %s %d", name, errno);
}
return IsValid();
}
void SSyncLock::Signal()
{
if (ev)
{
sem_post(ev);
}
}
bool SSyncLock::Wait(int ms)
{
if (!ev)
{
return false;
}
timespec t = { 0 };
#if defined(LINUX)
clock_gettime(CLOCK_REALTIME, &t);
#elif defined(APPLE)
// On OSX/iOS there is no sem_timedwait()
// We use repeated sem_trywait() instead
if (sem_trywait(ev) == 0)
{
return true;
}
#endif
static const long NANOSECS_IN_MSEC = 1000000L;
static const long NANOSECS_IN_SEC = 1000000000L;
t.tv_sec += ms / 1000;
t.tv_nsec += (ms % 1000) * NANOSECS_IN_MSEC;
if (t.tv_nsec > NANOSECS_IN_SEC)
{
t.tv_nsec -= NANOSECS_IN_SEC;
++t.tv_sec;
}
#if defined(LINUX)
return sem_timedwait(ev, &t) == 0; //ETIMEDOUT for timeout
#elif defined (APPLE)
// t = time left, interval = max time between tries, elapsed = actual time elapsed during a try
const int num_ms_interval = 50; // poll time, in ms
const timespec interval = { 0, NANOSECS_IN_MSEC * num_ms_interval };
while (t.tv_sec >= 0 || t.tv_nsec > interval.tv_nsec)
{
timespec remaining;
timespec elapsed = interval;
if (nanosleep(&interval, &remaining) == -1)
{
elapsed.tv_nsec -= remaining.tv_nsec;
}
t.tv_nsec -= elapsed.tv_nsec;
if (t.tv_nsec < 0L)
{
t.tv_nsec += NANOSECS_IN_SEC;
t.tv_sec -= 1;
}
if (sem_trywait(ev) == 0)
{
return true;
}
}
nanosleep(&t, NULL);
return sem_trywait(ev) == 0;
#else
#error Not implemented
#endif
}
void SSyncLock::Close()
{
if (ev)
{
sem_close(ev);
ev = nullptr;
if (!o_name.empty())
{
sem_unlink(o_name);
}
}
}
#else // defined(LINUX) || defined(APPLE)
bool SSyncLock::Open(const char* name)
{
ev = OpenEvent(SYNCHRONIZE, FALSE, name);
if (ev)
{
CryLogAlways("Opened event %p %s", ev, name);
}
return IsValid();
}
bool SSyncLock::Create(const char* name)
{
ev = CreateEvent(NULL, FALSE, FALSE, name);
if (ev)
{
CryLogAlways("Created event %p %s", ev, name);
}
else
{
CryLogAlways("Failed to create event %s", name);
}
return IsValid();
}
bool SSyncLock::Wait(int ms)
{
// CryLogAlways("Waiting %p", ev);
DWORD res = WaitForSingleObject(ev, ms);
if (res != WAIT_OBJECT_0)
{
CryLogAlways("WFS result %d", res);
}
return res == WAIT_OBJECT_0;
}
void SSyncLock::Signal()
{
//CryLogAlways("Signaled %p", ev);
if (!SetEvent(ev))
{
CryLogAlways("Error signalling!");
}
}
void SSyncLock::Close()
{
if (ev)
{
CryLogAlways("Closed event %p", ev);
CloseHandle(ev);
ev = 0;
}
}
#endif // defined(LINUX) || defined(APPLE)
bool SSyncLock::IsValid() const
{
return ev != 0;
}
#endif // defined(MAP_LOADING_SLICING)