os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_notifier.h
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfile\sf_notifier.h
    15 // 
    16 //
    17 
    18 #include "sf_std.h"
    19 #include "sf_pool.h"
    20 #include "e32hashtab.h" 
    21 #include "cl_notification.h"
    22 #include "f32notification.h"
    23 
    24 #ifndef SF_NOTIFIER_H
    25 #define SF_NOTIFIER_H
    26 
    27 /**
    28  * Number of notifications in TFsNotificationType that the client can set
    29  * @internalTechnology
    30  */
    31 const TInt KNumRegisterableFilters = 8; 
    32 
    33 /*
    34  * This determines the size of the CFsPool.
    35  * Until we have read/write locks there is no point in this being more than 1.
    36  * 
    37  * @internalTechnology
    38  */
    39 const TInt KNotificationPoolSize = 1;
    40 
    41 
    42 /**
    43  * A CFsNotificationPathFilter is a simple class containing two HBufCs of the target to be notified about:
    44  * 1 for the drive and path
    45  * 1 for the filename
    46  *  
    47  *  A CFsNotificationPathFilter has a 1 to Many relationship with TFsNotificationTypeFilter
    48  *  
    49  * @internalTechnology
    50  */
    51 class CFsNotificationPathFilter
    52 	{
    53 public:
    54 	static CFsNotificationPathFilter* NewL(const TDesC& aPath, const TDesC& aFilename);
    55 	~CFsNotificationPathFilter();
    56 private:
    57 	void ConstructL(const TDesC& aPath, const TDesC& aFilename);
    58 	CFsNotificationPathFilter();
    59 public:
    60 	HBufC* iPath;
    61 	HBufC* iFilename;
    62 	};
    63 
    64 /**
    65  * A TFsNotificationTypeFilter is a class which contains a pointer to the associated path to monitor
    66  * and the type of notification.
    67  * 
    68  * @internalTechnology
    69  */
    70 class TFsNotificationTypeFilter
    71 	{
    72 public:
    73 	CFsNotificationPathFilter* iPathFilter;
    74 	TFsNotification::TFsNotificationType iNotificationType; 
    75 	//As we are storing filters in filter-specific
    76 	//arrays then iNotificationType is potentially redundant.
    77 	};
    78 
    79 //These typedefs are to appease the compiler as it does not like
    80 //nested templated arguments.
    81  /**
    82   *  @internalTechnology
    83   */
    84 typedef RArray<TFsNotificationTypeFilter> TFsNotificationTypeArray;
    85 /**
    86  * @internalTechnology
    87  */
    88 typedef RArray<TFsNotificationTypeArray> TFsNotificationTypeDriveArray;
    89 
    90 class CFsNotificationBlock; //forward decl.
    91 
    92 /**
    93  * CFsNotifyRequest is a file-server side object representation of an RFsNotify sub-session.   
    94  * 
    95  * @internalTechnology
    96  */
    97 NONSHARABLE_CLASS(CFsNotifyRequest) : public CFsObject
    98 	{
    99 public:
   100 	
   101 	/*
   102 	 * Active means that the client is waiting for the first notification to be sent
   103 	 * The status then changes to Outstanding when further notifications are sent to the buffer
   104 	 * If the server overflows when in state EOutstanding then we move to state EOutstandingOverflow.
   105 	 * From EOutstandingOverflow after the next call to RequestNotifications from the client, we must move to state EInactive.
   106 	 * If we do not overflow then when RequestNotifications is called we can move back to state EActive.
   107 	 * EInactive is when there are no notifications outstanding and request notifications hasn't been called. 
   108 	 */
   109 	enum TNotifyRequestStatus
   110 		{
   111 		EActive,				//Server waiting for a notification (filters added, RequestNotifications called)
   112 		EOutstanding,			//Server waiting for client to call RequestNotifications, has notification(s) to send.
   113 		EOutstandingOverflow,	//Server waiting for client to call RequestNotifications, has notification(s) to send, buffer has overflowed.
   114 		EInactive				//Server waiting for RequestNotification, no notifications outstanding 
   115 		};
   116 	
   117 	static CFsNotifyRequest* NewL();
   118 	virtual ~CFsNotifyRequest();
   119 	
   120 	/*
   121 	 * Returns the RArray<TFsNotificationFilter> for an index
   122 	 * as returned from FsNotificationHelper::TypeToIndex()
   123 	 */
   124 	TFsNotificationTypeArray* FilterTypeList(TInt aDrive,TInt aIndex);
   125 	
   126 	//Removes all filters from iFilterList
   127 	TInt RemoveFilters();
   128 
   129 	//Add single filter to this request
   130 	TInt AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask);
   131 
   132 	//Sets filter as active/inactive
   133 	void SetActive(TNotifyRequestStatus aValue);
   134 	
   135 	/**
   136 	 *Get the status of this request.
   137 	 *@See TNotifyRequestStatus 
   138 	 */ 
   139 	TNotifyRequestStatus ActiveStatus();
   140 	
   141 	/*
   142 	 * Completes and frees notification request
   143 	 * 
   144 	 * @param aIsCancel is used to determine whether 
   145 	 * to write back to the client or not when aReason != KErrNone.
   146 	 * 
   147 	 * In the case of closing the subsession you shouldn't write back to the client.
   148 	 */
   149 	void CompleteClientRequest(TInt aReason,TBool aIsCancel=EFalse);
   150 
   151 	//RfsNotify::RequestNotifications has been called
   152 	TInt SetClientMessage(const RMessage2& aClientMsg);
   153 
   154 	/* 
   155 	 * Called from FsNotificationManager::HandleChange(),
   156 	 * this function packages the data in to a CFsNotificationBlock in preperation for 
   157 	 * notification of this operation to the client.
   158 	 * 
   159 	 * Calling of this function means that we are notifying about this operation. (all checks passed)
   160 	 * 
   161 	 * aRequest can be NULL when the request doesn't come from the file server 
   162 	 * (such as when a media card is removed)
   163 	 */
   164 	TInt NotifyChange(CFsClientMessageRequest* aRequest, const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock);
   165 		
   166 	/*
   167 	 * This function performs the IPC to the client's buffer.
   168 	 */
   169 	TInt SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize);
   170 	
   171 	//Closing this notification
   172 	void CloseNotification();
   173 
   174 	//Simple getter
   175 	TInt ClientMsgHandle();
   176 	
   177 private:
   178 	CFsNotifyRequest();
   179 	void ConstructL();
   180 	
   181 	//Check whether there is room for a new notification in the client's buffer
   182 	TBool ValidateNotification(TInt aNotificationSize, TInt& aServerTail);
   183 	
   184 	/*
   185 	 * The iTailSemaphore is used so that many CFsNotificationBlocks can
   186 	 * be processed concurrently.
   187 	 * This lock ensures that the iServerTail is safe.
   188 	 */
   189 	 //ToDo:  This should be a ReadWriteLock
   190 	RFastLock iTailSemaphore;
   191 	
   192 	/*
   193 	 * The iClientSyncLock is a Read/Write style lock whereby it is 
   194 	 * set up with the value of KNotificationPoolSize.
   195 	 * When a block is allocated it calls wait on this lock.
   196 	 * 
   197 	 * This lock is to ensure that all of the currently processing blocks are
   198 	 * written before the client is updated.
   199 	 * 
   200 	 * i.e. if two blocks are being processed concurrently and the second 
   201 	 * block is written we need to wait until the first one is also written
   202 	 * before the client receives the updated tail.
   203 	 */
   204 	//ToDo: This should be a ReadWriteLock
   205 	RFastLock iClientSyncLock;
   206 	
   207 
   208 	/*
   209 	 * HashMap<DriveNumber, TFsNotificationTypeDriveArray>
   210 	 * HashMap<DriveNumber, RArray<TFsNotificationTypeArray>>
   211 	 * HashMap<DriveNumber, RArray<RArray<TFsNotificationTypeFilter>>>
   212 	 * 
   213 	 * Each value of iDrivesTypesFiltersMap is of type TFsNotificationTypeDriveArray 
   214 	 * associated with a particular drive.
   215 	 * 
   216 	 * Each index of the TFsNotificationTypeDriveArray is a TFsNotificationTypeArray
   217 	 */
   218 	RHashMap<TInt,TFsNotificationTypeDriveArray> iDrivesTypesFiltersMap;
   219 	
   220 	/*
   221 	 * The iPathFilterList is an RPointerArray of CFsNotificationPathFilters.
   222 	 * 
   223 	 * These are normally only accessed via a TFsNotificationTypeFilter (via iDrivesTypesFiltersMap),
   224 	 * not via this array directly.
   225 	 */
   226 	RPointerArray<CFsNotificationPathFilter> iPathFilterList;
   227 	
   228 	RMessage2 iBufferMsg; //To update buffer
   229 	RMessage2 iClientMsg; //client notification request
   230 	
   231 	CSessionFs* iSession; //Session associated with this request (TFsSessionDisconnect::DoRequestL)
   232 	
   233 	TNotifyRequestStatus iNotifyRequestStatus;	//Current status of this request
   234 	
   235 	//The following 3 variables must be aligned when modified.
   236 	TInt iClientHead;	//Offset where the client should start reading from.
   237 						//If the server writes past this offset we must overflow the client.
   238 	
   239 	TInt iClientTail;	//The end of the client's accessible range.
   240 	
   241 	TInt iServerTail;	//The end of the server's accessible range.
   242 						//Overflow occurs if iServerTail becomes more than iClientHead.
   243 	
   244 	TInt iClientBufferSize;		//Buffer size is word-aligned.
   245 	
   246 	friend class TFsNotificationBuffer;	//For access to iClientBufferSize and iBufferMsg
   247 	friend class TFsNotificationRequest;//For access to iClientBufferSize
   248 	friend class FsNotificationManager; //For access to iSession
   249 	friend class TFsNotificationOpen; //For access to iSession
   250 	friend class TFsNotificationRemove; //For access to iDrivesTypesFiltersMap
   251 	};
   252 
   253 /**
   254  * A CFsNotificationBlock is a chunk of memory which is used to represent a notification
   255  * such that a single IPC can be performed from server to client.
   256  * 
   257  * CFsNotificationBlocks are stored in a CFsPool<CFsNotificationBlock>. 
   258  * 
   259  *@internalTechnology
   260  */
   261 class CFsNotificationBlock
   262 	{
   263 public:
   264 	static CFsNotificationBlock* New();
   265 	~CFsNotificationBlock();
   266 	TAny* Data();
   267 private:
   268 	CFsNotificationBlock();
   269 	TText8 iData[KMinNotificationBufferSize];
   270 	};
   271 
   272 /**
   273  * Helper class to get certain attributes from or about a particular operation to used in a notification
   274  * 
   275  * @internalTechnology
   276  */
   277 class FsNotificationHelper
   278 	{
   279 public:
   280 	static void NotificationType(TInt aFunction,TFsNotification::TFsNotificationType& aNotificationType);
   281 	static void PathName(CFsClientMessageRequest& aRequest, TDes& aName);
   282 	static void NewPathName(CFsClientMessageRequest& aRequest, TPtrC& aName);
   283 	static TInt NotificationSize(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aNotificationType, const TDesC& aName);
   284 	static TInt TypeToIndex(TFsNotification::TFsNotificationType aType);
   285 	static TFsNotification::TFsNotificationType NotificationType(TInt& aIndex);
   286 	static TInt DriveNumber(const TPtrC& aPath);
   287 	static void Attributes(CFsClientMessageRequest& aRequest, TUint& aSet, TUint& aClear);
   288 	};
   289 
   290 /**
   291  * The FsNotificationManager is a static object
   292  * 
   293  *@internalTechnology
   294  */
   295 class FsNotificationManager
   296 	{
   297 public:
   298 	//New notification request from client
   299 	static void AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest);
   300 
   301 	//Notification request cancel
   302 	static void RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest);
   303 	//Notification request cancel (session closed)
   304 	static void RemoveNotificationRequest(CSessionFs* aSession);
   305 
   306 	/* A change has occurred represented by this request.
   307 	 * Work out which CFsNotifyRequests are interested
   308 	 * (if any) and call CFsNotifyRequest::NotifyChange.
   309 	 */
   310 	static void HandleChange(CFsClientMessageRequest& aRequest);
   311 	
   312 	/* A change has occurred represented by this request.
   313 	 * Work out which CFsNotifyRequests are interested
   314 	 * (if any) and call CFsNotifyRequest::NotifyChange.
   315 	 * 
   316 	 * This override is used directly when we want to force a particular notification type
   317 	 */
   318 	static void HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType);
   319 	
   320 	/* 
   321 	 * This override is used directly when we want to specify the current operation's name (src) and notification type.
   322 	 * 
   323 	 * aRequest can be NULL when the request doesn't come from the file server 
   324 	 * such as when a media card is removed, see LocalDrives::CompleteDriveNotifications
   325 	 * 
   326 	 * @See LocalDrives::CompleteDriveNotifications(TInt aDrive)
   327 	 */
   328 	static void HandleChange(CFsClientMessageRequest* aRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType aType);
   329 
   330 	//Initialise iNotifyRequests and iStaticNotification
   331 	static void OpenL();
   332 	static TBool IsInitialised();
   333 	
   334 	/*
   335 	 * On CFsNotifyRequest closing, Close is called if this is the last request being removed.
   336 	 * This removes all of the managers private data.
   337 	 */
   338 	static void Close();
   339 
   340 	/*
   341 	 * Calls SetFilterRegister for every valid notification set in aMask.
   342 	 */
   343 	static void SetFilterRegisterMask(TUint aMask,TBool aAdd);
   344 	
   345 	/*
   346 	 * Adds or Removes to the count of filters set up for a particular type
   347 	 * This is a global count such that if there are no fiters for a particular type 
   348 	 * HandleChange doesn't need to do any iteration for that type.
   349 	 */
   350 	static void SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount = 1);
   351 	/*
   352 	 * Get the number of registers filters set up on a particular type.
   353 	 * @param aIndex the TFsNotificationType's index as determined from FsNotificationHelper::TypeToIndex
   354 	 */
   355 	static TInt& FilterRegister(TInt aIndex);
   356 
   357 	/*
   358 	 * Returns the number of CFsNotifyRequests set up
   359 	 */
   360 	static TInt Count();
   361 	
   362 	/*
   363 	 * Lock the iChainLock (currently not a ReadWriteLock)
   364 	 */
   365 	static void Lock();
   366 	
   367 	/*
   368 	 * Unlock iChainLock
   369 	 */
   370 	static void Unlock();
   371 
   372 private:
   373   
   374     /*
   375      * @internalTechnology
   376 	 * Used by DoMatchFilter and DoHandleChange to control the flow of 
   377 	 * loop execution.
   378      */
   379     enum TFsNotificationFilterMatch
   380         {
   381         EDifferent  = 0x00, //Operation and Filters do not match.
   382         EMatch      = 0x01, //Operation and Filters do match.
   383         EContinue   = 0x02  //Data caged directory - Do not notify.
   384         };
   385     
   386     /*
   387      * Checks whether aOperation matches the filter name and/or path set in aFilter. 
   388      */
   389     static TFsNotificationFilterMatch DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter);
   390     
   391 	/*
   392 	 * Iterates filters for a particular drive.
   393 	 * Called from HandleChange
   394 	 */
   395 	static void DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray, TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType);
   396 	
   397 	/*
   398 	 * Stores the CFsNotifyRequests
   399 	 */
   400 	static CFsObjectCon* iNotifyRequests;
   401 	
   402 	//As we are doing notifications 'in-place' which is multi-threaded
   403 	//we need to have locking to protect iNotifyRequests.
   404 	//ToDo: ReadWriteLock
   405 	static RFastLock iChainLock;
   406 	
   407 	/*
   408 	 * Global register per filter type. 
   409 	 * Keeps a count of the number of filters set up for a particular type
   410 	 * (NB: EMediaChange is reported regardless of filters set)
   411 	 */
   412 	static TInt iFilterRegister[KNumRegisterableFilters];
   413 	
   414 	/*
   415 	 * This is a pool of blocks which are server-side versions of TFsNotification.
   416 	 * They are used so that we can have a single IPC from server to client.
   417 	 * 
   418 	 * it will also be used for coalescing changes.
   419 	 */
   420 	static CFsPool<CFsNotificationBlock>* iPool;
   421 	
   422 	friend class CFsNotifyRequest;
   423 	friend class RequestAllocator;
   424 	friend class TFsNotificationSubClose;
   425 	};
   426 
   427 
   428 #endif /* SF_NOTIFIER_H */
   429 
   430