#ifndef __RWSTD_MUTEX_H__
#define __RWSTD_MUTEX_H__   1
/***************************************************************************
 *
 * Declarations for class _RWSTDMutex and _RWSTDGuard.
 *
 * $Id: stdmutex.h,v 1.14 1996/08/28 01:30:38 smithey Exp $
 *
 ***************************************************************************
 *    
 *  Copyright 2000 Compaq Computer Corporation
 *
 *  COMPAQ Registered in U.S. Patent and Trademark Office.
 *
 *  Confidential computer software. Valid license from Compaq required for
 *  possession, use or copying. Consistent with FAR 12.211 and 12.212,
 *  Commercial Computer Software, Computer Software Documentation, and
 *  Technical Data for Commercial Items are licensed to the U.S. Government
 *  under vendor's standard commercial license.
 *
 ****************************************************************************
 *
 * (c) Copyright 1994-1996 Rogue Wave Software, Inc.
 * ALL RIGHTS RESERVED
 *
 * The software and information contained herein are proprietary to, and
 * comprise valuable trade secrets of, Rogue Wave Software, Inc., which
 * intends to preserve as trade secrets such software and information.
 * This software is furnished pursuant to a written license agreement and
 * may be used, copied, transmitted, and stored only in accordance with
 * the terms of such license and with the inclusion of the above copyright
 * notice.  This software and information or any other copies thereof may
 * not be provided or otherwise made available to any other person.
 *
 * Notwithstanding any other lease or license that may pertain to, or
 * accompany the delivery of, this computer software and information, the
 * rights of the Government regarding its use, reproduction and disclosure
 * are as set forth in Section 52.227-19 of the FARS Computer
 * Software-Restricted Rights clause.
 * 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7013.
 * Contractor/Manufacturer is Rogue Wave Software, Inc.,
 * P.O. Box 2328, Corvallis, Oregon 97339.
 *
 * This computer software and information is distributed with "restricted
 * rights."  Use, duplication or disclosure is subject to restrictions as
 * set forth in NASA FAR SUP 18-52.227-79 (April 1985) "Commercial
 * Computer Software-Restricted Rights (April 1985)."  If the Clause at
 * 18-52.227-74 "Rights in Data General" is specified in the contract,
 * then the "Alternate III" clause applies.
 *
 ***************************************************************************
 *
 * This class is a portable implementation of a simple mutex lock
 * to be used for synchronizing multiple threads within a single process.
 * It is not suitable for use among threads of different processes.
 * This code was taken from the tools mutex.h.
 * 
 ***************************************************************************/
/***************************************************************************
 * 
 * This header is for Internal Use Only.
 *
****************************************************************************/
#include <stdcomp>
#include <stddefs>

#ifdef _RWSTD_MULTI_THREAD /* This class only relevant in MT situation */

#if defined(__DECCXX) 
#include <stl_macros>

#ifdef __PRAGMA_ENVIRONMENT
#   pragma __environment __save
#   pragma __environment __cxx_header_defaults
#endif

typedef void * _RWSTDMutexType;

#if !defined(__DECFIXCXXL1081)
#  if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#  pragma __extern_prefix __save
#  pragma __extern_prefix "CXXL$" 
#  endif
    extern int _RWcxx_locale_global_is_initialized;
    extern int _RWcxx_locale_id_imp_is_initialized;
#  if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#   pragma __extern_prefix __restore
#  endif
#endif
#elif defined(sun)          /* assuming Solaris 2.1 or greater */
#include <synch.h>
typedef mutex_t _RWSTDMutexType;
#elif defined(_RW_POSIX_THREADS)
#include <pthread.h>
typedef pthread_mutex_t _RWSTDMutexType;
#define _RWSTD_NEEDS_SEM_INIT
#elif defined(__WIN32__)
#include <windows.h>
typedef CRITICAL_SECTION _RWSTDMutexType;
#define _RWSTD_NEEDS_SEM_INIT
#elif defined(__OS2__)
#include <exception>
#define INCL_DOSSEMAPHORES
#define _RWSTD_NEEDS_SEM_INIT
#include <os2.h>
typedef HMTX _RWSTDMutexType;
extern const char* _RWrw_mutex_exception;

