diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfile/sf_notifier.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfile/sf_notifier.h Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,430 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// f32\sfile\sf_notifier.h +// +// + +#include "sf_std.h" +#include "sf_pool.h" +#include "e32hashtab.h" +#include "cl_notification.h" +#include "f32notification.h" + +#ifndef SF_NOTIFIER_H +#define SF_NOTIFIER_H + +/** + * Number of notifications in TFsNotificationType that the client can set + * @internalTechnology + */ +const TInt KNumRegisterableFilters = 8; + +/* + * This determines the size of the CFsPool. + * Until we have read/write locks there is no point in this being more than 1. + * + * @internalTechnology + */ +const TInt KNotificationPoolSize = 1; + + +/** + * A CFsNotificationPathFilter is a simple class containing two HBufCs of the target to be notified about: + * 1 for the drive and path + * 1 for the filename + * + * A CFsNotificationPathFilter has a 1 to Many relationship with TFsNotificationTypeFilter + * + * @internalTechnology + */ +class CFsNotificationPathFilter + { +public: + static CFsNotificationPathFilter* NewL(const TDesC& aPath, const TDesC& aFilename); + ~CFsNotificationPathFilter(); +private: + void ConstructL(const TDesC& aPath, const TDesC& aFilename); + CFsNotificationPathFilter(); +public: + HBufC* iPath; + HBufC* iFilename; + }; + +/** + * A TFsNotificationTypeFilter is a class which contains a pointer to the associated path to monitor + * and the type of notification. + * + * @internalTechnology + */ +class TFsNotificationTypeFilter + { +public: + CFsNotificationPathFilter* iPathFilter; + TFsNotification::TFsNotificationType iNotificationType; + //As we are storing filters in filter-specific + //arrays then iNotificationType is potentially redundant. + }; + +//These typedefs are to appease the compiler as it does not like +//nested templated arguments. + /** + * @internalTechnology + */ +typedef RArray TFsNotificationTypeArray; +/** + * @internalTechnology + */ +typedef RArray TFsNotificationTypeDriveArray; + +class CFsNotificationBlock; //forward decl. + +/** + * CFsNotifyRequest is a file-server side object representation of an RFsNotify sub-session. + * + * @internalTechnology + */ +NONSHARABLE_CLASS(CFsNotifyRequest) : public CFsObject + { +public: + + /* + * Active means that the client is waiting for the first notification to be sent + * The status then changes to Outstanding when further notifications are sent to the buffer + * If the server overflows when in state EOutstanding then we move to state EOutstandingOverflow. + * From EOutstandingOverflow after the next call to RequestNotifications from the client, we must move to state EInactive. + * If we do not overflow then when RequestNotifications is called we can move back to state EActive. + * EInactive is when there are no notifications outstanding and request notifications hasn't been called. + */ + enum TNotifyRequestStatus + { + EActive, //Server waiting for a notification (filters added, RequestNotifications called) + EOutstanding, //Server waiting for client to call RequestNotifications, has notification(s) to send. + EOutstandingOverflow, //Server waiting for client to call RequestNotifications, has notification(s) to send, buffer has overflowed. + EInactive //Server waiting for RequestNotification, no notifications outstanding + }; + + static CFsNotifyRequest* NewL(); + virtual ~CFsNotifyRequest(); + + /* + * Returns the RArray for an index + * as returned from FsNotificationHelper::TypeToIndex() + */ + TFsNotificationTypeArray* FilterTypeList(TInt aDrive,TInt aIndex); + + //Removes all filters from iFilterList + TInt RemoveFilters(); + + //Add single filter to this request + TInt AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask); + + //Sets filter as active/inactive + void SetActive(TNotifyRequestStatus aValue); + + /** + *Get the status of this request. + *@See TNotifyRequestStatus + */ + TNotifyRequestStatus ActiveStatus(); + + /* + * Completes and frees notification request + * + * @param aIsCancel is used to determine whether + * to write back to the client or not when aReason != KErrNone. + * + * In the case of closing the subsession you shouldn't write back to the client. + */ + void CompleteClientRequest(TInt aReason,TBool aIsCancel=EFalse); + + //RfsNotify::RequestNotifications has been called + TInt SetClientMessage(const RMessage2& aClientMsg); + + /* + * Called from FsNotificationManager::HandleChange(), + * this function packages the data in to a CFsNotificationBlock in preperation for + * notification of this operation to the client. + * + * Calling of this function means that we are notifying about this operation. (all checks passed) + * + * aRequest can be NULL when the request doesn't come from the file server + * (such as when a media card is removed) + */ + TInt NotifyChange(CFsClientMessageRequest* aRequest, const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock); + + /* + * This function performs the IPC to the client's buffer. + */ + TInt SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize); + + //Closing this notification + void CloseNotification(); + + //Simple getter + TInt ClientMsgHandle(); + +private: + CFsNotifyRequest(); + void ConstructL(); + + //Check whether there is room for a new notification in the client's buffer + TBool ValidateNotification(TInt aNotificationSize, TInt& aServerTail); + + /* + * The iTailSemaphore is used so that many CFsNotificationBlocks can + * be processed concurrently. + * This lock ensures that the iServerTail is safe. + */ + //ToDo: This should be a ReadWriteLock + RFastLock iTailSemaphore; + + /* + * The iClientSyncLock is a Read/Write style lock whereby it is + * set up with the value of KNotificationPoolSize. + * When a block is allocated it calls wait on this lock. + * + * This lock is to ensure that all of the currently processing blocks are + * written before the client is updated. + * + * i.e. if two blocks are being processed concurrently and the second + * block is written we need to wait until the first one is also written + * before the client receives the updated tail. + */ + //ToDo: This should be a ReadWriteLock + RFastLock iClientSyncLock; + + + /* + * HashMap + * HashMap> + * HashMap>> + * + * Each value of iDrivesTypesFiltersMap is of type TFsNotificationTypeDriveArray + * associated with a particular drive. + * + * Each index of the TFsNotificationTypeDriveArray is a TFsNotificationTypeArray + */ + RHashMap iDrivesTypesFiltersMap; + + /* + * The iPathFilterList is an RPointerArray of CFsNotificationPathFilters. + * + * These are normally only accessed via a TFsNotificationTypeFilter (via iDrivesTypesFiltersMap), + * not via this array directly. + */ + RPointerArray iPathFilterList; + + RMessage2 iBufferMsg; //To update buffer + RMessage2 iClientMsg; //client notification request + + CSessionFs* iSession; //Session associated with this request (TFsSessionDisconnect::DoRequestL) + + TNotifyRequestStatus iNotifyRequestStatus; //Current status of this request + + //The following 3 variables must be aligned when modified. + TInt iClientHead; //Offset where the client should start reading from. + //If the server writes past this offset we must overflow the client. + + TInt iClientTail; //The end of the client's accessible range. + + TInt iServerTail; //The end of the server's accessible range. + //Overflow occurs if iServerTail becomes more than iClientHead. + + TInt iClientBufferSize; //Buffer size is word-aligned. + + friend class TFsNotificationBuffer; //For access to iClientBufferSize and iBufferMsg + friend class TFsNotificationRequest;//For access to iClientBufferSize + friend class FsNotificationManager; //For access to iSession + friend class TFsNotificationOpen; //For access to iSession + friend class TFsNotificationRemove; //For access to iDrivesTypesFiltersMap + }; + +/** + * A CFsNotificationBlock is a chunk of memory which is used to represent a notification + * such that a single IPC can be performed from server to client. + * + * CFsNotificationBlocks are stored in a CFsPool. + * + *@internalTechnology + */ +class CFsNotificationBlock + { +public: + static CFsNotificationBlock* New(); + ~CFsNotificationBlock(); + TAny* Data(); +private: + CFsNotificationBlock(); + TText8 iData[KMinNotificationBufferSize]; + }; + +/** + * Helper class to get certain attributes from or about a particular operation to used in a notification + * + * @internalTechnology + */ +class FsNotificationHelper + { +public: + static void NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType); + static void PathName(CFsClientMessageRequest& aRequest, TDes& aName); + static void NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aName); + static TInt NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName); + static TInt TypeToIndex(TFsNotification::TFsNotificationType aType); + static TFsNotification::TFsNotificationType NotificationType(TInt& aIndex); + static TInt DriveNumber(const TPtrC& aPath); + static void Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear); + }; + +/** + * The FsNotificationManager is a static object + * + *@internalTechnology + */ +class FsNotificationManager + { +public: + //New notification request from client + static void AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest); + + //Notification request cancel + static void RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest); + //Notification request cancel (session closed) + static void RemoveNotificationRequest(CSessionFs* aSession); + + /* A change has occurred represented by this request. + * Work out which CFsNotifyRequests are interested + * (if any) and call CFsNotifyRequest::NotifyChange. + */ + static void HandleChange(CFsClientMessageRequest& aRequest); + + /* A change has occurred represented by this request. + * Work out which CFsNotifyRequests are interested + * (if any) and call CFsNotifyRequest::NotifyChange. + * + * This override is used directly when we want to force a particular notification type + */ + static void HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType); + + /* + * This override is used directly when we want to specify the current operation's name (src) and notification type. + * + * aRequest can be NULL when the request doesn't come from the file server + * such as when a media card is removed, see LocalDrives::CompleteDriveNotifications + * + * @See LocalDrives::CompleteDriveNotifications(TInt aDrive) + */ + static void HandleChange(CFsClientMessageRequest* aRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType aType); + + //Initialise iNotifyRequests and iStaticNotification + static void OpenL(); + static TBool IsInitialised(); + + /* + * On CFsNotifyRequest closing, Close is called if this is the last request being removed. + * This removes all of the managers private data. + */ + static void Close(); + + /* + * Calls SetFilterRegister for every valid notification set in aMask. + */ + static void SetFilterRegisterMask(TUint aMask,TBool aAdd); + + /* + * Adds or Removes to the count of filters set up for a particular type + * This is a global count such that if there are no fiters for a particular type + * HandleChange doesn't need to do any iteration for that type. + */ + static void SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount = 1); + /* + * Get the number of registers filters set up on a particular type. + * @param aIndex the TFsNotificationType's index as determined from FsNotificationHelper::TypeToIndex + */ + static TInt& FilterRegister(TInt aIndex); + + /* + * Returns the number of CFsNotifyRequests set up + */ + static TInt Count(); + + /* + * Lock the iChainLock (currently not a ReadWriteLock) + */ + static void Lock(); + + /* + * Unlock iChainLock + */ + static void Unlock(); + +private: + + /* + * @internalTechnology + * Used by DoMatchFilter and DoHandleChange to control the flow of + * loop execution. + */ + enum TFsNotificationFilterMatch + { + EDifferent = 0x00, //Operation and Filters do not match. + EMatch = 0x01, //Operation and Filters do match. + EContinue = 0x02 //Data caged directory - Do not notify. + }; + + /* + * Checks whether aOperation matches the filter name and/or path set in aFilter. + */ + static TFsNotificationFilterMatch DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter); + + /* + * Iterates filters for a particular drive. + * Called from HandleChange + */ + static void DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray, TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType); + + /* + * Stores the CFsNotifyRequests + */ + static CFsObjectCon* iNotifyRequests; + + //As we are doing notifications 'in-place' which is multi-threaded + //we need to have locking to protect iNotifyRequests. + //ToDo: ReadWriteLock + static RFastLock iChainLock; + + /* + * Global register per filter type. + * Keeps a count of the number of filters set up for a particular type + * (NB: EMediaChange is reported regardless of filters set) + */ + static TInt iFilterRegister[KNumRegisterableFilters]; + + /* + * This is a pool of blocks which are server-side versions of TFsNotification. + * They are used so that we can have a single IPC from server to client. + * + * it will also be used for coalescing changes. + */ + static CFsPool* iPool; + + friend class CFsNotifyRequest; + friend class RequestAllocator; + friend class TFsNotificationSubClose; + }; + + +#endif /* SF_NOTIFIER_H */ + +