mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-02-28 11:06:09 +08:00
225 lines
6.4 KiB
C++
225 lines
6.4 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
// ON_SleepLock::IsLocked() is not reliable. Do not use it. It will be deleted in the next SDK.
|
|
bool ON_SleepLock::IsLocked() const
|
|
{
|
|
// ON_SleepLock::IsLocked() is not reliable. Do not use it. It will be deleted in the next SDK.
|
|
#if defined(ON_SLEEPLOCK_USES_STD_ATOMIC_FLAG)
|
|
const bool b = m_lockedX.test_and_set(std::memory_order_acquire);
|
|
if (false == b)
|
|
m_lockedX.clear(std::memory_order_release);
|
|
return b;
|
|
#else
|
|
return 0 != m_locked;
|
|
#endif
|
|
}
|
|
|
|
bool ON_SleepLock::GetLockOrReturnFalse()
|
|
{
|
|
// returns true if the value of the m_locked changed from 0 to 1.
|
|
// returns false if the value of m_locked was 1 and was not changed.
|
|
// In all cases, the final value of m_locked = 1.
|
|
|
|
#if defined(ON_SLEEPLOCK_USES_STD_ATOMIC_FLAG)
|
|
// std::atomic_flag.test_and_set
|
|
// does the following as an atomic operation:
|
|
// bool b = m_lockedX;
|
|
// m_lockedX = true;
|
|
// // in all cases, the final value of m_lockedX = true.
|
|
bool locked = m_lockedX.test_and_set(std::memory_order_acquire);
|
|
return (false == locked);
|
|
#else
|
|
// Windows int locked = InterlockedCompareExchange(((LONG*)(&(m_locked))), 1, 0)
|
|
// does the following as an atomic operation:
|
|
// int locked = m_locked;
|
|
// if ( 0 == m_locked )
|
|
// m_locked = 1;
|
|
// // in all cases, the final value of m_locked = 1.
|
|
int locked = InterlockedCompareExchange(((LONG*)(&(m_locked))), 1, 0);
|
|
return (0 == locked);
|
|
#endif
|
|
}
|
|
|
|
bool ON_SleepLock::ReturnLock()
|
|
{
|
|
// returns true if the input value of m_locked != 0.
|
|
// returns false of the input value of m_locked = 0.
|
|
// In all cases, the final value of m_locked = 0.
|
|
|
|
#if defined(ON_SLEEPLOCK_USES_STD_ATOMIC_FLAG)
|
|
const bool b = m_lockedX.test_and_set(std::memory_order_acquire);
|
|
m_lockedX.clear(std::memory_order_release);
|
|
return b;
|
|
#else
|
|
// Windows int locked = InterlockedExchange(((LONG*)(&(m_locked))),0);
|
|
// does the following as an atomic operation:
|
|
// int locked = m_locked;
|
|
// m_locked = 0;
|
|
// // in all cases, the final value of m_locked = 0.
|
|
int locked = InterlockedExchange(((LONG*)(&(m_locked))),0);
|
|
return (0 != locked);
|
|
#endif
|
|
}
|
|
|
|
bool ON_SleepLock::GetLock()
|
|
{
|
|
return GetLock(ON_SleepLock::DefaultWaitInterval,0);
|
|
}
|
|
|
|
bool ON_SleepLock::GetLock(
|
|
unsigned int interval_wait_msecs,
|
|
unsigned int max_wait_msecs
|
|
)
|
|
{
|
|
return GetLock(interval_wait_msecs,max_wait_msecs,false);
|
|
}
|
|
|
|
bool ON_SleepLock::GetLock(
|
|
unsigned int interval_wait_msecs,
|
|
unsigned int max_wait_msecs,
|
|
bool bStealLockAfterWaiting
|
|
)
|
|
{
|
|
// int locked = ON_IntSleepLock_Test(m_locked,0,1)
|
|
// performs the following test and assignment in
|
|
// an atomic operation.
|
|
//
|
|
// int locked = m_locked;
|
|
// if ( 0 == locked )
|
|
// m_locked = 1;
|
|
if ( GetLockOrReturnFalse() )
|
|
return true; // acquired lock
|
|
|
|
if ( interval_wait_msecs <= 0 )
|
|
interval_wait_msecs = ON_SleepLock::DefaultWaitInterval;
|
|
|
|
for(;;)
|
|
{
|
|
// Something else currently has this lock.
|
|
|
|
// ON_PointerSleepLock_SuspendThisThread() suspends the thread
|
|
// (not the process) for the specified number of milliseconds.
|
|
#if defined(ON_SLEEPLOCK_USES_STD_ATOMIC_FLAG)
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(interval_wait_msecs));
|
|
#else
|
|
// Windows - sleep the thread (not the process)
|
|
::Sleep(interval_wait_msecs);
|
|
#endif
|
|
|
|
// locked = ON_IntSleepLock_Test(m_locked,0,1)
|
|
// performs the following test and assignment in
|
|
// an atomic operation.
|
|
//
|
|
// locked = m_locked;
|
|
// if ( 0 == locked )
|
|
// m_locked = 1;
|
|
if ( GetLockOrReturnFalse() )
|
|
return true; // acquired lock
|
|
|
|
if ( max_wait_msecs > 0 )
|
|
{
|
|
if ( interval_wait_msecs >= max_wait_msecs )
|
|
{
|
|
if (bStealLockAfterWaiting)
|
|
{
|
|
// If the caller set max_wait_msecs to a value that is too small,
|
|
// has a bug in their code, then this is a bad idea,
|
|
// but it's also their own fault.
|
|
//
|
|
// If the resource is locked because another thread locked it and
|
|
// then forgot to unlock it or terminated before it could be unlocked,
|
|
// then this is a good thing because it gets this thread unblocked
|
|
// and back in business.
|
|
//
|
|
ON_WARNING("Stealing a resource lock.");
|
|
GetLockOrReturnFalse();
|
|
return true;
|
|
}
|
|
|
|
// Give up and return false.
|
|
break;
|
|
}
|
|
max_wait_msecs -= interval_wait_msecs;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
ON_SleepLockGuard::ON_SleepLockGuard(class ON_SleepLock& sleep_lock)
|
|
: m_sleep_lock(sleep_lock)
|
|
{
|
|
m_bIsManagingLock = m_sleep_lock.GetLock();
|
|
}
|
|
|
|
ON_SleepLockGuard::ON_SleepLockGuard(class ON_FixedSizePool& fsp)
|
|
: m_sleep_lock(fsp.m_sleep_lock)
|
|
{
|
|
m_bIsManagingLock = m_sleep_lock.GetLock();
|
|
}
|
|
|
|
ON_SleepLockGuard::ON_SleepLockGuard(
|
|
class ON_SleepLock& sleep_lock,
|
|
unsigned int interval_wait_msecs,
|
|
unsigned int max_wait_msecs
|
|
)
|
|
: m_sleep_lock(sleep_lock)
|
|
{
|
|
m_bIsManagingLock = sleep_lock.GetLock(interval_wait_msecs,max_wait_msecs);
|
|
}
|
|
|
|
ON_SleepLockGuard::ON_SleepLockGuard(
|
|
class ON_SleepLock& sleep_lock,
|
|
unsigned int interval_wait_msecs,
|
|
unsigned int max_wait_msecs,
|
|
bool bStealLockAfterWaiting
|
|
)
|
|
: m_sleep_lock(sleep_lock)
|
|
{
|
|
m_bIsManagingLock = sleep_lock.GetLock(interval_wait_msecs,max_wait_msecs,bStealLockAfterWaiting);
|
|
}
|
|
|
|
ON_SleepLockGuard::~ON_SleepLockGuard()
|
|
{
|
|
ReturnLock();
|
|
}
|
|
|
|
|
|
void ON_SleepLockGuard::ReturnLock()
|
|
{
|
|
if (m_bIsManagingLock)
|
|
{
|
|
m_bIsManagingLock = false;
|
|
m_sleep_lock.ReturnLock();
|
|
}
|
|
}
|
|
|
|
const bool ON_SleepLockGuard::IsManagingLock() const
|
|
{
|
|
return m_bIsManagingLock;
|
|
}
|
|
|
|
|