memspy/Driver/Kernel/Source/MemSpyDriverUserEventMonitor.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:57:15 +0200
changeset 0 a03f92240627
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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:
*
*/

#include "MemSpyDriverUserEventMonitor.h"

// System includes
#include <memspy/driver/memspydriverenumerationsshared.h>

// User includes
#include "MemSpyDriverUtils.h"
#include "MemSpyDriverDevice.h"
#include "MemSpyDriverOSAdaption.h"
#include "MemSpyDriverEventMonitor.h"

// Literal constants
_LIT( KMemSpyDriverClientEMMutexName, "MemSpyDriverClientEM_0x" );




DMemSpyDriverClientEMManager::DMemSpyDriverClientEMManager( DMemSpyDriverDevice& aDevice )
:   iDevice( aDevice )
    {
    }


DMemSpyDriverClientEMManager::~DMemSpyDriverClientEMManager()
	{
	TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::~DMemSpyDriverClientEMManager() - START"));

    NKern::ThreadEnterCS();
    FreeAllInstances();
    NKern::ThreadLeaveCS();

	TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::~DMemSpyDriverClientEMManager() - END"));
	}


TInt DMemSpyDriverClientEMManager::Create()
    {
    return KErrNone;
    }


DMemSpyDriverClientEM* DMemSpyDriverClientEMManager::EMOpen()
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMOpen() - START - iNextHandle: %d, iDevice: 0x%08x", iNextHandle+1, &iDevice ) );
    NKern::ThreadEnterCS();
    //
    DMemSpyDriverClientEM* object = new DMemSpyDriverClientEM( iDevice, ++iNextHandle );
    if  ( object != NULL )
        {
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMOpen() - calling create..." ) );
        const TInt error = object->Create();
        if ( error != KErrNone )
            {
            TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMOpen() - creation error: %d", error ) );
            delete object;
            object = NULL;
            }
        else
            {
            iEMInstances.Add( &object->iLink );
            }
        }
    //
    NKern::ThreadLeaveCS();
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMOpen() - END - object: 0x%08x", object ) );
    //
    return object;
    }


TInt DMemSpyDriverClientEMManager::EMClose( TUint aHandle )
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMClose() - START - aHandle: 0x%08x", aHandle ) );
    TInt error = KErrNotFound;
    //
    DMemSpyDriverClientEM* object = EMInstance( aHandle );
    if  ( object != NULL )
        {
        NKern::ThreadEnterCS();
        object->iLink.Deque();
        delete object;
        NKern::ThreadLeaveCS();
        error = KErrNone;
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMClose() - END - error: %d", error ) );
    return error;
    }


DMemSpyDriverClientEM* DMemSpyDriverClientEMManager::EMInstance( TUint aHandle )
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMInstance() - START - aHandle: 0x%08x", aHandle ) );
    DMemSpyDriverClientEM* ret = NULL;
    //
	const SDblQueLink* const anchor = &iEMInstances.iA;
	for (SDblQueLink* link = iEMInstances.First(); link != anchor; link = link->iNext )
		{
		DMemSpyDriverClientEM* object = _LOFF( link, DMemSpyDriverClientEM, iLink );
        //
        if  ( object->Handle() == aHandle )
            {
            ret = object;
            break;
            }
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::EMInstance() - END - aHandle: 0x%08x, ret: 0x%08x", aHandle, ret ) );
    return ret;
    }


void DMemSpyDriverClientEMManager::FreeAllInstances()
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::FreeAllInstances() - START") );
	
    SDblQueLink* link = iEMInstances.GetFirst();
	while( link )
		{
		DMemSpyDriverClientEM* object = _LOFF( link, DMemSpyDriverClientEM, iLink );
        delete object;
        link = iEMInstances.GetFirst();
		}

    TRACE_EM( Kern::Printf("DMemSpyDriverClientEMManager::FreeAllInstances() - END") );
    }





























