67 @param aName The name to be assigned to this thread. |
65 @param aName The name to be assigned to this thread. |
68 @param aThreadFunction Function to be called when thread is initially scheduled. |
66 @param aThreadFunction Function to be called when thread is initially scheduled. |
69 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction. |
67 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction. |
70 */ |
68 */ |
71 CThreadContext* CThreadContext::NewL(const TDesC& aName, |
69 CThreadContext* CThreadContext::NewL(const TDesC& aName, |
72 TThreadFunction aThreadFunction, |
70 TThreadFunction aThreadFunction, |
73 TAny* aOwner) |
71 TAny* aOwner) |
74 { |
72 { |
75 __FNLOG("CThreadContext::NewL"); |
73 CThreadContext* self = new (ELeave) CThreadContext(); |
76 CThreadContext* self = new (ELeave) CThreadContext(); |
74 CleanupStack::PushL(self); |
77 CleanupStack::PushL(self); |
75 self->ConstructL(aName, aThreadFunction, aOwner); |
78 self->ConstructL(aName, aThreadFunction, aOwner); |
76 CleanupStack::Pop(); |
79 CleanupStack::Pop(); |
77 return self; |
80 return self; |
78 } |
81 } |
|
82 |
79 |
83 /** |
80 /** |
84 Construct a CThreadContext object |
81 Construct a CThreadContext object |
85 |
82 |
86 @param aName The name to be assigned to this thread. |
83 @param aName The name to be assigned to this thread. |
87 @param aThreadFunction Function to be called when thread is initially scheduled. |
84 @param aThreadFunction Function to be called when thread is initially scheduled. |
88 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction. |
85 @param aOwner Pointer to the object owning the thread. Used as the parameter to aThreadFunction. |
89 */ |
86 */ |
90 void CThreadContext::ConstructL(const TDesC& aName, |
87 void CThreadContext::ConstructL(const TDesC& aName, |
91 TThreadFunction aThreadFunction, |
88 TThreadFunction aThreadFunction, |
92 TAny* aOwner) |
89 TAny* aOwner) |
93 { |
90 { |
94 __FNLOG("CThreadContext::ConstructL"); |
91 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_10, "Creating Critical Section"); |
95 __PRINT(_L("Creating Critical Section")); |
92 User::LeaveIfError(iCritSect.CreateLocal()); |
96 User::LeaveIfError(iCritSect.CreateLocal()); |
93 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_11, "Creating RThread"); |
97 __PRINT(_L("Creating RThread")); |
94 |
98 |
95 TUint serial(0); // Used to retry creation of a thread in case |
99 TUint serial(0); // Used to retry creation of a thread in case |
96 // one with the same name already exists |
100 // one with the same name already exists |
97 |
101 |
98 RBuf threadName; |
102 RBuf threadName; |
99 threadName.CreateMaxL(aName.Length() + 8); |
103 threadName.CreateMaxL(aName.Length() + 8); |
100 CleanupClosePushL(threadName); |
104 CleanupClosePushL(threadName); |
101 threadName = aName; |
105 threadName = aName; |
102 |
106 |
103 TInt err; |
107 TInt err; |
104 for (;;) |
108 for (;;) |
105 { |
109 { |
106 err = iThread.Create(threadName, aThreadFunction, 0x1000, NULL, aOwner); |
110 err = iThread.Create(threadName, aThreadFunction, 0x1000, NULL, aOwner); |
107 OstTraceData(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_13, |
111 __PRINT2(_L("CThreadContext::ConstructL Created thread %S err=%d"), &threadName, err); |
108 "CThreadContext::ConstructL Created thread %s err=%d", threadName.Ptr(), threadName.Length()); |
|
109 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_14, |
|
110 "err=%d", err); |
|
111 |
112 |
112 |
113 // for a restart wait and retry until old thread is gone |
113 // for a restart wait and retry until old thread is gone |
114 if (err == KErrAlreadyExists) |
114 if (err == KErrAlreadyExists) |
115 { |
115 { |
116 User::After(10 * 1000); // 10 mS |
116 User::After(10 * 1000); // 10 mS |
117 threadName = aName; |
117 threadName = aName; |
118 threadName.AppendNumFixedWidth(serial, EDecimal, 8); |
118 threadName.AppendNumFixedWidth(serial, EDecimal, 8); |
119 ++serial; |
119 ++serial; |
120 } |
120 } |
121 else |
121 else |
122 { |
122 { |
123 break; |
123 break; |
124 } |
124 } |
125 } |
125 } |
126 |
126 |
127 User::LeaveIfError(err); |
127 User::LeaveIfError(err); |
128 CleanupStack::Pop(); // threadName |
128 CleanupStack::Pop(); // threadName |
129 threadName.Close(); |
129 threadName.Close(); |
130 |
130 |
131 // set priority |
131 // set priority |
132 iThread.SetPriority(EPriorityMore); |
132 iThread.SetPriority(EPriorityMore); |
133 } |
133 } |
134 |
134 |
135 |
135 |
136 /** |
136 /** |
137 Construct a CThreadContext object |
137 Construct a CThreadContext object |
138 */ |
138 */ |
139 CThreadContext::CThreadContext() |
139 CThreadContext::CThreadContext() |
140 : |
140 : |
141 iError(KErrNone) |
141 iError(KErrNone) |
142 { |
142 { |
143 __FNLOG("CThreadContext::CThreadContext"); |
143 } |
144 } |
|
145 |
144 |
146 /** |
145 /** |
147 Destructor |
146 Destructor |
148 */ |
147 */ |
149 CThreadContext::~CThreadContext() |
148 CThreadContext::~CThreadContext() |
150 { |
149 { |
151 __FNLOG("CThreadContext::~CThreadContext"); |
150 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_20, "Closing Critical Section"); |
152 __PRINT(_L("Closing Critical Section")); |
151 iCritSect.Close(); |
153 iCritSect.Close(); |
152 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_21, "Killing ThreadContext"); |
154 __PRINT(_L("Killing ThreadContext")); |
153 iThread.Kill(0); |
155 iThread.Kill(0); |
154 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_22, "Closing ThreadContext"); |
156 __PRINT(_L("Closing ThreadContext")); |
155 iThread.Close(); |
157 iThread.Close(); |
156 } |
158 } |
|
159 |
157 |
160 //----------------------------------------------- |
158 //----------------------------------------------- |
161 |
159 |
162 /** |
160 /** |
163 Construct a CWriteDriveThread object |
161 Construct a CWriteDriveThread object |
164 */ |
162 */ |
165 CWriteDriveThread* CWriteDriveThread::NewL() |
163 CWriteDriveThread* CWriteDriveThread::NewL() |
166 { |
164 { |
167 __FNLOG("CWriteDriveThread::NewL"); |
165 CWriteDriveThread* self = new (ELeave) CWriteDriveThread(); |
168 CWriteDriveThread* self = new (ELeave) CWriteDriveThread(); |
166 CleanupStack::PushL(self); |
169 CleanupStack::PushL(self); |
167 self->ConstructL(); |
170 self->ConstructL(); |
168 CleanupStack::Pop(); |
171 CleanupStack::Pop(); |
169 return self; |
172 return self; |
170 } |
173 } |
|
174 |
171 |
175 /** |
172 /** |
176 Construct a CWriteDriveThread object |
173 Construct a CWriteDriveThread object |
177 */ |
174 */ |
178 void CWriteDriveThread::ConstructL() |
175 void CWriteDriveThread::ConstructL() |
179 { |
176 { |
180 __FNLOG("CWriteDriveThread::ConstructL"); |
177 TBuf<16> name = _L("MassStorageWrite"); |
181 TBuf<16> name = _L("MassStorageWrite"); |
178 iThreadContext = CThreadContext::NewL(name, ThreadFunction, this); |
182 iThreadContext = CThreadContext::NewL(name, ThreadFunction, this); |
179 // There are two free pointers to start with so initialise the semaphore with 1 |
183 // There are two free pointers to start with so initialise the semaphore with 1 |
180 User::LeaveIfError(iProducerSem.CreateLocal(1)); |
184 User::LeaveIfError(iProducerSem.CreateLocal(1)); |
181 User::LeaveIfError(iConsumerSem.CreateLocal(0)); |
185 User::LeaveIfError(iConsumerSem.CreateLocal(0)); |
182 |
186 |
183 iThreadContext->Resume(); |
187 iThreadContext->Resume(); |
184 } |
188 } |
|
189 |
185 |
190 /** |
186 /** |
191 Construct a CWriteDriveThread object |
187 Construct a CWriteDriveThread object |
192 */ |
188 */ |
193 CWriteDriveThread::CWriteDriveThread() |
189 CWriteDriveThread::CWriteDriveThread() |
194 : iIsCommandWrite10(EFalse) |
190 : iIsCommandWrite10(EFalse) |
195 { |
191 { |
196 __FNLOG("CWriteDriveThread::CWriteDriveThread"); |
192 } |
197 } |
|
198 |
193 |
199 /** |
194 /** |
200 Destructor |
195 Destructor |
201 */ |
196 */ |
202 CWriteDriveThread::~CWriteDriveThread() |
197 CWriteDriveThread::~CWriteDriveThread() |
203 { |
198 { |
204 __FNLOG("CWriteDriveThread::~CWriteDriveThread"); |
199 delete iThreadContext; |
205 delete iThreadContext; |
200 } |
206 } |
|
207 |
201 |
208 /** |
202 /** |
209 This function is called when the thread is initially scheduled. |
203 This function is called when the thread is initially scheduled. |
210 |
204 |
211 @param aSelf Pointer to self to facilitate call to member method. |
205 @param aSelf Pointer to self to facilitate call to member method. |
212 */ |
206 */ |
213 TInt CWriteDriveThread::ThreadFunction(TAny* aSelf) |
207 TInt CWriteDriveThread::ThreadFunction(TAny* aSelf) |
214 { |
208 { |
215 __FNLOG("CWriteDriveThread::ThreadFunction"); |
209 CWriteDriveThread* self = static_cast<CWriteDriveThread*>(aSelf); |
216 CWriteDriveThread* self = static_cast<CWriteDriveThread*>(aSelf); |
210 return self->WriteToDrive(); |
217 return self->WriteToDrive(); |
211 } |
218 } |
|
219 |
212 |
220 /** |
213 /** |
221 Writes the data pointed to by iDescWritePtr to the drive. |
214 Writes the data pointed to by iDescWritePtr to the drive. |
222 */ |
215 */ |
223 TInt CWriteDriveThread::WriteToDrive() |
216 TInt CWriteDriveThread::WriteToDrive() |
224 { |
217 { |
225 __FNLOG("\tCWriteDriveThread::WriteToDrive"); |
218 // One-off convenience variable assignment |
226 |
219 TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr; |
227 // One-off convenience variable assignment |
220 |
228 TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr; |
221 for(;;) |
229 |
222 { |
230 for(;;) |
223 iConsumerSem.Wait(); |
231 { |
224 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_30, "Waiting on Write CS..."); |
232 iConsumerSem.Wait(); |
225 iThreadContext->iCritSect.Wait(); |
233 __PRINT(_L("\tWaiting on Write CS...")); |
226 // +++ WRITE CS STARTS HERE +++ |
234 iThreadContext->iCritSect.Wait(); |
227 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_31, |
235 // +++ WRITE CS STARTS HERE +++ |
228 "Now using as write buffer: iBuf%d", iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf)); |
236 __PRINT1(_L("\tNow using as write buffer: iBuf%d"), iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf)); |
229 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_32, |
237 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME |
230 "SCSI: writing %d bytes", desc->iBuf.Length()); |
238 RDebug::Print(_L("\tSCSI: writing %d bytes\n"), desc->iBuf.Length()); |
231 // Write buffer to disk |
239 TTime t0, t1; |
232 iThreadContext->iError = iThreadContext->iDrive->Write(desc->iByteOffset, desc->iBuf,iThreadContext->iDrive->IsWholeMediaAccess()); |
240 t0.HomeTime(); |
233 |
241 #else |
234 iCallback((TUint8*) (desc->iBuf.Ptr()), iCallbackParameter); |
242 __PRINT1(_L("\tSCSI: writing %d bytes\n"), desc->iBuf.Length()); |
235 iWriteCounter--; |
243 #endif |
236 __ASSERT_DEBUG(iWriteCounter >= 0, User::Panic(KUsbMsSvrPncCat, EMsThreadWriteToDrive)); |
244 // Write buffer to disk |
237 |
245 |
238 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_33, "Signalling Write CS"); |
246 #ifdef INJECT_ERROR |
239 iThreadContext->iCritSect.Signal(); |
247 if (desc->iBuf[0] == '2') |
240 // +++ WRITE CS ENDS HERE +++ |
248 { |
241 iProducerSem.Signal(); |
249 desc->iBuf[0] = 'x'; |
242 } |
250 RDebug::Printf("Injecting error"); |
243 } |
251 } |
244 |
252 |
245 /** |
253 |
246 Initiates writing data pointed to by iReadBuf to the drive and resumes the thread. Writing |
254 RDebug::Printf("%08lx %x [%x] [%x]", desc->iByteOffset, desc->iBuf.Length(), |
|
255 desc->iBuf[0], |
|
256 desc->iBuf[desc->iBuf.Length()-1]); |
|
257 #endif |
|
258 |
|
259 iThreadContext->iError = iThreadContext->iDrive->Write(desc->iByteOffset, desc->iBuf,iThreadContext->iDrive->IsWholeMediaAccess()); |
|
260 #ifdef INJECT_ERROR |
|
261 if (desc->iBuf[0] == 'x') |
|
262 { |
|
263 iThreadContext->iError = KErrUnknown; |
|
264 } |
|
265 #endif |
|
266 |
|
267 #ifdef MEASURE_AND_DISPLAY_WRITE_TIME |
|
268 t1.HomeTime(); |
|
269 const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0); |
|
270 const TUint time_ms = I64LOW(time.Int64() / 1000); |
|
271 RDebug::Print(_L("SCSI: write took %d ms\n"), time_ms); |
|
272 #endif |
|
273 iCallback((TUint8*) (desc->iBuf.Ptr()), iCallbackParameter); |
|
274 iWriteCounter--; |
|
275 ASSERT(iWriteCounter >= 0); |
|
276 |
|
277 __PRINT(_L("\tSignalling Write CS")); |
|
278 iThreadContext->iCritSect.Signal(); |
|
279 // +++ WRITE CS ENDS HERE +++ |
|
280 iProducerSem.Signal(); |
|
281 } |
|
282 } |
|
283 |
|
284 /** |
|
285 Initiates writing data pointed to by iReadBuf to the drive and resumes the thread. Writing |
|
286 is completed by the ThreadFunction when the thread is resumed. |
247 is completed by the ThreadFunction when the thread is resumed. |
287 |
248 |
288 @param aDrive Drive to write to. |
249 @param aDrive Drive to write to. |
289 @param aOffset Write offset. |
250 @param aOffset Write offset. |
290 */ |
251 */ |
291 TInt CWriteDriveThread::WriteDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TPtrC8& aDes, ProcessWriteCompleteFunc aFunc, TAny* aPtr) |
252 TInt CWriteDriveThread::WriteDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TPtrC8& aDes, ProcessWriteCompleteFunc aFunc, TAny* aPtr) |
292 { |
253 { |
293 // Check error code from previous write |
254 // Check error code from previous write |
294 const TInt r = iThreadContext->iError; |
255 const TInt r = iThreadContext->iError; |
295 if (r != KErrNone) |
256 if (r != KErrNone) |
296 { |
257 { |
297 __PRINT1(_L("Error after previous write = 0x%x \n"), r); |
258 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_40, "Error after previous write = %d", r); |
298 return KErrAbort; |
259 return KErrAbort; |
299 } |
260 } |
300 |
261 |
301 // Swap the two buffer pointers |
262 // Swap the two buffer pointers |
302 iProducerSem.Wait(); |
263 iProducerSem.Wait(); |
303 __PRINT(_L("Waiting on Write CS...")); |
264 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_41, "Waiting on Write CS..."); |
304 // +++ WRITE CS STARTS HERE +++ |
265 // +++ WRITE CS STARTS HERE +++ |
305 iThreadContext->iCritSect.Wait(); |
266 iThreadContext->iCritSect.Wait(); |
306 |
267 |
307 // New DB First read into the iDescReadPtr pointer, |
268 // New DB First read into the iDescReadPtr pointer, |
308 // then swap,so that write pointer points to correct location, as the ptr pointed to by iDescWritePtr is what is written from in WriteToDrive |
269 // then swap,so that write pointer points to correct location, as the ptr pointed to by iDescWritePtr is what is written from in WriteToDrive |
309 iThreadContext->iBuffer.iDescReadPtr->iBuf.Set((TUint8*)aDes.Ptr(), aDes.Length(), KMaxBufSize ); |
270 iThreadContext->iBuffer.iDescReadPtr->iBuf.Set((TUint8*)aDes.Ptr(), aDes.Length(), KMaxBufSize); |
310 |
271 |
311 iCallback = aFunc; |
272 iCallback = aFunc; |
312 iCallbackParameter = aPtr; |
273 iCallbackParameter = aPtr; |
313 |
274 |
314 iWriteCounter++; |
275 iWriteCounter++; |
315 iThreadContext->iBuffer.SwapDesc(); |
276 iThreadContext->iBuffer.SwapDesc(); |
316 // Prepare variables for next write |
277 // Prepare variables for next write |
317 iThreadContext->iDrive = aDrive; |
278 iThreadContext->iDrive = aDrive; |
318 iThreadContext->iBuffer.iDescWritePtr->iByteOffset = aOffset; |
279 iThreadContext->iBuffer.iDescWritePtr->iByteOffset = aOffset; |
319 // +++ WRITE CS ENDS HERE +++ |
280 // +++ WRITE CS ENDS HERE +++ |
320 __PRINT(_L("Signalling Write CS...")); |
281 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_42, "Signalling Write CS..."); |
321 iThreadContext->iCritSect.Signal(); |
282 iThreadContext->iCritSect.Signal(); |
322 |
283 |
323 iConsumerSem.Signal(); |
284 iConsumerSem.Signal(); |
324 return KErrNone; |
285 return KErrNone; |
325 } |
286 } |
326 |
287 |
327 |
288 |
328 void CWriteDriveThread::WaitForWriteEmpty() |
289 void CWriteDriveThread::WaitForWriteEmpty() |
329 { |
290 { |
330 while(iWriteCounter > 0) |
291 while(iWriteCounter > 0) |
331 { |
292 { |
332 User::After(100); |
293 User::After(100); |
333 } |
294 } |
334 } |
295 } |
335 |
296 |
336 // Check if the target address range was recently written to, this is to force a |
297 // Check if the target address range was recently written to, this is to force a |
337 // cache miss when reading from the same sectors that were just written. |
298 // cache miss when reading from the same sectors that were just written. |
338 // Optimisation note: this is only needed if the read precache was started |
299 // Optimisation note: this is only needed if the read precache was started |
339 // before the write was completed. |
300 // before the write was completed. |
340 TBool CWriteDriveThread::IsRecentlyWritten(TInt64 aOffset, TInt aLength) |
301 TBool CWriteDriveThread::IsRecentlyWritten(TInt64 aOffset, TInt aLength) |
341 { |
302 { |
342 ASSERT(iWriteCounter == 0); |
303 __ASSERT_DEBUG(iWriteCounter == 0, User::Panic(KUsbMsSvrPncCat, EMsThreadIsRecentlyWritten)); |
343 if (iIsCommandWrite10) //If the previous command is Write10, then discard pre-read as the same buffers are used and will be over written by Write10 |
304 if (iIsCommandWrite10) //If the previous command is Write10, then discard pre-read as the same buffers are used and will be over written by Write10 |
344 return ETrue; |
305 return ETrue; |
345 if(aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset && |
306 if(aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset && |
346 aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset) |
307 aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset) |
347 return ETrue; |
308 return ETrue; |
348 if(aOffset >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset && |
309 if(aOffset >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset && |
349 aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength) |
310 aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength) |
350 return ETrue; |
311 return ETrue; |
351 if(aOffset <= iThreadContext->iBuffer.iDescWritePtr->iByteOffset && |
312 if(aOffset <= iThreadContext->iBuffer.iDescWritePtr->iByteOffset && |
352 aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset) |
313 aOffset + aLength >= iThreadContext->iBuffer.iDescReadPtr->iByteOffset) |
353 return ETrue; |
314 return ETrue; |
354 if(aOffset >= iThreadContext->iBuffer.iDescWritePtr->iByteOffset && |
315 if(aOffset >= iThreadContext->iBuffer.iDescWritePtr->iByteOffset && |
355 aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength) |
316 aOffset <= iThreadContext->iBuffer.iDescReadPtr->iByteOffset + iThreadContext->iBuffer.iDescReadPtr->iLength) |
356 return ETrue; |
317 return ETrue; |
357 return EFalse; |
318 return EFalse; |
358 } |
319 } |
359 |
320 |
360 //----------------------------------------------- |
321 //----------------------------------------------- |
361 |
322 |
362 /** |
323 /** |
363 Construct a CReadDriveThread object |
324 Construct a CReadDriveThread object |
364 */ |
325 */ |
365 CReadDriveThread* CReadDriveThread::NewL() |
326 CReadDriveThread* CReadDriveThread::NewL() |
366 { |
327 { |
367 __FNLOG("CReadDriveThread::NewL"); |
328 CReadDriveThread* self = new (ELeave) CReadDriveThread(); |
368 CReadDriveThread* self = new (ELeave) CReadDriveThread(); |
329 CleanupStack::PushL(self); |
369 CleanupStack::PushL(self); |
330 self->ConstructL(); |
370 self->ConstructL(); |
331 CleanupStack::Pop(); |
371 CleanupStack::Pop(); |
332 return self; |
372 return self; |
333 } |
373 } |
|
374 |
334 |
375 /** |
335 /** |
376 Construct a CReadDriveThread object |
336 Construct a CReadDriveThread object |
377 |
337 |
378 @param aName The name to be assigned to this thread. |
338 @param aName The name to be assigned to this thread. |
379 @pram aThreadFunction Function to be called when thread is initially scheduled. |
339 @pram aThreadFunction Function to be called when thread is initially scheduled. |
380 */ |
340 */ |
381 void CReadDriveThread::ConstructL() |
341 void CReadDriveThread::ConstructL() |
382 { |
342 { |
383 __FNLOG("CReadDriveThread::ConstructL"); |
343 TBuf<15> name = _L("MassStorageRead"); |
384 TBuf<15> name = _L("MassStorageRead"); |
344 iThreadContext = CThreadContext::NewL(name, ThreadFunction, this); |
385 iThreadContext = CThreadContext::NewL(name, ThreadFunction, this); |
345 } |
386 } |
|
387 |
346 |
388 /** |
347 /** |
389 Construct a CReadDriveThread object |
348 Construct a CReadDriveThread object |
390 */ |
349 */ |
391 CReadDriveThread::CReadDriveThread() |
350 CReadDriveThread::CReadDriveThread() |
392 : |
351 : |
393 iThreadRunning(EFalse) |
352 iThreadRunning(EFalse) |
394 { |
353 { |
395 __FNLOG("CReadDriveThread::CReadDriveThread"); |
354 } |
396 } |
|
397 |
355 |
398 /** |
356 /** |
399 Destructor |
357 Destructor |
400 */ |
358 */ |
401 CReadDriveThread::~CReadDriveThread() |
359 CReadDriveThread::~CReadDriveThread() |
402 { |
360 { |
403 __FNLOG("CReadDriveThread::~CReadDriveThread"); |
361 delete iThreadContext; |
404 delete iThreadContext; |
362 } |
405 } |
|
406 |
363 |
407 /** |
364 /** |
408 This function is called when the thread is initially scheduled. |
365 This function is called when the thread is initially scheduled. |
409 |
366 |
410 @param aSelf Pointer to self to facilitate call to member method. |
367 @param aSelf Pointer to self to facilitate call to member method. |
411 */ |
368 */ |
412 TInt CReadDriveThread::ThreadFunction(TAny* aSelf) |
369 TInt CReadDriveThread::ThreadFunction(TAny* aSelf) |
413 { |
370 { |
414 __FNLOG("CReadDriveThread::ThreadFunction"); |
371 CReadDriveThread* self = static_cast<CReadDriveThread*>(aSelf); |
415 CReadDriveThread* self = static_cast<CReadDriveThread*>(aSelf); |
372 return self->ReadFromDrive(); |
416 return self->ReadFromDrive(); |
373 } |
417 } |
|
418 |
374 |
419 /** |
375 /** |
420 Reads data from the drive with iOffset and iReadLength into memory pointer iReadBuffer |
376 Reads data from the drive with iOffset and iReadLength into memory pointer iReadBuffer |
421 and suspends the thread. |
377 and suspends the thread. |
422 */ |
378 */ |
423 TInt CReadDriveThread::ReadFromDrive() |
379 TInt CReadDriveThread::ReadFromDrive() |
424 { |
380 { |
425 __FNLOG("\tCReadDriveThread::ReadFromDrive"); |
381 // One-off convenience variable assignment |
426 |
382 TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr; |
427 // One-off convenience variable assignment |
383 |
428 TBlockDesc* &desc = iThreadContext->iBuffer.iDescWritePtr; |
384 for (;;) |
429 |
385 { |
430 for (;;) |
386 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_50, "Waiting on Read CS..."); |
431 { |
387 iThreadContext->iCritSect.Wait(); |
432 __PRINT(_L("\tWaiting on Read CS...")); |
388 // +++ READ CS STARTS HERE +++ |
433 iThreadContext->iCritSect.Wait(); |
389 iThreadRunning = ETrue; |
434 // +++ READ CS STARTS HERE +++ |
390 iCompleted = EFalse; |
435 iThreadRunning = ETrue; |
391 |
436 iCompleted = EFalse; |
392 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_51, |
437 |
393 "\tNow using as read buffer: iBuf%d", iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf)); |
438 __PRINT1(_L("\tNow using as read buffer: iBuf%d"), iThreadContext->iBuffer.GetBufferNumber(&desc->iBuf)); |
394 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_52, |
439 |
395 "\tSCSI: reading %d bytes", desc->iBuf.Length()); |
440 #ifdef MEASURE_AND_DISPLAY_READ_TIME |
396 |
441 RDebug::Print(_L("\tSCSI: reading %d bytes\n"), desc->iBuf.Length()); |
397 // Fill read buffer from disk |
442 TTime t0, t1; |
398 iThreadContext->iError = iThreadContext->iDrive->Read(desc->iByteOffset, |
443 t0.HomeTime(); |
399 desc->iLength, |
444 #else |
400 desc->iBuf, |
445 __PRINT1(_L("\tSCSI: reading %d bytes\n"), desc->iBuf.Length()); |
401 iThreadContext->iDrive->IsWholeMediaAccess()); |
446 #endif |
402 |
447 // Fill read buffer from disk |
403 iCompleted = ETrue; |
448 iThreadContext->iError = iThreadContext->iDrive->Read(desc->iByteOffset, |
404 iThreadRunning = EFalse; |
449 desc->iLength, |
405 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_53, "Signalling Read CS"); |
450 desc->iBuf, |
406 // +++ READ CS ENDS HERE +++ |
451 iThreadContext->iDrive->IsWholeMediaAccess()); |
407 iThreadContext->iCritSect.Signal(); |
452 |
408 // Suspend self |
453 #ifdef MEASURE_AND_DISPLAY_READ_TIME |
409 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_54, "Suspending Read Thread"); |
454 t1.HomeTime(); |
410 RThread().Suspend(); |
455 const TTimeIntervalMicroSeconds time = t1.MicroSecondsFrom(t0); |
411 } |
456 const TUint time_ms = I64LOW(time.Int64() / 1000); |
412 } |
457 RDebug::Print(_L("SCSI: read took %d ms\n"), time_ms); |
413 |
458 #endif |
414 /** |
459 |
415 Client read request of a data block from the specified drive. |
460 iCompleted = ETrue; |
|
461 iThreadRunning = EFalse; |
|
462 __PRINT(_L("\tSignalling Read CS")); |
|
463 // +++ READ CS ENDS HERE +++ |
|
464 iThreadContext->iCritSect.Signal(); |
|
465 // Suspend self |
|
466 __PRINT(_L("\tSuspending Read Thread")); |
|
467 RThread().Suspend(); |
|
468 } |
|
469 } |
|
470 |
|
471 /** |
|
472 Client read request of a data block from the specified drive. |
|
473 If there is no pre-read data that matches the requested Offset and Length then the drive |
416 If there is no pre-read data that matches the requested Offset and Length then the drive |
474 is read and the next pre-read is setup. If there is matching pre-read data available then |
417 is read and the next pre-read is setup. If there is matching pre-read data available then |
475 the next pre-read is setup. Finishes by resuming the thread and the ThreadFunciton runs. |
418 the next pre-read is setup. Finishes by resuming the thread and the ThreadFunciton runs. |
476 |
419 |
477 @param aDrive Drive to read from. |
420 @param aDrive Drive to read from. |
478 @param aOffset Read offset |
421 @param aOffset Read offset |
479 @param aLength Length |
422 @param aLength Length |
480 */ |
423 */ |
481 TBool CReadDriveThread::ReadDriveData(CMassStorageDrive* aDrive, |
424 TBool CReadDriveThread::ReadDriveData(CMassStorageDrive* aDrive, |
482 const TInt64& aOffset, |
425 const TInt64& aOffset, |
483 TUint32 aLength, |
426 TUint32 aLength, |
484 TBool aIgnoreCache) |
427 TBool aIgnoreCache) |
485 { |
428 { |
486 __MT_READ_PRINT2(_L("\nRead10: offs %ld len %d"), aOffset, aLength); |
429 OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_60, "Read10: offs %ld len %d", aOffset, aLength); |
487 |
430 |
488 __PRINT(_L("Waiting on Read CS...")); |
431 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_61, "Waiting on Read CS..."); |
489 iThreadContext->iCritSect.Wait(); |
432 iThreadContext->iCritSect.Wait(); |
490 // +++ READ CS STARTS HERE +++ |
433 // +++ READ CS STARTS HERE +++ |
491 __ASSERT_DEBUG(!iThreadRunning, User::Panic(_L("MSDC-THREAD"), 666)); |
434 __ASSERT_DEBUG(!iThreadRunning, User::Panic(KUsbMsSvrPncCat, EMsThreadReadDriveThread)); |
492 |
435 |
493 TBlockDesc* &desc = iThreadContext->iBuffer.iDescReadPtr; |
436 TBlockDesc* &desc = iThreadContext->iBuffer.iDescReadPtr; |
494 TBlockDesc* &bgDesc = iThreadContext->iBuffer.iDescWritePtr; |
437 TBlockDesc* &bgDesc = iThreadContext->iBuffer.iDescWritePtr; |
495 |
438 |
496 if ((!aIgnoreCache) && |
439 if ((!aIgnoreCache) && |
497 (iCompleted) && |
440 (iCompleted) && |
498 (iThreadContext->iError == KErrNone) && |
441 (iThreadContext->iError == KErrNone) && |
499 (iThreadContext->iDrive == aDrive) && |
442 (iThreadContext->iDrive == aDrive) && |
500 (bgDesc->iByteOffset == aOffset) && |
443 (bgDesc->iByteOffset == aOffset) && |
501 (bgDesc->iLength == aLength)) |
444 (bgDesc->iLength == aLength)) |
502 { |
445 { |
503 // Good: We pre-read the correct data :-) |
446 // Good: We pre-read the correct data :-) |
504 __MT_READ_PRINT(_L("Match: Using pre-read data :-) :-) :-) :-)")); |
447 OstTrace0(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_70, "Match: Using pre-read data :-) :-) :-) :-)"); |
505 } |
448 } |
506 else |
449 else |
507 { |
450 { |
508 __MT_READ_PRINT(_L("Not using pre-read data")); |
451 OstTrace0(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_71, "Not using pre-read data"); |
509 if (iThreadContext->iError != KErrNone) |
452 if (iThreadContext->iError != KErrNone) |
510 { |
453 { |
511 __MT_READ_PRINT1(_L("Pre-read failed: %d"), iThreadContext->iError); |
454 OstTrace1(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_72, "Pre-read failed: %d", iThreadContext->iError); |
512 } |
455 } |
513 if (iThreadContext->iDrive != aDrive) |
456 if (iThreadContext->iDrive != aDrive) |
514 { |
457 { |
515 __MT_READ_PRINT2(_L("Pre-read drive mismatch: pre 0x%08x / act 0x%08x"), |
458 OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_73, |
516 iThreadContext->iDrive, aDrive); |
459 "Pre-read drive mismatch: pre 0x%08x / act 0x%08x", |
517 } |
460 (TUint32)iThreadContext->iDrive, (TUint32)aDrive); |
518 if (desc->iByteOffset != aOffset) |
461 } |
519 { |
462 if (desc->iByteOffset != aOffset) |
520 __MT_READ_PRINT2(_L("Pre-read offset mismatch: pre %ld / act %ld"), |
463 { |
521 desc->iByteOffset, aOffset); |
464 OstTraceExt4(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_74, |
522 } |
465 "Pre-read offset mismatch: pre 0x%x 0x%x / act 0x%x 0x%x", |
523 if (desc->iLength != aLength) |
466 I64HIGH(desc->iByteOffset), I64LOW(desc->iByteOffset), I64HIGH(aOffset), I64LOW(aOffset)); |
524 { |
467 } |
525 __MT_READ_PRINT2(_L("Pre-read length mismatch: pre %d / act %d"), |
468 if (desc->iLength != aLength) |
526 desc->iLength, aLength); |
469 { |
527 // Potential optimization: If the pre-read was OK but for more data |
470 OstTraceExt2(TRACE_SMASSSTORAGE_MEDIADB, CTHREADCONTEXT_75, |
528 // than the host is now asking for, we could still satisfy that |
471 "Pre-read length mismatch: pre 0x%x / act 0x%x", |
529 // request from the pre-read data by shortening the buffer. |
472 (TUint32)desc->iLength, aLength); |
530 } |
473 // Potential optimization: If the pre-read was OK but for more data |
531 // No valid pre-read data was available - so we have to read it now |
474 // than the host is now asking for, we could still satisfy that |
532 bgDesc->iByteOffset = aOffset; |
475 // request from the pre-read data by shortening the buffer. |
533 bgDesc->iLength = aLength; |
476 } |
534 TInt err = aDrive->Read(aOffset, |
477 // No valid pre-read data was available - so we have to read it now |
535 aLength, |
478 bgDesc->iByteOffset = aOffset; |
536 bgDesc->iBuf, |
479 bgDesc->iLength = aLength; |
537 aDrive->IsWholeMediaAccess()); |
480 TInt err = aDrive->Read(aOffset, |
538 if (err != KErrNone) |
481 aLength, |
539 { |
482 bgDesc->iBuf, |
540 __PRINT1(_L("Read failed, err=%d\n"), err); |
483 aDrive->IsWholeMediaAccess()); |
541 // +++ READ CS ENDS HERE +++ |
484 if (err != KErrNone) |
542 __PRINT(_L("Signalling Read CS...")); |
485 { |
543 iThreadContext->iCritSect.Signal(); |
486 OstTrace1(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_76, "Read failed, err=%d", err); |
544 return EFalse; |
487 // +++ READ CS ENDS HERE +++ |
545 } |
488 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_77, "Signalling Read CS..."); |
546 } |
489 iThreadContext->iCritSect.Signal(); |
547 |
490 return EFalse; |
548 // Prepare thread variables for next pre-read attempt by the ReadThread |
491 } |
549 const TInt64 offs_new = aOffset + aLength; |
492 } |
550 iThreadContext->iDrive = aDrive; // same drive |
493 |
551 desc->iByteOffset = offs_new; // next block |
494 // Prepare thread variables for next pre-read attempt by the ReadThread |
552 desc->iLength = aLength; // same length |
495 const TInt64 offs_new = aOffset + aLength; |
553 iCompleted = EFalse; |
496 iThreadContext->iDrive = aDrive; // same drive |
554 iThreadContext->iBuffer.SwapDesc(); |
497 desc->iByteOffset = offs_new; // next block |
555 |
498 desc->iLength = aLength; // same length |
556 // +++ READ CS ENDS HERE +++ |
499 iCompleted = EFalse; |
557 __PRINT(_L("Signalling Read CS...")); |
500 iThreadContext->iBuffer.SwapDesc(); |
558 iThreadContext->iCritSect.Signal(); |
501 |
559 // Start background read |
502 // +++ READ CS ENDS HERE +++ |
560 __PRINT(_L("Resuming Read Thread")); |
503 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_78, "Signalling Read CS..."); |
561 iThreadContext->Resume(); |
504 iThreadContext->iCritSect.Signal(); |
562 return ETrue; |
505 // Start background read |
563 } |
506 OstTrace0(TRACE_SMASSSTORAGE_MEDIA, CTHREADCONTEXT_79, "Resuming Read Thread"); |
564 |
507 iThreadContext->Resume(); |
565 /** |
508 return ETrue; |
566 Discard the read buffer. This is used to force a cache miss when reading from |
509 } |
567 the same sectors that were just written. |
510 |
568 */ |
|
569 void CReadDriveThread::DiscardRead() |
|
570 { |
|
571 __PRINT(_L("Waiting on Read CS in DiscardRead...")); |
|
572 iThreadContext->iCritSect.Wait(); |
|
573 // +++ READ CS STARTS HERE +++ |
|
574 __PRINT(_L("Discarding pre-read buffer")); |
|
575 iCompleted = EFalse; |
|
576 iThreadContext->iBuffer.iDescReadPtr->iLength = 0; |
|
577 |
|
578 // +++ READ CS ENDS HERE +++ |
|
579 __PRINT(_L("Signalling Read CS in DiscardRead...")); |
|
580 iThreadContext->iCritSect.Signal(); |
|
581 } |
|
582 #endif // MSDC_MULTITHREADED |
511 #endif // MSDC_MULTITHREADED |
583 |
512 |