Changeset View
Changeset View
Standalone View
Standalone View
extern/opennurbs/opennurbs_sleeplock.cpp
- This file was added.
| /* $NoKeywords: $ */ | |||||
| /* | |||||
| // | |||||
| // Copyright (c) 1993-2012 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; | |||||
| } | |||||