cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptojobs.cpp
changeset 8 35751d3474b7
equal deleted inserted replaced
2:675a964f4eb5 8:35751d3474b7
       
     1 /*
       
     2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalComponent
       
    22  @released
       
    23 */
       
    24 #include <kernel/kern_priv.h>
       
    25 #include "cryptojobs.h"
       
    26 
       
    27 EXPORT_C TraceFunction * &TraceFunction::HeadRef()
       
    28 	{
       
    29 	static TraceFunction *sHead = 0;
       
    30 	return sHead;
       
    31 	}
       
    32 
       
    33 
       
    34 
       
    35 EXPORT_C DCryptoJobScheduler::DCryptoJobScheduler()
       
    36 	{
       
    37 	TRACE_FUNCTION("DCryptoJobScheduler");
       
    38 	}
       
    39 
       
    40 EXPORT_C DCryptoJobScheduler::~DCryptoJobScheduler()
       
    41 	{
       
    42 	TRACE_FUNCTION("~DCryptoJobScheduler");
       
    43 	// At this point the LDD channels and PDD factory/chans should
       
    44 	// have already been deleted...
       
    45 	}
       
    46 
       
    47 
       
    48 EXPORT_C void DCryptoJobScheduler::ScheduleJob(CryptoJob *aJob)
       
    49 	{
       
    50 	TRACE_FUNCTION("ScheduleJob");
       
    51 	if(aJob->iInJobList)
       
    52 		{
       
    53 		// Already in a job list
       
    54 		// If it is the current job and it is not running then try and schedule it
       
    55 		// It was probably stalled waiting for the user to read and/or write data.
       
    56 		if((aJob == iJobList) && (aJob->iState != CryptoJob::ERunning))
       
    57 			{
       
    58 			// Job is not running, and is first in list, so schedule
       
    59 			// it without rescheduling the first job (which is us!)
       
    60 			Schedule(EFalse);
       
    61 			return;
       
    62 			}
       
    63 		// Attempt to reschedule current job, ie if it is not running
       
    64 		// save its state and try running a different job.
       
    65 		Schedule(ETrue);
       
    66 		return;
       
    67 		}
       
    68 
       
    69 	// Not in list, so add it
       
    70 	aJob->iJobScheduler = this;
       
    71 	aJob->iNext = 0;
       
    72 	if(aJob->iState == CryptoJob::ECreated)
       
    73 		{
       
    74 		aJob->iState = CryptoJob::EReadyForFirstRun;
       
    75 		}
       
    76 	if(iJobList == 0)
       
    77 		{
       
    78 		// Only job
       
    79 		iJobList = aJob;
       
    80 		aJob->iInJobList = ETrue;
       
    81 		}
       
    82 	else
       
    83 		{
       
    84 		// Insert as second on list.
       
    85 		// 
       
    86 		// This quick and easy to do because it does not require a
       
    87 		// re-schedule or a full list walk. It is slightly unfair to
       
    88 		// existing jobs, but usually there will only be the head job
       
    89 		// anyway.
       
    90 		CryptoJob *p = iJobList->iNext;
       
    91 		iJobList->iNext = aJob;
       
    92 		aJob->iNext = p;
       
    93 		aJob->iInJobList = ETrue;
       
    94 		}
       
    95 	
       
    96 	// Attempt re-schedule
       
    97 	Schedule(ETrue);
       
    98 	}
       
    99 
       
   100 EXPORT_C void DCryptoJobScheduler::DeScheduleJob(CryptoJob *aJob)
       
   101 	{
       
   102 	TRACE_FUNCTION("DeScheduleJob");
       
   103 	if((aJob->iState == CryptoJob::EReady) || (aJob->iState == CryptoJob::ERunning))
       
   104 		{
       
   105 		aJob->DoReleaseHw();
       
   106 		}
       
   107 	
       
   108 	aJob->iState = CryptoJob::ECreated;
       
   109 	
       
   110 	// Hunt for and remove job from queue.
       
   111 	// This is a linear search, BUT the list length is probably one...
       
   112 	// Try and set pp to point to the pointer to the job we are removing
       
   113 	CryptoJob **pp = &iJobList; 
       
   114 	while(*pp != aJob && *pp)
       
   115 		{
       
   116 		pp = &((*pp)->iNext);
       
   117 		}
       
   118 	if(*pp == aJob)
       
   119 		{
       
   120 		*pp = (*pp)->iNext;
       
   121 		aJob->iNext = 0;
       
   122 		aJob->iJobScheduler = 0;
       
   123 		aJob->iInJobList = EFalse;
       
   124 		}
       
   125 	}
       
   126 
       
   127 
       
   128 
       
   129 EXPORT_C void DCryptoJobScheduler::SliceComplete(CryptoJob *aJob, TInt aStatus)
       
   130 	{
       
   131 	TRACE_FUNCTION("SliceComplete");
       
   132 	// Need start next slice or swap to another job and start it
       
   133 	if(aJob != iJobList)
       
   134 		{
       
   135 		Kern::Printf("DCryptoJobScheduler::SliceComplete - not running job 0x%x=0x%x",
       
   136 					 aJob, iJobList);
       
   137 		return;
       
   138 		}
       
   139 	
       
   140 	if(aStatus != KErrNone)
       
   141 		{
       
   142 		JobComplete(aJob, aStatus);
       
   143 		return;
       
   144 		}
       
   145 
       
   146 	Schedule(ETrue); // Change jobs and run top one
       
   147 	return;
       
   148 	}
       
   149 
       
   150 
       
   151 EXPORT_C void DCryptoJobScheduler::JobComplete(CryptoJob *aJob, TInt aStatus)
       
   152 	{
       
   153 	TRACE_FUNCTION("JobComplete");
       
   154 	if(aJob != iJobList)
       
   155 		{
       
   156 		Kern::Printf("DCryptoJobScheduler::JobComplete - not running job 0x%x=0x%x",
       
   157 					 aJob, iJobList);
       
   158 		return;
       
   159 		}
       
   160 
       
   161 	// Pop job and update state
       
   162 	DeScheduleJob(aJob);
       
   163 	
       
   164 	aJob->iCallbacks->JobComplete(aStatus);
       
   165 
       
   166 	Schedule(EFalse); // Run top job
       
   167 	}
       
   168 
       
   169 void DCryptoJobScheduler::Schedule(TBool aReschedule)
       
   170 	{
       
   171 	TRACE_FUNCTION("Schedule");
       
   172 	if(iJobList == 0)
       
   173 		{
       
   174 		return;
       
   175 		}
       
   176 
       
   177 	if(iJobList->iState == CryptoJob::ERunning)
       
   178 		{
       
   179 		// h/w busy so can not do anything now.
       
   180 		return;
       
   181 		}
       
   182 	
       
   183 	if((iJobList->iNext == 0) && (iJobList->iState == CryptoJob::EStalled))
       
   184 		{
       
   185 		// Only one job in list and its stalled. Leave it on the h/w
       
   186 		// as an optimisation.
       
   187 		return;
       
   188 		}
       
   189 
       
   190 	if(iJobList->iNext)
       
   191 		{
       
   192 		// More than one job in list.
       
   193 		// If top job is stalled, or reschedule is requested then swap jobs
       
   194 		// Only the top job can ever be marked as EStalled.
       
   195 		// (Only running job can stall and new jobs get inserted second in the list)
       
   196 		TBool stalledJob = (iJobList->iState == CryptoJob::EStalled);
       
   197 		if(stalledJob || aReschedule)
       
   198 			{
       
   199 			//
       
   200 			// Pop current job from front of list
       
   201 			//
       
   202 			CryptoJob *oldJob = iJobList;
       
   203 			iJobList = iJobList->iNext;
       
   204 			oldJob->iNext = 0;
       
   205 			if(oldJob->DoSaveState())
       
   206 				{
       
   207 				// State was saved
       
   208 				oldJob->iState = CryptoJob::EReadySavedState;
       
   209 				}
       
   210 			else
       
   211 				{
       
   212 				// No state was saved
       
   213 				oldJob->iState = CryptoJob::EReadyNoSavedState;
       
   214 				}
       
   215 			if(stalledJob)
       
   216 				{
       
   217 				oldJob->iInJobList = EFalse;
       
   218 				}
       
   219 			else
       
   220 				{
       
   221 				//
       
   222 				// Append oldJob to end of list
       
   223 				//
       
   224 				// Find ptr to last job
       
   225 				CryptoJob **pp = &iJobList;
       
   226 				while(*pp)
       
   227 					{
       
   228 					pp = &(*pp)->iNext;
       
   229 					}
       
   230 				// Append
       
   231 				*pp = oldJob;
       
   232 				}
       
   233 			}
       
   234 		}
       
   235 	
       
   236 	//
       
   237 	// Run new job
       
   238 	//
       
   239 	CryptoJob *firstJob = iJobList;
       
   240 
       
   241 	switch(firstJob->iState)
       
   242 		{
       
   243 		case CryptoJob::EReady:
       
   244 			firstJob->DoSlice(EFalse);
       
   245 			break;
       
   246 
       
   247 		case CryptoJob::EReadyForFirstRun:
       
   248 			firstJob->iState = CryptoJob::EReady;
       
   249 			firstJob->DoSlice(ETrue);
       
   250 			break;
       
   251 
       
   252 		case CryptoJob::EReadyNoSavedState:
       
   253 			firstJob->iState = CryptoJob::EReady;
       
   254 			firstJob->DoSlice(EFalse);
       
   255 			break;
       
   256 
       
   257 		case CryptoJob::EReadySavedState:
       
   258 			firstJob->iState = CryptoJob::EReady;
       
   259 			firstJob->DoRestoreState();
       
   260 			firstJob->DoSlice(EFalse);
       
   261 			break;
       
   262 			
       
   263 		case CryptoJob::ECreated:
       
   264 		case CryptoJob::EStalled:
       
   265 		default:
       
   266 			Kern::Printf("DCryptoJobScheduler::Schedule bad state %d", iJobList->iState);
       
   267 			DeScheduleJob(firstJob); // Abort/remove from list
       
   268 			Schedule(EFalse);
       
   269 			return;
       
   270 		}
       
   271 
       
   272 	return;
       
   273 	}
       
   274 
       
   275 
       
   276 EXPORT_C CryptoJob::CryptoJob()
       
   277 	: iState(ECreated),
       
   278 	  iJobScheduler(0),
       
   279 	  iCallbacks(0),
       
   280 	  iNext(0),
       
   281 	  iInJobList(EFalse)
       
   282 	{
       
   283 	TRACE_FUNCTION("CryptoJob");
       
   284 	}
       
   285 
       
   286 EXPORT_C CryptoJob::~CryptoJob()
       
   287 	{
       
   288 	TRACE_FUNCTION("~CryptoJob");
       
   289 	// Do not call DeScheduleJob from here because it will crash....  The
       
   290 	// derived class destructor has already run and the object is now
       
   291 	// considered to be of type CryptoJob (not the derived class) so
       
   292 	// most virtual functions are pure virtual and calling them will
       
   293 	// cause a crash.
       
   294 	}
       
   295 
       
   296 EXPORT_C void CryptoJob::Stalled()
       
   297 	{
       
   298 	TRACE_FUNCTION("Stalled");
       
   299 	iState = EStalled;
       
   300 	iJobScheduler->SliceComplete(this, KErrNone);	
       
   301 	}
       
   302 
       
   303 EXPORT_C void CryptoJob::Resume()
       
   304 	{
       
   305 	TRACE_FUNCTION("Resume");
       
   306 	if(iState == EStalled)
       
   307 		{
       
   308 		iState = EReady;
       
   309 		}
       
   310 	iJobScheduler->ScheduleJob(this);	
       
   311 	}
       
   312 
       
   313 EXPORT_C void CryptoJob::DeScheduleJob()
       
   314 	{
       
   315 	TRACE_FUNCTION("DeScheduleJob");
       
   316 	if(iJobScheduler)
       
   317 		{
       
   318 		iJobScheduler->DeScheduleJob(this);
       
   319 		}
       
   320 	}
       
   321 
       
   322 EXPORT_C void CryptoJob::SetRunning(TBool aRunning)
       
   323 	{
       
   324 	TRACE_FUNCTION("SetRunning");
       
   325 	if(aRunning)
       
   326 		{
       
   327 		if((iState != EReady) && (iState != ERunning))
       
   328 			{
       
   329 			Kern::Printf("CryptoJob::SetRunning(%d) iState is %d this=%x", aRunning, iState, this);
       
   330 			Kern::Fault("CryptoJob", 42);
       
   331 			}
       
   332 		iState = ERunning;
       
   333 		}
       
   334 	else
       
   335 		{
       
   336 		if((iState != ERunning) && (iState != EReady))
       
   337 			{
       
   338 			Kern::Printf("CryptoJob::SetRunning(%d) iState is %d this=%x", aRunning, iState, this);
       
   339 			Kern::Fault("CryptoJob", 43);
       
   340 			}
       
   341 		iState = EReady;
       
   342 		}
       
   343 	}
       
   344 
       
   345 EXPORT_C CryptoJob::CryptoJobState CryptoJob::State() const
       
   346 	{
       
   347 	TRACE_FUNCTION("State");
       
   348 	return iState;
       
   349 	}
       
   350 
       
   351 
       
   352 // End of file
       
   353