mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
211 lines
6.1 KiB
C++
211 lines
6.1 KiB
C++
// (C) Copyright Mac Murrett 2001.
|
|
// Use, modification and distribution are subject to the
|
|
// Boost Software License, Version 1.0. (See accompanying file
|
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
// See http://www.boost.org for most recent version.
|
|
|
|
#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
|