Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 75
Текст из файла (страница 75)
Requests that involve both a source and a destination path, such as RFs::Rename() and RFile::Replace(), alsouse the second TParse member, iDest.Each request processed by the server needs a separate request object,and it is the job of the RequestAllocator class to manage theallocation and issuing of new requests. To keep request handling time as354THE FILE SERVERshort as possible, the request allocator preallocates blocks of empty clientrequest objects. During file server startup, when the first client request isreceived, it creates the first block of fifteen request objects and adds themto a free list.
If ever a request object is required but the allocator’s free listis empty, it then allocates a further block of fifteen request objects – upto a maximum of 45. If the allocator ever needs more objects than this,it switches to a new strategy, whereby it allocates and frees individualrequest objects.The allocator is responsible for returning the correct type of object forthe particular request. When a request object is no longer required, theserver informs the allocator, and it returns the object to the free pool.However, the file server has to be able to handle session and subsession closure requests without the possibility of failure. This means thatfor these requests, it must not be necessary for the RequestAllocatorto issue new request objects, in case there are none free and there is notenough free memory to allocate a new one.
To cope with this, we ensurethat the file server always allocates the necessary request objects aheadof receiving a session or sub-session close request. We do this like so:• Sub-session closure. Each request to open a sub-session results inthe request allocator setting aside an internal request object, DispatchObjectCloseOp, to handle sub-session closure• Session closure. This involves two further types of request in additionto sub-session closure. These are:◦ A request issued from the main thread to the disconnect thread tocommence session disconnect. Every CSessionFs object has a‘‘SessionDiconnectOp’’ message request object as one of itsprivate members (iDisconnectRequest) – see Figure 9.3◦ A request to clean up outstanding requests for the session.
Thesession disconnect thread has a CancelSessionOp internalrequest object as one of its private members (CDisconnectThread::iRequest) – see Figure 9.6.9.3.2.2 Server threadsAs I have already mentioned, as well as the main file server thread, thereare two other types of file server threads: the drive threads and the sessiondisconnect thread. Unlike the main thread, which processes each newrequest as it is received, these other threads may be busy or blockedwhen a new request arrives, and so they employ a request queue tohold any pending requests.
The base class CRequestThread (shownin Figure 9.6) encapsulates a file server thread that accepts requests intoa queue and then processes them. Requests can be added to either thestart or the end of its doubly linked list, iList. The fast semaphoreTHE FILE SERVER355iListLock prevents access to the list from more than one thread atonce. From the CRequestThread entry point, the thread initializesitself and then calls CRequestThread::Receive() in readiness toreceive requests.
This method waits for a request to arrive from anotherthread – at which point it calls the request’s Process() method. Whilethe request list is empty, CRequestThread waits on the semaphoreiWaitingLock. This is signaled by other threads whenever they delivera new request and the CRequestThread is idle.The class CDriveThread, which is derived from CRequestThread,handles requests that are carried out on a particular logical drive. The fileserver creates an instance of this class for each asynchronous drive onthe phone, when the drive is mounted. The FsThreadManager class,which contains only static members, manages drive thread allocationand access.
When the file server needs to mount a file system on alogical drive, its main thread calls the FsThreadManager to createthe corresponding drive thread. However, the mounting of a file systeminvolves an access to the disk itself, and this can only be done from thecorrect drive thread, so the main thread then sends a mount request tothe newly created drive thread. On drive dismount, the drive thread exits,but the file server does not free the drive thread object.The class CDisconnectThread, also derived from CRequestThread, handles session disconnect requests. The file server createsone instance of this class during startup to handle all session disconnectrequests. This object is never deleted.9.3.2.3 Synchronous request handlingFigure 9.7 shows the program flow for the synchronous request:RFs::Drive().
(This request returns drive information to the client.)CSessionFs::ServiceL()RequestAllocator::GetMessageRequest()CFsRequest::Dispatch()TOperation::DoRequestL()RFs::Drive()Mainfile serverthreadRMessagePtr2::Complete()Figure 9.7 Program flow for a synchronous requestOn receiving the request, the file server calls CSessionFs::ServiceL() which executes in the main thread. This acquiresa request object, identifies the appropriate TOperation object for thisrequest type and then dispatches the request. CFsRequest::Dispatch() first calls TOperation::Initialise() to validate the356THE FILE SERVERarguments supplied by the client.
Next it checks whether or not theoperation is synchronous using TOperation::IsSync(). Since therequest is synchronous, the main thread processes the request by callingTOperation::DoRequestL(). Finally, the main thread completes theclient request by calling RMessagePtr2::Complete().9.3.2.4 Asynchronous request handlingFigure 9.8 shows the program flow for the asynchronous request RFile::Create() (which creates and opens a file).CSessionFs::ServiceL()RequestAllocator::GetMessageRequest()CFsRequest::Dispatch()Mainfile serverthreadRFile::Create()CFsRequest'EFsFileCreate'Request QueueRMessagePtr2::Complete()DrivethreadFSYCRequestThread::Receive()TOperation::DoRequestL()Figure 9.8 Program flow for an asynchronous requestOn receiving the request, again the file server calls CSessionFs::ServiceL() to acquire a request object and initialize it with theappropriate TOperation object. Still in the main thread, CFsRequest::Dispatch() calls TOperation::Initialise(), whichparses the name of the file supplied.
This time, however, the call toTOperation::IsSync() reveals that the operation is asynchronous,and so the main thread dispatches the request to the appropriate drivethread. Once it has done this, it is able to accept other client requests.When the drive thread retrieves the request from its queue, it processes it by calling TOperation::DoRequestL(). This involvesinteraction with the file system and the underlying media sub-system.Finally, the drive thread completes the client request by calling RMessagePtr2::Complete().9.3.2.5 Session disconnectionFigure 9.9 shows the first phase of program flow for session disconnection,RFs::Close(). On receiving the request, the file server’s main threadTHE FILE SERVER357CSessionFs::Disconnect()CFsRequest::Dispatch()RFs::Close()Mainfile serverthreadFSY(for sync drives)CFsRequest'SessionDiscOp'SessiondisconnectthreadCRequestThread::Receive()TOperation::DoRequestL()CFsRequest::Dispatch()CFsRequest'CancelSessionOp'Request QueueRequest QueueDrivethreadCRequestThread::Receive()TOperation::DoRequestL()Figure 9.9Program flow for the first phase of session disconnectioncalls CSessionFs::Disconnect().
This method first closes any opensub-session objects for synchronous drives. (They can’t be closed later,when the disconnect thread issues sub-session close requests to theasynchronous drives, because the main thread is not designed to acceptinternal requests.)The next phase is the cleanup of any outstanding requests for thesession. However, the main thread passes the responsibility for this andthe completion of session disconnection to the disconnect thread bydispatching a ‘‘disconnect session’’ (SessionDiconnectOp) requestto it. (Remember that for session disconnect, the server can’t use therequest allocator to acquire this request object, and instead it must usethe session’s request object: CSessionFs::iDisconnectRequest. Idiscussed this in Section 9.3.2.1.)When the disconnect thread retrieves the request from its queue, itissues an internal CancelSessionOp request to each drive thread in358THE FILE SERVERturn, asking each thread to cancel any requests queued for the sessionin question.
(Requests in progress will be allowed to complete, sincethe drive thread doesn’t check its queue again until it has completedits current request). The cancel request is inserted at the front of eachdrive thread queue, so that it will be the next request fetched by eachdrive thread. Each drive thread will later signal the completion of itsCancelSessionOp request to the disconnect thread.Figure 9.10 shows the second phase of the program flow for sessiondisconnection, RFs::Close(). Now that the disconnect thread hasensured the cleanup of any outstanding requests for the session, it isable to finish processing the ‘‘disconnect session’’ request it receivedfrom the main thread. If any sub-sessions objects remain open – onlyfor asynchronous drives now – then the disconnect thread closes them.Sub-session closure may require the server to write to a disk, so it doesthis by issuing another internal request, DispatchObjectCloseOp, toeach drive concerned.~CSessionFs()CFsDispatchObject::Close()CFsRequest::Dispatch()RMessagePtr2::Complete()SessiondisconnectthreadCFsRequest'DispatchObjectCloseOp'Request QueueDrivethreadFSYCRequestThread::Receive()TOperation::DoRequestL()Figure 9.10 Program flow for the second phase of session disconnectionAgain each drive thread signals back completion to the disconnectthread.
Finally, the session-disconnect thread completes the originalclient request by calling RMessagePtr2::Complete().THE FILE SERVER3599.3.3 Interfacing with the file systemFigure 9.11 shows a diagram of the server-side classes that form theinterface with a file system, with a FAT file system implementation shownas an example. I will now describe these classes.TOperationCFsMessageRequestiScratchValue : TUintiOperationDoRequest()Initialise()1iDrive1TDriveiCurrentMount : CMountCB*iDriveNumber : TIntiAtt : TUintiChanged : TBooliSubstedDrive : TDrive*iSubst : HBufC*iFsy1iDriveiMountiMountCDirCBnCFileSystemCMountCBiVolumeName : HBufC*iUniqueID : TUintiSize : TInt64iLockMount : TIntiMountQCFileCBiMountEFILE.EXEEFAT.FSYCFatFileSystemCFatMountCBCFatFileCBCFatDirCBFigure 9.11 The F32 server-side classes forming the interface with the file system9.3.3.1 TDrive classWe’ve seen that the file server supports 26 drives (A: to Z:); the TDriveclass is the file server’s abstraction for a logical drive.