DMemSpyDriverClientEM::DMemSpyDriverClientEM( DMemSpyDriverDevice& aDevice, TUint aHandle )
:   iDevice( aDevice ), iHandle( aHandle )
    {
    }


DMemSpyDriverClientEM::~DMemSpyDriverClientEM()
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::~DMemSpyDriverClientEM() - START - this: 0x%08x", this ));
	iDevice.EventMonitor().RequestEventsCancel( *this );

    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::~DMemSpyDriverClientEM() - calling NotifyChangesCancel..." ) );
    NotifyChangesCancel();
    
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::~DMemSpyDriverClientEM() - calling ResetPendingChanges..." ) );
    ResetPendingChanges();

	if  ( iLock )
		{
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::~DMemSpyDriverClientEM() - closing mutex..." ) );
		iLock->Close(NULL);
		}

    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::~DMemSpyDriverClientEM() - END - this: 0x%08x" ));
    }


TInt DMemSpyDriverClientEM::Create()
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::Create() - START - handle: 0x%08x", Handle() ) );

    // Create mutex
    TName name( KMemSpyDriverClientEMMutexName );
    name.AppendNumFixedWidth( (TUint) this, EHex, 8 );
    TInt error = Kern::MutexCreate( iLock, name, KMutexOrdNone );
    //
    if  ( error == KErrNone )
        {
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::Create() - calling global device driver event monitor...") );
        iDevice.EventMonitor().RequestEvents( *this );
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::Create() - END - handle: 0x%08x, err: %d", Handle(), error ) );
    return error;
    }