class _RWSTDExport thread_error : public exception
{
  public:
    thread_error () _RWSTD_THROW_SPEC_NULL : exception( )
    { ; }
    virtual const char * what () const  _RWSTD_THROW_SPEC_NULL
    {
        return _RWrw_mutex_exception;
    }
};                            

#else
#error Class _RWSTDMutex is not yet supported in this environment
#endif

#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#pragma __extern_prefix __save
#pragma __extern_prefix "CXXL$" 
#endif

class _RWSTDMutex
{
  private:

    _RWSTDMutexType mutex;
#if defined(_RWSTD_NEEDS_SEM_INIT)
    int initFlag;
#endif

#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
    int cma_mutex_created;
#endif

    void init ();

#if defined(__DECCXX) && !defined(__DECFIXCXXL1137) && defined(__MODEL_ANSI) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))
    void allocate_mutex ();
    void deallocate_mutex ();
#endif
    //
    // Disallow copying and assignment.
    //
    _RWSTDMutex (const _RWSTDMutex&);
    _RWSTDMutex& operator= (const _RWSTDMutex&);

public:

  enum StaticCtor { staticCtor };

  _RWSTDMutex ();             // Construct the mutex.
  _RWSTDMutex (StaticCtor);   // Some statics need special handling.
  ~_RWSTDMutex ();            // Destroy the mutex.

  void acquire ();           // Acquire the mutex.
  void release ();           // Release the mutex.
};

class _RWSTDGuard
{
  private:

    _RWSTDMutex& rwmutex;

  public:

    _RWSTDGuard  (_RWSTDMutex& m);  // Acquire the mutex.
    ~_RWSTDGuard ();               // Release the mutex.
};

/*
** For those OSs that require a non-zero mutex, we must treat static 
** mutexes specially; they may not be initialized when we need them.
** For efficiency, we do conditional compilation in several methods
** based on that need.
*/

inline _RWSTDMutex::_RWSTDMutex (_RWSTDMutex::StaticCtor)
{
    //
    // Empty, because acquire() may already have been used.
    //
}

inline _RWSTDMutex::~_RWSTDMutex () 
{ 
#if defined(_RWSTD_NEEDS_SEM_INIT)
    if (0 == initFlag)
        return;
    else
        initFlag = 0;
#endif
#if defined(__DECCXX)
#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
    if ( cma_mutex_created )
#endif
    __CXX_MUTEX_DESTROY((void*&)mutex);
#if defined(__DECCXX) && !defined(__DECFIXCXXL1137) && defined(__MODEL_ANSI) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))
    deallocate_mutex();
#endif
#elif defined(sun)
    mutex_destroy(&mutex); 
#elif defined(_RW_POSIX_THREADS)
    pthread_mutex_destroy(&mutex); 
#elif defined(__WIN32__)
    DeleteCriticalSection(&mutex);
#elif defined(__OS2__)
    APIRET rv;
    _RWSTD_THROW_NO_MSG(0 != (rv = DosCloseMutexSem(mutex)),
                thread_error);
#endif
}


void inline _RWSTDMutex::init ()
{ 
#if defined(__DECCXX)
#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
    if ( __CXX_MUTEX_CREATE((void*&)mutex) == 0 ) cma_mutex_created = 1;
    else                                          cma_mutex_created = 0;
#else
    __CXX_MUTEX_CREATE((void*&)mutex);
#endif
#elif defined(sun)
    mutex_init(&mutex, USYNC_THREAD, NULL); 
#elif defined(_RW_POSIX_THREADS)
   #ifdef SNI_SINIX
    pthread_mutex_init(&mutex, pthread_attr_default);
   #else
    pthread_mutex_init(&mutex, &pthread_attr_default);	
   #endif
#elif defined(__WIN32__)
    InitializeCriticalSection(&mutex);
#elif defined(__OS2__)
    APIRET rv;
    _RWSTD_THROW_NO_MSG(0 != (rv = DosCreateMutexSem(0,&mutex,DC_SEM_SHARED,FALSE)),
                thread_error);
#endif
#if defined(_RWSTD_NEEDS_SEM_INIT)
    initFlag = 1;
#endif
}  

