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