//
//  Fichier : Question_01.cxx
//
//  cree le : 27/11/1999
//
//  par     : D. Mathieu
//
//  Contenu : Test de TPs systeme 2 - question 1
//

#include <iostream>

#include "COperation.h"
#include "nsSysteme.h"
#include "CExc.h"

class CSemaphore
{
  private :
    bool m_Proprietaire;

  protected :
    int  m_Id;

  public :

    // Question 1.1 -

    // CSemaphore (const char * const Nom);

    CSemaphore (const char * const Nom, const int NbreRessources = 1);

    // Question 1.1 - suite

    ~CSemaphore (void);

    void P (void);
    void V (void);

    // Question 1.2 -

    bool P_WouldBlock (void);

    // Question 1.2 - suite

}; // CSemaphore

// Question 1.1 - suite

inline CSemaphore::CSemaphore (const char * const Nom,
                             const int NbreRessources = 1)
{
    try
    {
        m_Id = nsSysteme::semget (atoi (Nom), 1, IPC_EXCL | IPC_CREAT | 0700);
        nsSysteme::semctl (m_Id, 0, SETVAL, NbreRessources);
        m_Proprietaire = true;
    }
    catch (const CExcFctSystIPC & Exc)
    {
        if (Exc.GetErrno () != EEXIST) throw;
        m_Id = nsSysteme::semget (atoi (Nom), 1, IPC_PRIVATE);
        m_Proprietaire = false;
    }

}  //  CSemaphore()

inline CSemaphore::~CSemaphore (void)
{
    if (m_Proprietaire) nsSysteme::semctl (m_Id);

}  //  ~CSemaphore()

inline void CSemaphore::P (void)
{
    COperation Op (0, -1);
    nsSysteme::semop (m_Id, & Op, 1);

}  //  P()

// Question 1.2 - suite

inline bool CSemaphore::P_WouldBlock (void)
{
    try
    {
        COperation Op (0, -1, IPC_NOWAIT);
        nsSysteme::semop (m_Id, & Op, 1);
        return false;
    }
    catch (const CExcFctSystIPC & Exc)
    {
        if (EAGAIN != Exc.GetErrno ()) throw;
        return true;
    }

}  //  P_WouldBlock()

inline void CSemaphore::V (void)
{
    COperation Op (0, 1);
    nsSysteme::semop (m_Id, & Op, 1);

}  //  V()

// Question 1.3

class CSemaphoreUser : public CSemaphore
{
  private :
    int m_NbreMinimal;

  public :
     CSemaphoreUser (const char * const Nom,
                     const int NbreRessources,
                     const int NbreMinimal = 0);
    void P (void);
    bool P_WouldBlock (void);

}; // CSemaphoreUser

inline CSemaphoreUser::CSemaphoreUser (const char * const Nom,
                                       const int NbreRessources,
                                       const int NbreMinimal = 0)
    : CSemaphore (Nom, NbreRessources), m_NbreMinimal (NbreMinimal) {}

inline void CSemaphoreUser::P (void)
{
    COperation Op [2];

    Op [0].SetNum (0);
    Op [0].SetOp  (-1 - m_NbreMinimal);
    Op [0].SetFlg (0);

    Op [1].SetNum (0);
    Op [1].SetOp  (m_NbreMinimal);
    Op [1].SetFlg (0);

    nsSysteme::semop (m_Id, Op, 2);

}  //  P()

// Hors question

inline bool CSemaphoreUser::P_WouldBlock (void)
{
    try
    {
        COperation Op [2];

        Op [0].SetNum (0);
        Op [0].SetOp  (-1 - m_NbreMinimal);
        Op [0].SetFlg (IPC_NOWAIT);

        Op [1].SetNum (0);
        Op [1].SetOp  (m_NbreMinimal);
        Op [1].SetFlg (0);

        nsSysteme::semop (m_Id, Op, 2);

        return false;
    }
    catch (const CExcFctSystIPC & Exc)
    {
        if (EAGAIN != Exc.GetErrno ()) throw;
        return true;
    }

}  //  P_WouldBlock()

int ppal (int argc, char * argv []) throw (CExc)
{
    if (1 != argc) throw CExc (string ("Usage : ") + argv [0]);

    // Test du semaphore "user" et de P_WouldBlock :

    CSemaphoreUser SemUser ("123321", 5, 2);

    if (SemUser.P_WouldBlock ())
        cout << "Aurait ete bloquant" << endl;
    else
        cout << "N'a pas bloque" << endl;

    if (SemUser.P_WouldBlock ())
        cout << "Aurait ete bloquant" << endl;
    else
        cout << "N'a pas bloque" << endl;

    if (SemUser.P_WouldBlock ())
        cout << "Aurait ete bloquant" << endl;
    else
        cout << "N'a pas bloque" << endl;

    if (SemUser.P_WouldBlock ())
        cout << "Aurait ete bloquant" << endl;
    else
        cout << "N'a pas bloque" << endl;

    if (SemUser.P_WouldBlock ())
        cout << "Aurait ete bloquant" << endl;
    else
        cout << "N'a pas bloque" << endl;

    return 0;

}  //  ppal()