/*++

Microsoft Windows NT RPC Name Service
Copyright (c) 1995 Microsoft Corporation

Module Name:

    mutex.hxx

Abstract:

    This file contains definitions of classes which provide mutual exclusion.
    At the moment, only  an InterlockedInteger and a simple (interprocess) 
    Mutex are defined, but in future, a readers/writers version may be added.

Author:

    Satish Thatte (SatishT) 02/22/96  Created all the code below except where
									  otherwise indicated.

--*/

#ifndef __MUTEX_HXX__
#define __MUTEX_HXX__

class CInterlockedInteger   // created by MarioGo
    {
    private:
    LONG i;

    public:

    CInterlockedInteger(LONG i = 0) : i(i) {}

    LONG operator++(int)
        {
        return(InterlockedIncrement(&i));
        }

    LONG operator--(int)
        {
        return(InterlockedDecrement(&i));
        }

    operator LONG()
        {
        return(i);
        }
    };



/*++

Class Definition:

   CGlobalMutex

Abstract:

   This class implements an inter process mutex which controls 
   access to resources and data in shared memory.

--*/

class CGlobalMutex {

    HANDLE _hMutex; // Reference to system mutex object
							  // we are impersonating


public:

    CGlobalMutex(ORSTATUS &status);

    ~CGlobalMutex();

    void Enter() ;

    void Leave();
};





/*++

Class Definition:

    CProtectSharedMemory

Abstract:

    A convenient way to acquire and release a lock on a CGlobalMutex.
	Entry occurs on creation and exit on destruction of this object, and hence
	can be made to coincide with a local scope.  Especially convenient when
	there are multiple exit points from the scope (returns, breaks, etc.).


--*/

extern CGlobalMutex *gpMutex;   // global mutex to protect shared memory

class CProtectSharedMemory {

public:

	CProtectSharedMemory() {
		gpMutex->Enter();
	}

	~CProtectSharedMemory() {
		gpMutex->Leave();
	}
};



class CTempReleaseSharedMemory {

public:

	CTempReleaseSharedMemory() {
		gpMutex->Leave();
	}

	~CTempReleaseSharedMemory() {
		gpMutex->Enter();
	}
};



/******** inline methods ********/


inline
CGlobalMutex::CGlobalMutex(ORSTATUS &status) 
/*++

Routine Description:

    create a mutex and initialize the handle member _hMutex.

--*/
{	
    SECURITY_DESCRIPTOR sd;
    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
    {
        status = GetLastError();
        ComDebOut((DEB_OXID,"InitializeSecurityDescriptor Failed with %d\n",status));
        return;
    }

    if (! SetSecurityDescriptorDacl(
                                &sd,	// address of security descriptor
                                TRUE,	// flag for presence of discretionary ACL 
                                NULL,	// address of discretionary ACL
                                FALSE 	// flag for default discretionary ACL
                                )
       )
    {
        status = GetLastError();
        ComDebOut((DEB_OXID,"SetSecurityDescriptorDacl Failed with %d\n",status));
        return;
    }

    SECURITY_ATTRIBUTES sa;

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = &sd;
    sa.bInheritHandle = FALSE;

    _hMutex = CreateMutex(
            &sa,                  //  LPSECURITY_ATTRIBUTES   lpsa
            FALSE,                //  BOOL                    fInitialOwner
            GLOBAL_MUTEX_NAME     //  LPCTSTR                 lpszMutexName
            );

    //
    // Did the mutex create/open fail?
    //

    if ( !_hMutex )
    {
        status = GetLastError();
        ComDebOut((DEB_OXID,"Global Mutex Creation Failed with %d\n",status));
    }
    else
    {
        status = OR_OK;
    }
}


inline
CGlobalMutex::~CGlobalMutex() 
/*++

Routine Description:

    close the mutex handle.

--*/
{
	CloseHandle(_hMutex);
}


inline void
CGlobalMutex::Enter() 
/*++

Routine Description:

    Wait for the mutex to be signalled.

--*/
{
	WaitForSingleObject(_hMutex,INFINITE);
}


inline void
CGlobalMutex::Leave() 
/*++

Routine Description:

    Signal the mutex

--*/
{
	ReleaseMutex(_hMutex);
}


#endif // __MUTEX_HXX__