📄 safe.cpp
字号:
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include <DriverServices.h>
#include <Events.h>
#include <Multiprocessing.h>
#include <Threads.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/thread/detail/force_cast.hpp>
#include <limits>
#include "execution_context.hpp"
using boost::detail::thread::force_cast;
namespace boost {
namespace threads {
namespace mac {
namespace detail {
static OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration);
// we call WNE to allow tasks that own the resource the blue is waiting on system
// task time, in case they are blocked on an ST remote call (or a memory allocation
// for that matter).
static void idle()
{
if(at_st())
{
EventRecord sEvent;
bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL);
}
}
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration)
{
function<OSStatus, Duration> oWaitOnSemaphore;
oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1);
return(safe_wait(oWaitOnSemaphore, lDuration));
}
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/)
{
if(pCriticalRegionCriticalRegionID != kInvalidID)
{
if(at_mp())
{
// enter the critical region's critical region
OSStatus lStatus = noErr;
AbsoluteTime sExpiration;
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
{
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
}
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
if(lStatus == noErr)
{
// calculate a new duration
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
{
// check if we have any time left
AbsoluteTime sUpTime(UpTime());
if(force_cast<uint64_t>(sExpiration) > force_cast<uint64_t>(sUpTime))
{
// reset our duration to our remaining time
lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime);
}
else
{
// no time left
lDuration = kDurationImmediate;
}
}
// if we entered the critical region, exit it again
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
assert(lStatus == noErr);
}
else
{
// otherwise, give up
return(lStatus);
}
}
else
{
// if we're at system task time, try to enter the critical region's critical
// region until we succeed. MP tasks will block on this until we let it go.
OSStatus lStatus;
do
{
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate);
} while(lStatus == kMPTimeoutErr);
assert(lStatus == noErr);
}
}
// try to enter the critical region
function<OSStatus, Duration> oEnterCriticalRegion;
oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1);
OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration);
// if we entered the critical region's critical region to get the critical region,
// exit the critical region's critical region.
if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false)
{
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
assert(lStatus == noErr);
}
return(lStatus);
}
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration)
{
function<OSStatus, Duration> oWaitOnQueue;
oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1);
return(safe_wait(oWaitOnQueue, lDuration));
}
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime)
{
if(execution_context() == k_eExecutionContextMPTask)
{
return(MPDelayUntil(pWakeUpTime));
}
else
{
uint64_t ullWakeUpTime = force_cast<uint64_t>(*pWakeUpTime);
while(force_cast<uint64_t>(UpTime()) < ullWakeUpTime)
{
idle();
}
return(noErr);
}
}
OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration)
{
if(execution_context() == k_eExecutionContextMPTask)
{
return(rFunction(lDuration));
}
else
{
uint64_t ullExpiration = 0ULL;
// get the expiration time in UpTime units
if(lDuration == kDurationForever)
{
ullExpiration = ::std::numeric_limits<uint64_t>::max();
}
else if(lDuration == kDurationImmediate)
{
ullExpiration = force_cast<uint64_t>(UpTime());
}
else
{
AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime());
ullExpiration = force_cast<uint64_t>(sExpiration);
}
OSStatus lStatus;
bool bExpired = false;
do
{
lStatus = rFunction(kDurationImmediate);
// mm - "if" #if 0'd out to allow task time to threads blocked on I/O
#if 0
if(lStatus == kMPTimeoutErr)
#endif
{
idle();
}
if(lDuration != kDurationForever)
{
bExpired = (force_cast<uint64_t>(UpTime()) < ullExpiration);
}
} while(lStatus == kMPTimeoutErr && bExpired == false);
return(lStatus);
}
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -