|
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 |