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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfile\sf_notifier.h
20 #include "e32hashtab.h"
21 #include "cl_notification.h"
22 #include "f32notification.h"
28 * Number of notifications in TFsNotificationType that the client can set
31 const TInt KNumRegisterableFilters = 8;
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.
39 const TInt KNotificationPoolSize = 1;
43 * A CFsNotificationPathFilter is a simple class containing two HBufCs of the target to be notified about:
44 * 1 for the drive and path
47 * A CFsNotificationPathFilter has a 1 to Many relationship with TFsNotificationTypeFilter
51 class CFsNotificationPathFilter
54 static CFsNotificationPathFilter* NewL(const TDesC& aPath, const TDesC& aFilename);
55 ~CFsNotificationPathFilter();
57 void ConstructL(const TDesC& aPath, const TDesC& aFilename);
58 CFsNotificationPathFilter();
65 * A TFsNotificationTypeFilter is a class which contains a pointer to the associated path to monitor
66 * and the type of notification.
70 class TFsNotificationTypeFilter
73 CFsNotificationPathFilter* iPathFilter;
74 TFsNotification::TFsNotificationType iNotificationType;
75 //As we are storing filters in filter-specific
76 //arrays then iNotificationType is potentially redundant.
79 //These typedefs are to appease the compiler as it does not like
80 //nested templated arguments.
84 typedef RArray<TFsNotificationTypeFilter> TFsNotificationTypeArray;
88 typedef RArray<TFsNotificationTypeArray> TFsNotificationTypeDriveArray;
90 class CFsNotificationBlock; //forward decl.
93 * CFsNotifyRequest is a file-server side object representation of an RFsNotify sub-session.
97 NONSHARABLE_CLASS(CFsNotifyRequest) : public CFsObject
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.
109 enum TNotifyRequestStatus
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
117 static CFsNotifyRequest* NewL();
118 virtual ~CFsNotifyRequest();
121 * Returns the RArray<TFsNotificationFilter> for an index
122 * as returned from FsNotificationHelper::TypeToIndex()
124 TFsNotificationTypeArray* FilterTypeList(TInt aDrive,TInt aIndex);
126 //Removes all filters from iFilterList
127 TInt RemoveFilters();
129 //Add single filter to this request
130 TInt AddFilterL(CFsNotificationPathFilter* aFilter, TUint aMask);
132 //Sets filter as active/inactive
133 void SetActive(TNotifyRequestStatus aValue);
136 *Get the status of this request.
137 *@See TNotifyRequestStatus
139 TNotifyRequestStatus ActiveStatus();
142 * Completes and frees notification request
144 * @param aIsCancel is used to determine whether
145 * to write back to the client or not when aReason != KErrNone.
147 * In the case of closing the subsession you shouldn't write back to the client.
149 void CompleteClientRequest(TInt aReason,TBool aIsCancel=EFalse);
151 //RfsNotify::RequestNotifications has been called
152 TInt SetClientMessage(const RMessage2& aClientMsg);
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.
159 * Calling of this function means that we are notifying about this operation. (all checks passed)
161 * aRequest can be NULL when the request doesn't come from the file server
162 * (such as when a media card is removed)
164 TInt NotifyChange(CFsClientMessageRequest* aRequest, const TDesC& aName, TFsNotification::TFsNotificationType aNotificationType, CFsNotificationBlock& aBlock);
167 * This function performs the IPC to the client's buffer.
169 TInt SynchroniseBuffer(CFsNotificationBlock& aBlock,TInt aServerTail, TInt aNotificationSize);
171 //Closing this notification
172 void CloseNotification();
175 TInt ClientMsgHandle();
181 //Check whether there is room for a new notification in the client's buffer
182 TBool ValidateNotification(TInt aNotificationSize, TInt& aServerTail);
185 * The iTailSemaphore is used so that many CFsNotificationBlocks can
186 * be processed concurrently.
187 * This lock ensures that the iServerTail is safe.
189 //ToDo: This should be a ReadWriteLock
190 RFastLock iTailSemaphore;
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.
197 * This lock is to ensure that all of the currently processing blocks are
198 * written before the client is updated.
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.
204 //ToDo: This should be a ReadWriteLock
205 RFastLock iClientSyncLock;
209 * HashMap<DriveNumber, TFsNotificationTypeDriveArray>
210 * HashMap<DriveNumber, RArray<TFsNotificationTypeArray>>
211 * HashMap<DriveNumber, RArray<RArray<TFsNotificationTypeFilter>>>
213 * Each value of iDrivesTypesFiltersMap is of type TFsNotificationTypeDriveArray
214 * associated with a particular drive.
216 * Each index of the TFsNotificationTypeDriveArray is a TFsNotificationTypeArray
218 RHashMap<TInt,TFsNotificationTypeDriveArray> iDrivesTypesFiltersMap;
221 * The iPathFilterList is an RPointerArray of CFsNotificationPathFilters.
223 * These are normally only accessed via a TFsNotificationTypeFilter (via iDrivesTypesFiltersMap),
224 * not via this array directly.
226 RPointerArray<CFsNotificationPathFilter> iPathFilterList;
228 RMessage2 iBufferMsg; //To update buffer
229 RMessage2 iClientMsg; //client notification request
231 CSessionFs* iSession; //Session associated with this request (TFsSessionDisconnect::DoRequestL)
233 TNotifyRequestStatus iNotifyRequestStatus; //Current status of this request
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.
239 TInt iClientTail; //The end of the client's accessible range.
241 TInt iServerTail; //The end of the server's accessible range.
242 //Overflow occurs if iServerTail becomes more than iClientHead.
244 TInt iClientBufferSize; //Buffer size is word-aligned.
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
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.
257 * CFsNotificationBlocks are stored in a CFsPool<CFsNotificationBlock>.
261 class CFsNotificationBlock
264 static CFsNotificationBlock* New();
265 ~CFsNotificationBlock();
268 CFsNotificationBlock();
269 TText8 iData[KMinNotificationBufferSize];
273 * Helper class to get certain attributes from or about a particular operation to used in a notification
275 * @internalTechnology
277 class FsNotificationHelper
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);
291 * The FsNotificationManager is a static object
295 class FsNotificationManager
298 //New notification request from client
299 static void AddNotificationRequestL(CFsNotifyRequest* aNotificationRequest);
301 //Notification request cancel
302 static void RemoveNotificationRequest(CFsNotifyRequest* aNotificationRequest);
303 //Notification request cancel (session closed)
304 static void RemoveNotificationRequest(CSessionFs* aSession);
306 /* A change has occurred represented by this request.
307 * Work out which CFsNotifyRequests are interested
308 * (if any) and call CFsNotifyRequest::NotifyChange.
310 static void HandleChange(CFsClientMessageRequest& aRequest);
312 /* A change has occurred represented by this request.
313 * Work out which CFsNotifyRequests are interested
314 * (if any) and call CFsNotifyRequest::NotifyChange.
316 * This override is used directly when we want to force a particular notification type
318 static void HandleChange(CFsClientMessageRequest& aRequest, TFsNotification::TFsNotificationType aType);
321 * This override is used directly when we want to specify the current operation's name (src) and notification type.
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
326 * @See LocalDrives::CompleteDriveNotifications(TInt aDrive)
328 static void HandleChange(CFsClientMessageRequest* aRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType aType);
330 //Initialise iNotifyRequests and iStaticNotification
332 static TBool IsInitialised();
335 * On CFsNotifyRequest closing, Close is called if this is the last request being removed.
336 * This removes all of the managers private data.
341 * Calls SetFilterRegister for every valid notification set in aMask.
343 static void SetFilterRegisterMask(TUint aMask,TBool aAdd);
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.
350 static void SetFilterRegister(TUint aFilter, TBool aAdd, TInt aCount = 1);
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
355 static TInt& FilterRegister(TInt aIndex);
358 * Returns the number of CFsNotifyRequests set up
363 * Lock the iChainLock (currently not a ReadWriteLock)
370 static void Unlock();
375 * @internalTechnology
376 * Used by DoMatchFilter and DoHandleChange to control the flow of
379 enum TFsNotificationFilterMatch
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.
387 * Checks whether aOperation matches the filter name and/or path set in aFilter.
389 static TFsNotificationFilterMatch DoMatchFilter(CFsClientMessageRequest* aRequest, const TDesC& aOperationName,CFsNotificationPathFilter& aFilter);
392 * Iterates filters for a particular drive.
393 * Called from HandleChange
395 static void DoHandleChange(TFsNotificationTypeArray* aFilterTypeArray, TInt& aSeenFilter, CFsClientMessageRequest* aRequest, CFsNotifyRequest* aNotifyRequest, const TDesC& aOperationName, TFsNotification::TFsNotificationType& aType);
398 * Stores the CFsNotifyRequests
400 static CFsObjectCon* iNotifyRequests;
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;
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)
412 static TInt iFilterRegister[KNumRegisterableFilters];
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.
418 * it will also be used for coalescing changes.
420 static CFsPool<CFsNotificationBlock>* iPool;
422 friend class CFsNotifyRequest;
423 friend class RequestAllocator;
424 friend class TFsNotificationSubClose;
428 #endif /* SF_NOTIFIER_H */