inline _RWSTDMutex::_RWSTDMutex () 
{ 
#if defined(__DECCXX) && !defined(__DECFIXCXXL1137) && defined(__MODEL_ANSI) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))
  allocate_mutex();
#endif
  init(); 
}  // Initialize the mutex.   

inline void _RWSTDMutex::acquire ()
{ 
#if defined(_RWSTD_NEEDS_SEM_INIT)
    if(0 == initFlag)
        init();
#endif
#if defined(__DECCXX)
#if defined(__DECCXX) && !defined(__DECFIXCXXL1137) && defined(__MODEL_ANSI) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))
    if (!mutex) {
	allocate_mutex ();
#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
	if ( __CXX_MUTEX_CREATE((void*&)mutex) == 0 ) cma_mutex_created = 1;
	else                                          cma_mutex_created = 0;
#else
	__CXX_MUTEX_CREATE((void*&)mutex);
#endif
    }
#endif
#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
    if ( cma_mutex_created )
#endif
    __CXX_MUTEX_LOCK((void*&)mutex);
#elif defined(sun)
    mutex_lock(&mutex);    
#elif defined(_RW_POSIX_THREADS)
    pthread_mutex_lock(&mutex);    
#elif defined(__WIN32__)
    EnterCriticalSection(&mutex);
#elif defined(__OS2__)
    APIRET rv;
    _RWSTD_THROW_NO_MSG(0 != (rv = DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)),
               thread_error); 
#endif
}

inline void _RWSTDMutex::release ()
{ 
#if defined(__DECCXX)
#if defined(__DECCXX) && !defined(__DECFIXCXXL1564) && !defined(__linux) \
    && ((defined(__MODEL_ARM) \
    && (defined(__unix) || (defined(__VMS) && (__VMS_VER >= 70000000)))) \
    || (defined(__VMS) && (__VMS_VER < 70000000)))
    if ( cma_mutex_created )
#endif
    __CXX_MUTEX_UNLOCK((void*&)mutex);
#elif defined(sun)
    mutex_unlock(&mutex);  
#elif defined(_RW_POSIX_THREADS)
    pthread_mutex_unlock(&mutex);  
#elif defined(__WIN32__)
    LeaveCriticalSection(&mutex);
#elif defined(__OS2__)
    APIRET rv;
    _RWSTD_THROW_NO_MSG(0 != (rv = DosReleaseMutexSem(mutex)),
                thread_error);
#endif
}


inline _RWSTDGuard::_RWSTDGuard (_RWSTDMutex& m) : rwmutex(m)
{
    rwmutex.acquire();
}

inline _RWSTDGuard::~_RWSTDGuard () { rwmutex.release(); }

#if defined(__DECCXX) && !defined(__DECFIXCXXL1078)
class _RWSTDlocale_global_Mutex : public _RWSTDMutex
{
public:
    _RWSTDlocale_global_Mutex () {
           _RWcxx_locale_global_is_initialized = 1;
    }
    ~_RWSTDlocale_global_Mutex () {
           _RWcxx_locale_global_is_initialized = 0;
    }
};
class _RWSTDlocale_id_imp_Mutex : public _RWSTDMutex
{
public:
    _RWSTDlocale_id_imp_Mutex () {
           _RWcxx_locale_id_imp_is_initialized = 1;
    }
    ~_RWSTDlocale_id_imp_Mutex () {
           _RWcxx_locale_id_imp_is_initialized = 0;
    }
};
#endif

#if defined(__DECCXX) && !defined(__DECFIXCXXL1429)
#define STDGUARD(a) _RWSTDGuard tmpobj(a)
#else
#define STDGUARD(a) _RWSTDGuard(a)
#endif

#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#   pragma __extern_prefix __restore
#endif

#if defined(__DECCXX)
#   ifdef __PRAGMA_ENVIRONMENT
#      pragma __environment __restore
#   endif
#endif
#else
#define STDGUARD(a) 
#endif  /*_RWSTD_MULTI_THREAD*/
#endif  /*__RWSTD_MUTEX_H__*/
