// sema.h :
//

#if !defined(AGD_SEMA_H__EA777512_58F6_495A_A36F_1272222A4749__INCLUDED_)
#define AGD_SEMA_H__EA777512_58F6_495A_A36F_1272222A4749__INCLUDED_

#include <inttypes.h>
#include <stdlib.h>
#include "uuid.h"

#define _SHM_SEMA_RECURSIVE				1

/////////////////////////////////////////////////////////////////////////////
// sema.h - Declarations:

#ifdef __cplusplus
extern "C" {
#endif	//	__cplusplus

union semun
{
	int              val;    // Value for SETVAL
	struct semid_ds *buf;    // Buffer for IPC_STAT, IPC_SET
	unsigned short  *array;  // Array for GETALL, SETALL
	struct seminfo  *__buf;  // Buffer for IPC_INFO	(Linux-specific)
};

#ifdef __cplusplus
}
#endif	//	__cplusplus

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

class CSemaphore
{
public:
	CSemaphore(void);
	virtual ~CSemaphore(void);

	virtual int Create(const char *pszFilename, int nsems, unsigned short *pInitArr = NULL);
	virtual void Release(void);

	int Ctl(int cmd);
	int Ctl(int semnum, int cmd);
	int Ctl(int semnum, int cmd, int val);
	int Ctl(int cmd, struct semid_ds *buf);
	int Ctl(int cmd, unsigned short *arr);
	int Ctl(int cmd, struct seminfo *si);

	int IpcStat(struct semid_ds *buf);
	int IpcInfo(struct seminfo *si);
	int IpcSet(struct semid_ds *buf);
	int IpcRmID(void);
	int SemStat(int index, struct semid_ds *buf);
	int SemInfo(struct seminfo *si);
	int GetVal(int semnum = 0);
	int SetVal(int semnum, int val);
	int GetAll(unsigned short *arr);
	int SetAll(unsigned short *arr);
	int GetPid(int semnum = 0);
	int GetNCnt(int semnum = 0);
	int GetZCnt(int semnum = 0);

	bool Op(struct sembuf *sops, size_t nsops);
	bool TimedOp(struct sembuf *sops, size_t nsops, const struct timespec *timeout);

	bool Lock(int semnum = 0);
	bool LockTimeout(const struct timespec *timeout, int semnum = 0);
	bool LockTimeout(unsigned long msec, int semnum = 0);
	bool Unlock(int semnum = 0);
	bool WaitZero(int semnum = 0);
	bool WaitZeroTimeout(const struct timespec *timeout, int semnum = 0);
	bool WaitZeroTimeout(unsigned long msec, int semnum = 0);

	static void DumpIpcPerm(struct ipc_perm *ip);
	static void DumpSemidDs(struct semid_ds *sid);
	static void DumpSeminfo(struct seminfo *psi);

protected:
	int Ctl(int semnum, int cmd, union semun su);

protected:
	int m_nSemID;
};

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

#ifdef _WIN32
#define _DEF_SEMA_DIR						"."
#endif	//	_WIN32

#ifdef __linux__
#define _DEF_SEMA_DIR						"/tmp"
#endif	//	__linux__

/////////////////////////////////////////////////////////////////////////////

class CShmSemaphore : public CSemaphore
{
public:
	CShmSemaphore(void);
	virtual ~CShmSemaphore(void);

	virtual int Create(const char *pszFilename);
	virtual int Create(const uuid_t &ruuid, const char *pszDir = _DEF_SEMA_DIR);
	virtual void Release(void);
};

/////////////////////////////////////////////////////////////////////////////
#endif	//	!defined(AGD_SEMA_H__EA777512_58F6_495A_A36F_1272222A4749__INCLUDED_)