TInt DMemSpyDriverClientEM::NotifyChanges( DThread* aClientThread, TRequestStatus* aClientRS, TAny* aClientContext )
    {
	Kern::MutexWait( *iLock );

    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChanges() - START - handle: 0x%08x", Handle() ) );
    TInt r = KErrInUse;
    //
    if  ( iClientRS == NULL )
        {
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChanges() - saving client's request...") );
        iClientThread = aClientThread;
        iClientRS = aClientRS;
        iClientContext = aClientContext;
        //
        if	( !iPendingChanges.IsEmpty() )
			{
            TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyOnChange() - Have buffered changes - SENDING TO CLIENT IMMEDIATELY..." ) );
			
            // We have something in the pending buffer so we can
			// give it back to the client immediately.
	        DMemSpyDriverClientEM::TChange* cachedChange = _LOFF( iPendingChanges.First(), DMemSpyDriverClientEM::TChange, iLink );
			cachedChange->iLink.Deque();
			
            // Notify about change			
			CompleteClientsRequest( cachedChange->iCompletionCode, cachedChange->iContext );
			
			// Discard cached entry
            NKern::ThreadEnterCS();
			delete cachedChange;
            NKern::ThreadLeaveCS();
			}
        //
        r = KErrNone;
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChanges() - END - handle: 0x%08x, error: %d", Handle(), r ) );
	Kern::MutexSignal( *iLock );
    return r;
    }


TInt DMemSpyDriverClientEM::NotifyChangesCancel()
    {
	Kern::MutexWait( *iLock );
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChangesCancel() - START - handle: 0x%08x, iClientThread: 0x%08x, iClientRS: 0x%08x", Handle(), iClientThread, iClientRS ) );
    //
    TInt r = KErrNotReady;
    //
    if  ( iClientRS != NULL )
        {
        DThread* clientThread = iClientThread;
        TRequestStatus* clientRS = iClientRS;
        //
        iClientThread = NULL;
        iClientRS = NULL;
        iClientContext = NULL;
        //
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChangesCancel() - doing final request complete...") );
		Kern::RequestComplete( clientThread, clientRS, KErrCancel );
        r = KErrNone;
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::NotifyChangesCancel() - END - handle: 0x%08x, error: %d", Handle(), r ) );
	Kern::MutexSignal( *iLock );
    return r;
    }


TUint DMemSpyDriverClientEM::EMTypeMask() const
    {
    const TUint ret = EMemSpyEventThreadAdd  | EMemSpyEventThreadKill |
                      EMemSpyEventProcessAdd | EMemSpyEventProcessRemove | 
                      EMemSpyEventChunkAdd   | EMemSpyEventChunkDelete;
    return ret;
    }


void DMemSpyDriverClientEM::EMHandleProcessAdd( DProcess& aProcess )
    {
    const TUint pid = iDevice.OSAdaption().DProcess().GetId( aProcess );
    //
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeProcessCreate, pid );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::EMHandleProcessRemoved( DProcess& aProcess )
    {
    const TUint pid = iDevice.OSAdaption().DProcess().GetId( aProcess );
    //
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeProcessRemove, pid );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::EMHandleThreadAdd( DThread& aThread )
    {
    const TUint tid = iDevice.OSAdaption().DThread().GetId( aThread );
    //
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeThreadCreate, tid );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::EMHandleThreadKilled( DThread& aThread )
    {
    const TUint tid = iDevice.OSAdaption().DThread().GetId( aThread );
    //
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeThreadKill, tid );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::EMHandleChunkAdd( DChunk& aChunk ) 
    {
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeChunkAdd, (TUint) &aChunk );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::EMHandleChunkDeleted( DChunk& aChunk )
    {
	Kern::MutexWait( *iLock );
    CompleteClientsRequest( EMemSpyDriverEventTypeChunkDestroy, (TUint) &aChunk );
	Kern::MutexSignal( *iLock );
    }


void DMemSpyDriverClientEM::CompleteClientsRequest( TInt aCompletionCode, TUint aContext )
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - START - handle: 0x%08x, iClientThread: 0x%08x, iClientRS: 0x%08x, iClientContext: 0x%08x, aCompletionCode: %d, aContext: %d, changesPending: %d", Handle(), iClientThread, iClientRS, iClientContext, aCompletionCode, aContext, !iPendingChanges.IsEmpty() ) );
    //
    if  ( iClientRS != NULL )
        {
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - attempting to complete client's request...") );

        // First write context info
        const TInt writeErr = Kern::ThreadRawWrite( iClientThread, iClientContext, &aContext, sizeof(TUint) );
		if  ( writeErr != KErrNone )
		    {
            TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - write error: %d", writeErr ) );
            aCompletionCode = writeErr;
		    }

        // Now complete event - avoiding race conditions!
        DThread* clientThread = iClientThread;
        TRequestStatus* clientRS = iClientRS;
        //
        iClientThread = NULL;
        iClientRS = NULL;
        iClientContext = NULL;
        //
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - doing final request complete...") );
		Kern::RequestComplete( clientThread, clientRS, aCompletionCode );
        }
    else
        {
		// Buffer the change for next time around...
        TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - BUFFERING change event whilst client is AWOL...", this ) );
        NKern::ThreadEnterCS();
        
        DMemSpyDriverClientEM::TChange* cachedChange = new DMemSpyDriverClientEM::TChange( aCompletionCode, aContext );
        if  ( cachedChange )
            {
            iPendingChanges.Add( &cachedChange->iLink );
            }
        //
        NKern::ThreadLeaveCS();
        }
    //
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::CompleteClientsRequest() - END - handle: 0x%08x", Handle() ) );
    }


void DMemSpyDriverClientEM::ResetPendingChanges()
    {
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::ResetPendingChanges() - START - this: 0x%08x", this ) );
    NKern::ThreadEnterCS();
    //
    SDblQueLink* link = iPendingChanges.GetFirst();
	while( link )
		{
        DMemSpyDriverClientEM::TChange* cachedChange = _LOFF( link, DMemSpyDriverClientEM::TChange, iLink );
        delete cachedChange;
        link = iPendingChanges.GetFirst();
		}
    //
    NKern::ThreadLeaveCS();
    TRACE_EM( Kern::Printf("DMemSpyDriverClientEM::ResetPendingChanges() - END - this: 0x%08x", this ) );
    }