/*!========================================================================
  
  @file         RTESync_BinarySemaphore.hpp
  @author       StefanP
  @ingroup      Synchronisation
  @brief        Semaphore class for non-counting semaphores (also called binary semaphores or Events
                                                             respectively)

  @since        2003-09-29  14:28
  @sa           

  =======================================================================

  \if EMIT_LICENCE
    
    ========== licence begin  GPL
    Copyright (c) 2003-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

  \endif
  ----------------------------------------------------------------------------*/


#ifndef RTESYNC_BINARYSEMAPHORE_HPP
#define RTESYNC_BINARYSEMAPHORE_HPP


/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/
#include    "RunTime/RTE_MessageList.hpp"
#include    "SAPDBCommon/SAPDB_ToString.hpp"
#include    "RunTime/RTE_TagFileHandlingUNIX.hpp" //UNIX only

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/
#if defined (_WIN32)
#define     RTE_INFINITE_WAIT   INFINITE   
#else
#define     RTE_INFINITE_WAIT   (SAPDB_ULong)(-1)
#endif

#if defined(_WIN32)
#define RTE_SYNC_UNDEF_SEM_ID        NULL
#else
#define RTE_SYNC_UNDEF_SEM_ID        ((RTESync_SemaphoreID)-1)
#endif

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/


/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/


#if defined(_WIN32)
    typedef SAPDB_Char *        RTESync_SemaphoreID;
#else
    typedef int                 RTESync_SemaphoreID;
#endif



/*!
    @class          RTESync_BinarySemaphore
    @brief    Semaphore class for non-counting semaphores (also called binary semaphores or Events
                                                                 respectively)
                    
                    Semaphore objects can be shared by different processes on UNIX. On NT it depends
                    on a identifier wich can be given to the the OPEN method. If no identifier is given (NULL)
                    the semaphore object is unnamed and can only be used in the creating process.

                    This class offers the basic methods for using binary semaphores such as WAIT and POST
                    methods.

                    At construction time one has to determine the open mode of the semaphore object. 
                    One can open a new object as well as an existing object. The constructor does not open 
                    the semaphore object. This is first done by a call to the OPEN method! 
 
*/

class   RTESync_BinarySemaphore
{
public:

enum SemRC {NoError = 0,
            Error,
            AlreadyExist,
            Timeout};


  /*!
     @brief   Constructor
                    
     @return        none

  */
    RTESync_BinarySemaphore         ();

  /*!
     @brief   Destructor
     @return        none

  */

    ~RTESync_BinarySemaphore        ();


  /*!
     @brief   Create a semaphore. After creation the state of the semaphore is
                    cleared (nonsignaled)
                     
     @param          pSemID [in]            - NT only: Name of the semaphore object or NULL (unnamed semaphore)
     @param          pSA [in]               - NT only: Pointer to security attributes 
     @param          userType [in]          - UNIX only: Type of user (ClientUser, KernelUser)
     @param          serverDB [in]          - UNIX only: Database name
     @param          mode [in]              - UNIX only: Permission 
     @param          uid [in]               - UNIX only: UID of the user to which the ownership of the semaphore 
                                              has to be transferred
     @param          messageList [in/out]   - Message list


     @return         RTESync_SemErrorOK, RTESync_SemErrorNOK, RTESync_SemErrorExist (NT only)

  */


#if defined (_WIN32)
    SemRC  Create       (RTESync_SemaphoreID const          pSemID,         
                         PSECURITY_ATTRIBUTES const         pSA,            
                         SAPDBErr_MessageList &             messageList);

#else
    SemRC  Create       (RTE_UserType const                 userType,       
                         RTE_DBName const                   serverDB,       
                         int const                          mode,           
                         uid_t const                        uid,            
                         RTESync_SemaphoreID &              semID,
                         SAPDBErr_MessageList &             messageList);

#endif

  /*!
     @brief   Open a semaphore 
                     
     @param          semID [in]             
     @param          userType [in]          - UNIX only: Type of user (ClientUser, KernelUser)
     @param          serverDB [in]          - UNIX only: Database name
     @param          messageList [in/out]   - Message list


     @return         RTESync_SemErrorOK, RTESync_SemErrorNOK

  */


#if defined (_WIN32)
    SemRC    Open       (RTESync_SemaphoreID const          semID,          
                         SAPDBErr_MessageList &             messageList);

#else
    SemRC    Open       (RTESync_SemaphoreID const          semID,          
                         RTE_UserType const                 userType,       
                         RTE_DBName const                   serverDB,       
                         SAPDBErr_MessageList &             messageList);

#endif

  /*!
     @brief    Post a semaphore (set the object state to signaled) 
                     
     @param          messageList [in/out]   - Message list

     @return         RTESync_SemErrorOK, RTESync_SemErrorNOK
                     

  */

                                     
    SemRC    Post       (SAPDBErr_MessageList &         messageList) const;


  /*!
     @brief   Wait for semaphore to be posted (signaled). If the semaphore is signaled the state 
                    is cleared by this function (set to nonsignaled state). 
                    Of course awakening from the wait state and clearing the semaphore is processed as an 
                    atomic instruction.
                     
     @param         timeout [in]            - Timeout value in milliseconds (NT only at present) 
     @param         messageList [in/out]    - Message list

     @return        RTESync_SemErrorOK, RTESync_SemErrorNOK, RTESync_SemErrorTimeout (NT only) 

  */

    SemRC    Wait       (SAPDB_ULong const              timeout,
                         SAPDBErr_MessageList &         messageList) const;

  /*!
     @brief   Close semaphore 
                     
     @param         messageList [in/out]    - Message list

     @return        RTESync_SemErrorOK, RTESync_SemErrorNOK 

  */

    SemRC    Close      (SAPDBErr_MessageList &         messageList);

  /*!
     @brief   Determines if the semaphore is already opened 

     @return        None
  */

    SAPDB_Bool  IsOpen     () 
        const
        {
            return (m_Handle != RTE_UNDEF_HANDLE);
        }

private:
    // It is not allowed to call the Copy Constructor from outside
	inline   RTESync_BinarySemaphore  (const RTESync_BinarySemaphore & sem) {;};


    RTESync_SemaphoreID     m_SemID;        //NT: Name, 
                                            //UNIX: semaphore identifier 
    RTE_SemaphoreHandle     m_Handle;       //NT: Handle to semaphore object
                                            //UNIX: SemID == Handle 

#if !defined (_WIN32)
    RTE_DBName                  m_ServerDB;
    RTE_UserType                m_UserType;    
#endif

};


inline SAPDB_ToStringClass SAPDB_ToString(RTESync_BinarySemaphore::SemRC     rcSem)
{
    switch (rcSem)
    {
    case RTESync_BinarySemaphore::NoError: 
        return SAPDB_ToStringClass("NOERROR");
    case RTESync_BinarySemaphore::Error: 
        return SAPDB_ToStringClass("ERROR");
    case RTESync_BinarySemaphore::AlreadyExist: 
        return SAPDB_ToStringClass("ALREADYEXIST");
    case RTESync_BinarySemaphore::Timeout: 
        return SAPDB_ToStringClass("TIMEOUT");
    default:                          
        break;
    }

    return SAPDB_ToStringClass((SAPDB_Int4)rcSem); 
}

#endif  /* RTESYNC_BINARYSEMAPHORE_HPP */
