sl@0: /* sl@0: * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: @released sl@0: */ sl@0: #include sl@0: #include "cryptojobs.h" sl@0: sl@0: EXPORT_C TraceFunction * &TraceFunction::HeadRef() sl@0: { sl@0: static TraceFunction *sHead = 0; sl@0: return sHead; sl@0: } sl@0: sl@0: sl@0: sl@0: EXPORT_C DCryptoJobScheduler::DCryptoJobScheduler() sl@0: { sl@0: TRACE_FUNCTION("DCryptoJobScheduler"); sl@0: } sl@0: sl@0: EXPORT_C DCryptoJobScheduler::~DCryptoJobScheduler() sl@0: { sl@0: TRACE_FUNCTION("~DCryptoJobScheduler"); sl@0: // At this point the LDD channels and PDD factory/chans should sl@0: // have already been deleted... sl@0: } sl@0: sl@0: sl@0: EXPORT_C void DCryptoJobScheduler::ScheduleJob(CryptoJob *aJob) sl@0: { sl@0: TRACE_FUNCTION("ScheduleJob"); sl@0: if(aJob->iInJobList) sl@0: { sl@0: // Already in a job list sl@0: // If it is the current job and it is not running then try and schedule it sl@0: // It was probably stalled waiting for the user to read and/or write data. sl@0: if((aJob == iJobList) && (aJob->iState != CryptoJob::ERunning)) sl@0: { sl@0: // Job is not running, and is first in list, so schedule sl@0: // it without rescheduling the first job (which is us!) sl@0: Schedule(EFalse); sl@0: return; sl@0: } sl@0: // Attempt to reschedule current job, ie if it is not running sl@0: // save its state and try running a different job. sl@0: Schedule(ETrue); sl@0: return; sl@0: } sl@0: sl@0: // Not in list, so add it sl@0: aJob->iJobScheduler = this; sl@0: aJob->iNext = 0; sl@0: if(aJob->iState == CryptoJob::ECreated) sl@0: { sl@0: aJob->iState = CryptoJob::EReadyForFirstRun; sl@0: } sl@0: if(iJobList == 0) sl@0: { sl@0: // Only job sl@0: iJobList = aJob; sl@0: aJob->iInJobList = ETrue; sl@0: } sl@0: else sl@0: { sl@0: // Insert as second on list. sl@0: // sl@0: // This quick and easy to do because it does not require a sl@0: // re-schedule or a full list walk. It is slightly unfair to sl@0: // existing jobs, but usually there will only be the head job sl@0: // anyway. sl@0: CryptoJob *p = iJobList->iNext; sl@0: iJobList->iNext = aJob; sl@0: aJob->iNext = p; sl@0: aJob->iInJobList = ETrue; sl@0: } sl@0: sl@0: // Attempt re-schedule sl@0: Schedule(ETrue); sl@0: } sl@0: sl@0: EXPORT_C void DCryptoJobScheduler::DeScheduleJob(CryptoJob *aJob) sl@0: { sl@0: TRACE_FUNCTION("DeScheduleJob"); sl@0: if((aJob->iState == CryptoJob::EReady) || (aJob->iState == CryptoJob::ERunning)) sl@0: { sl@0: aJob->DoReleaseHw(); sl@0: } sl@0: sl@0: aJob->iState = CryptoJob::ECreated; sl@0: sl@0: // Hunt for and remove job from queue. sl@0: // This is a linear search, BUT the list length is probably one... sl@0: // Try and set pp to point to the pointer to the job we are removing sl@0: CryptoJob **pp = &iJobList; sl@0: while(*pp != aJob && *pp) sl@0: { sl@0: pp = &((*pp)->iNext); sl@0: } sl@0: if(*pp == aJob) sl@0: { sl@0: *pp = (*pp)->iNext; sl@0: aJob->iNext = 0; sl@0: aJob->iJobScheduler = 0; sl@0: aJob->iInJobList = EFalse; sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: EXPORT_C void DCryptoJobScheduler::SliceComplete(CryptoJob *aJob, TInt aStatus) sl@0: { sl@0: TRACE_FUNCTION("SliceComplete"); sl@0: // Need start next slice or swap to another job and start it sl@0: if(aJob != iJobList) sl@0: { sl@0: Kern::Printf("DCryptoJobScheduler::SliceComplete - not running job 0x%x=0x%x", sl@0: aJob, iJobList); sl@0: return; sl@0: } sl@0: sl@0: if(aStatus != KErrNone) sl@0: { sl@0: JobComplete(aJob, aStatus); sl@0: return; sl@0: } sl@0: sl@0: Schedule(ETrue); // Change jobs and run top one sl@0: return; sl@0: } sl@0: sl@0: sl@0: EXPORT_C void DCryptoJobScheduler::JobComplete(CryptoJob *aJob, TInt aStatus) sl@0: { sl@0: TRACE_FUNCTION("JobComplete"); sl@0: if(aJob != iJobList) sl@0: { sl@0: Kern::Printf("DCryptoJobScheduler::JobComplete - not running job 0x%x=0x%x", sl@0: aJob, iJobList); sl@0: return; sl@0: } sl@0: sl@0: // Pop job and update state sl@0: DeScheduleJob(aJob); sl@0: sl@0: aJob->iCallbacks->JobComplete(aStatus); sl@0: sl@0: Schedule(EFalse); // Run top job sl@0: } sl@0: sl@0: void DCryptoJobScheduler::Schedule(TBool aReschedule) sl@0: { sl@0: TRACE_FUNCTION("Schedule"); sl@0: if(iJobList == 0) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: if(iJobList->iState == CryptoJob::ERunning) sl@0: { sl@0: // h/w busy so can not do anything now. sl@0: return; sl@0: } sl@0: sl@0: if((iJobList->iNext == 0) && (iJobList->iState == CryptoJob::EStalled)) sl@0: { sl@0: // Only one job in list and its stalled. Leave it on the h/w sl@0: // as an optimisation. sl@0: return; sl@0: } sl@0: sl@0: if(iJobList->iNext) sl@0: { sl@0: // More than one job in list. sl@0: // If top job is stalled, or reschedule is requested then swap jobs sl@0: // Only the top job can ever be marked as EStalled. sl@0: // (Only running job can stall and new jobs get inserted second in the list) sl@0: TBool stalledJob = (iJobList->iState == CryptoJob::EStalled); sl@0: if(stalledJob || aReschedule) sl@0: { sl@0: // sl@0: // Pop current job from front of list sl@0: // sl@0: CryptoJob *oldJob = iJobList; sl@0: iJobList = iJobList->iNext; sl@0: oldJob->iNext = 0; sl@0: if(oldJob->DoSaveState()) sl@0: { sl@0: // State was saved sl@0: oldJob->iState = CryptoJob::EReadySavedState; sl@0: } sl@0: else sl@0: { sl@0: // No state was saved sl@0: oldJob->iState = CryptoJob::EReadyNoSavedState; sl@0: } sl@0: if(stalledJob) sl@0: { sl@0: oldJob->iInJobList = EFalse; sl@0: } sl@0: else sl@0: { sl@0: // sl@0: // Append oldJob to end of list sl@0: // sl@0: // Find ptr to last job sl@0: CryptoJob **pp = &iJobList; sl@0: while(*pp) sl@0: { sl@0: pp = &(*pp)->iNext; sl@0: } sl@0: // Append sl@0: *pp = oldJob; sl@0: } sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Run new job sl@0: // sl@0: CryptoJob *firstJob = iJobList; sl@0: sl@0: switch(firstJob->iState) sl@0: { sl@0: case CryptoJob::EReady: sl@0: firstJob->DoSlice(EFalse); sl@0: break; sl@0: sl@0: case CryptoJob::EReadyForFirstRun: sl@0: firstJob->iState = CryptoJob::EReady; sl@0: firstJob->DoSlice(ETrue); sl@0: break; sl@0: sl@0: case CryptoJob::EReadyNoSavedState: sl@0: firstJob->iState = CryptoJob::EReady; sl@0: firstJob->DoSlice(EFalse); sl@0: break; sl@0: sl@0: case CryptoJob::EReadySavedState: sl@0: firstJob->iState = CryptoJob::EReady; sl@0: firstJob->DoRestoreState(); sl@0: firstJob->DoSlice(EFalse); sl@0: break; sl@0: sl@0: case CryptoJob::ECreated: sl@0: case CryptoJob::EStalled: sl@0: default: sl@0: Kern::Printf("DCryptoJobScheduler::Schedule bad state %d", iJobList->iState); sl@0: DeScheduleJob(firstJob); // Abort/remove from list sl@0: Schedule(EFalse); sl@0: return; sl@0: } sl@0: sl@0: return; sl@0: } sl@0: sl@0: sl@0: EXPORT_C CryptoJob::CryptoJob() sl@0: : iState(ECreated), sl@0: iJobScheduler(0), sl@0: iCallbacks(0), sl@0: iNext(0), sl@0: iInJobList(EFalse) sl@0: { sl@0: TRACE_FUNCTION("CryptoJob"); sl@0: } sl@0: sl@0: EXPORT_C CryptoJob::~CryptoJob() sl@0: { sl@0: TRACE_FUNCTION("~CryptoJob"); sl@0: // Do not call DeScheduleJob from here because it will crash.... The sl@0: // derived class destructor has already run and the object is now sl@0: // considered to be of type CryptoJob (not the derived class) so sl@0: // most virtual functions are pure virtual and calling them will sl@0: // cause a crash. sl@0: } sl@0: sl@0: EXPORT_C void CryptoJob::Stalled() sl@0: { sl@0: TRACE_FUNCTION("Stalled"); sl@0: iState = EStalled; sl@0: iJobScheduler->SliceComplete(this, KErrNone); sl@0: } sl@0: sl@0: EXPORT_C void CryptoJob::Resume() sl@0: { sl@0: TRACE_FUNCTION("Resume"); sl@0: if(iState == EStalled) sl@0: { sl@0: iState = EReady; sl@0: } sl@0: iJobScheduler->ScheduleJob(this); sl@0: } sl@0: sl@0: EXPORT_C void CryptoJob::DeScheduleJob() sl@0: { sl@0: TRACE_FUNCTION("DeScheduleJob"); sl@0: if(iJobScheduler) sl@0: { sl@0: iJobScheduler->DeScheduleJob(this); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CryptoJob::SetRunning(TBool aRunning) sl@0: { sl@0: TRACE_FUNCTION("SetRunning"); sl@0: if(aRunning) sl@0: { sl@0: if((iState != EReady) && (iState != ERunning)) sl@0: { sl@0: Kern::Printf("CryptoJob::SetRunning(%d) iState is %d this=%x", aRunning, iState, this); sl@0: Kern::Fault("CryptoJob", 42); sl@0: } sl@0: iState = ERunning; sl@0: } sl@0: else sl@0: { sl@0: if((iState != ERunning) && (iState != EReady)) sl@0: { sl@0: Kern::Printf("CryptoJob::SetRunning(%d) iState is %d this=%x", aRunning, iState, this); sl@0: Kern::Fault("CryptoJob", 43); sl@0: } sl@0: iState = EReady; sl@0: } sl@0: } sl@0: sl@0: EXPORT_C CryptoJob::CryptoJobState CryptoJob::State() const sl@0: { sl@0: TRACE_FUNCTION("State"); sl@0: return iState; sl@0: } sl@0: sl@0: sl@0: // End of file sl@0: