SCSIParallelTimer.cpp [plain text]
#include <IOKit/IOTypes.h>
#include "SCSIParallelTimer.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "SPI TIMER"
#if DEBUG
#define SCSI_PARALLEL_TIMER_DEBUGGING_LEVEL 0
#endif
#include "IOSCSIParallelFamilyDebugging.h"
#if ( SCSI_PARALLEL_TIMER_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) panic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_PARALLEL_TIMER_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_PARALLEL_TIMER_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#define super IOTimerEventSource
OSDefineMetaClassAndStructors ( SCSIParallelTimer, IOTimerEventSource );
#if 0
#pragma mark -
#pragma mark IOKit Member Routines
#pragma mark -
#endif
SCSIParallelTimer *
SCSIParallelTimer::CreateTimerEventSource ( OSObject * owner, Action action )
{
SCSIParallelTimer * timer = NULL;
timer = OSTypeAlloc ( SCSIParallelTimer );
require_nonzero ( timer, ErrorExit );
require ( timer->Init ( owner, action ), FreeTimer );
return timer;
FreeTimer:
require_nonzero ( timer, ErrorExit );
timer->release ( );
timer = NULL;
ErrorExit:
return timer;
}
bool
SCSIParallelTimer::Init ( OSObject * owner, Action action )
{
queue_init ( &fListHead );
return super::init ( owner, action );
}
void
SCSIParallelTimer::Enable ( void )
{
super::enable ( );
}
void
SCSIParallelTimer::Disable ( void )
{
super::disable ( );
}
void
SCSIParallelTimer::CancelTimeout ( void )
{
super::cancelTimeout ( );
}
void
SCSIParallelTimer::BeginTimeoutContext ( void )
{
closeGate ( );
fHandlingTimeout = true;
openGate ( );
}
void
SCSIParallelTimer::EndTimeoutContext ( void )
{
closeGate ( );
fHandlingTimeout = false;
openGate ( );
}
SInt32
SCSIParallelTimer::CompareDeadlines ( AbsoluteTime time1, AbsoluteTime time2 )
{
return CMP_ABSOLUTETIME ( &time1, &time2 );
}
AbsoluteTime
SCSIParallelTimer::GetDeadline ( SCSIParallelTask * task )
{
check ( task != NULL );
return task->GetTimeoutDeadline ( );
}
UInt32
SCSIParallelTimer::GetTimeoutDuration ( SCSIParallelTask * task )
{
check ( task != NULL );
return task->GetTimeoutDuration ( );
}
SCSIParallelTaskIdentifier
SCSIParallelTimer::GetExpiredTask ( void )
{
SCSIParallelTask * expiredTask = NULL;
closeGate ( );
if ( queue_empty ( &fListHead ) == false )
{
uint64_t now;
AbsoluteTime deadline1;
AbsoluteTime deadline2;
SCSIParallelTask * task;
task = ( SCSIParallelTask * ) queue_first ( &fListHead );
now = mach_absolute_time ( );
deadline1 = *( AbsoluteTime * ) &now;
deadline2 = GetDeadline ( task );
if ( CompareDeadlines ( deadline1, deadline2 ) == 1 )
{
queue_remove_first ( &fListHead, expiredTask, SCSIParallelTask *, fTimeoutChain );
}
}
openGate ( );
return ( SCSIParallelTaskIdentifier ) expiredTask;
}
IOReturn
SCSIParallelTimer::SetTimeout ( SCSIParallelTaskIdentifier taskIdentifier,
UInt32 inTimeoutMS )
{
SCSIParallelTask * task = ( SCSIParallelTask * ) taskIdentifier;
IOReturn status = kIOReturnBadArgument;
AbsoluteTime deadline;
require_nonzero ( task, ErrorExit );
closeGate ( );
if ( inTimeoutMS == kTimeoutValueNone )
{
inTimeoutMS = GetTimeoutDuration ( task );
if ( inTimeoutMS == kTimeoutValueNone )
{
inTimeoutMS = 0xFFFFFFFF;
}
}
clock_interval_to_deadline ( inTimeoutMS, kMillisecondScale, &deadline );
task->SetTimeoutDeadline ( deadline );
if ( ( queue_empty ( &fListHead ) == true ) ||
( CompareDeadlines ( GetDeadline ( ( SCSIParallelTask * ) queue_first ( &fListHead ) ), deadline ) == 1 ) )
{
queue_enter_first ( &fListHead, task, SCSIParallelTask *, fTimeoutChain );
Rearm ( );
}
else if ( CompareDeadlines ( deadline, GetDeadline ( ( SCSIParallelTask * ) queue_last ( &fListHead ) ) ) == 1 )
{
queue_enter ( &fListHead, task, SCSIParallelTask *, fTimeoutChain );
}
else
{
SCSIParallelTask * currentTask = NULL;
bool slotFound = false;
queue_iterate ( &fListHead, currentTask, SCSIParallelTask *, fTimeoutChain )
{
if ( CompareDeadlines ( GetDeadline ( currentTask ), deadline ) == 1 )
{
queue_insert_before ( &fListHead, task, currentTask, SCSIParallelTask *, fTimeoutChain );
slotFound = true;
break;
}
}
if ( slotFound == false )
{
queue_enter ( &fListHead, task, SCSIParallelTask *, fTimeoutChain );
}
}
openGate ( );
status = kIOReturnSuccess;
ErrorExit:
return status;
}
void
SCSIParallelTimer::RemoveTask ( SCSIParallelTaskIdentifier parallelRequest )
{
SCSIParallelTask * task = NULL;
bool headOfList = false;
task = OSDynamicCast ( SCSIParallelTask, parallelRequest );
require_nonzero ( task, Exit );
require_nonzero ( ( task->fTimeoutChain.next ), Exit );
require_nonzero ( ( task->fTimeoutChain.prev ), Exit );
closeGate ( );
require ( ( queue_empty ( &fListHead ) == false ), ExitGate );
if ( task == ( SCSIParallelTask * ) queue_first ( &fListHead ) )
headOfList = true;
queue_remove ( &fListHead, task, SCSIParallelTask *, fTimeoutChain );
if ( headOfList == true )
{
Rearm ( );
}
ExitGate:
openGate ( );
Exit:
return;
}
bool
SCSIParallelTimer::Rearm ( void )
{
bool result = false;
closeGate ( );
if ( ( queue_empty ( &fListHead ) == false ) && ( fHandlingTimeout == false ) )
{
wakeAtTime ( GetDeadline ( ( SCSIParallelTask * ) queue_first ( &fListHead ) ) );
result = true;
}
else
{
cancelTimeout ( );
}
openGate ( );
return result;
}