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) IOPanic 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;
}
void
SCSIParallelTimer::Enable ( void )
{
super::enable ( );
}
void
SCSIParallelTimer::Disable ( void )
{
super::disable ( );
}
void
SCSIParallelTimer::CancelTimeout ( void )
{
super::cancelTimeout ( );
}
SInt32
SCSIParallelTimer::CompareDeadlines ( AbsoluteTime time1, AbsoluteTime time2 )
{
return CMP_ABSOLUTETIME ( &time1, &time2 );
}
AbsoluteTime
SCSIParallelTimer::GetDeadline ( SCSIParallelTask * task )
{
check ( task != NULL );
return task->GetTimeoutDeadline ( );
}
void
SCSIParallelTimer::SetDeadline ( SCSIParallelTask * task, UInt32 inTimeoutMS )
{
AbsoluteTime delta;
AbsoluteTime deadline;
check ( task != NULL );
clock_interval_to_absolutetime_interval ( inTimeoutMS, kMillisecondScale, &delta );
clock_get_uptime ( &deadline );
ADD_ABSOLUTETIME ( &deadline, &delta );
return task->SetTimeoutDeadline ( deadline );
}
SCSIParallelTask *
SCSIParallelTimer::GetNextTask ( SCSIParallelTask * task )
{
check ( task != NULL );
return task->GetNextTimeoutTaskInList ( );
}
void
SCSIParallelTimer::SetNextTask ( SCSIParallelTask * task, SCSIParallelTask * next )
{
check ( task != NULL );
return task->SetNextTimeoutTaskInList ( next );
}
UInt32
SCSIParallelTimer::GetTimeoutDuration ( SCSIParallelTask * task )
{
check ( task != NULL );
return task->GetTimeoutDuration ( );
}
SCSIParallelTaskIdentifier
SCSIParallelTimer::GetExpiredTask ( void )
{
SCSIParallelTask * task = NULL;
closeGate ( );
if ( fTimeoutTaskListHead != NULL )
{
AbsoluteTime now;
AbsoluteTime deadline;
clock_get_uptime ( &now );
deadline = GetDeadline ( fTimeoutTaskListHead );
if ( CompareDeadlines ( now, deadline ) == 1 )
{
SCSIParallelTask * newHead = NULL;
newHead = GetNextTask ( fTimeoutTaskListHead );
task = fTimeoutTaskListHead;
SetNextTask ( task, NULL );
fTimeoutTaskListHead = newHead;
}
}
if ( fTimeoutTaskListHead == NULL )
{
cancelTimeout ( );
}
openGate ( );
return ( SCSIParallelTaskIdentifier ) task;
}
IOReturn
SCSIParallelTimer::SetTimeout ( SCSIParallelTaskIdentifier taskIdentifier,
UInt32 inTimeoutMS )
{
SCSIParallelTask * task = ( SCSIParallelTask * ) taskIdentifier;
IOReturn status = kIOReturnBadArgument;
require_nonzero ( task, ErrorExit );
closeGate ( );
if ( inTimeoutMS == kTimeoutValueNone )
{
inTimeoutMS = GetTimeoutDuration ( task );
if ( inTimeoutMS == kTimeoutValueNone )
{
inTimeoutMS = 0xFFFFFFFF;
}
}
SetDeadline ( task, inTimeoutMS );
if ( ( fTimeoutTaskListHead == NULL ) ||
( CompareDeadlines ( GetDeadline ( task ), GetDeadline ( fTimeoutTaskListHead ) ) == 1 ) )
{
SCSIParallelTask * oldHead = fTimeoutTaskListHead;
fTimeoutTaskListHead = task;
task->SetNextTimeoutTaskInList ( oldHead );
Rearm ( );
}
else
{
SCSIParallelTask * prev = fTimeoutTaskListHead;
SCSIParallelTask * next = NULL;
next = GetNextTask ( fTimeoutTaskListHead );
while ( next != NULL )
{
if ( CompareDeadlines ( GetDeadline ( next ), GetDeadline ( task ) ) == 1 )
{
SetNextTask ( task, next );
SetNextTask ( prev, task );
break;
}
prev = next;
next = GetNextTask ( next );
}
if ( next == NULL )
{
SetNextTask ( task, NULL );
SetNextTask ( prev, task );
}
}
openGate ( );
status = kIOReturnSuccess;
ErrorExit:
return status;
}
void
SCSIParallelTimer::RemoveTask ( SCSIParallelTaskIdentifier parallelRequest )
{
SCSIParallelTask * task = NULL;
SCSIParallelTask * prevTask = NULL;
require_nonzero ( OSDynamicCast ( SCSIParallelTask, parallelRequest ), Exit );
require_nonzero ( fTimeoutTaskListHead, Exit );
closeGate ( );
if ( parallelRequest == fTimeoutTaskListHead )
{
fTimeoutTaskListHead = GetNextTask ( ( SCSIParallelTask * ) parallelRequest );
}
else
{
task = GetNextTask ( fTimeoutTaskListHead );
prevTask = fTimeoutTaskListHead;
while ( task != NULL )
{
if ( task == parallelRequest )
{
SetNextTask ( prevTask, GetNextTask ( task ) );
break;
}
prevTask = task;
task = GetNextTask ( task );
}
}
openGate ( );
Rearm ( );
Exit:
return;
}
bool
SCSIParallelTimer::Rearm ( void )
{
bool result = false;
closeGate ( );
if ( fTimeoutTaskListHead != NULL )
{
wakeAtTime ( GetDeadline ( fTimeoutTaskListHead ) );
result = true;
}
openGate ( );
return result;
}