|
@@ -0,0 +1,459 @@
|
|
|
+#ifdef _WIN32
|
|
|
+#define _CRT_SECURE_NO_WARNINGS
|
|
|
+#define _CRT_NONSTDC_NO_WARNINGS
|
|
|
+#include <windows.h>
|
|
|
+#include <io.h>
|
|
|
+#include "../Win32/w32def.h"
|
|
|
+#endif // _WIN32
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <unistd.h>
|
|
|
+#ifdef __linux__
|
|
|
+#include <sys/file.h>
|
|
|
+#include <sys/ipc.h>
|
|
|
+#include <sys/sem.h>
|
|
|
+#include <sys/shm.h>
|
|
|
+#include <linux/limits.h>
|
|
|
+#endif // __linux__
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include "defines.h"
|
|
|
+#include "sema.h"
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#define _IS_VALID_SEMID(id) ((id) >= 0)
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+CSemaphore::CSemaphore(void) : m_nSemID(_INVALID_ID)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+CSemaphore::~CSemaphore(void)
|
|
|
+{
|
|
|
+ Release();
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::Create(const char *pszFilename, int nsems, unsigned short *pInitArr)
|
|
|
+{
|
|
|
+ int nFdSema, nRet = -1;
|
|
|
+
|
|
|
+ if((nFdSema = ::open(pszFilename, O_RDWR | O_CREAT | O_TRUNC, _NUMBER_OF_THE_BEAST)) >= 0)
|
|
|
+ {
|
|
|
+ if(!::flock(nFdSema, LOCK_EX))
|
|
|
+ {
|
|
|
+ key_t semKey;
|
|
|
+
|
|
|
+ if((semKey = ::ftok(pszFilename, 'R')) >= 0)
|
|
|
+ {
|
|
|
+ if((m_nSemID = ::semget(semKey, nsems, IPC_CREAT | _NUMBER_OF_THE_BEAST)) >= 0)
|
|
|
+ {
|
|
|
+ struct semid_ds sds;
|
|
|
+ ::memset(&sds, 0, sizeof(sds));
|
|
|
+
|
|
|
+ if(!IpcStat(&sds))
|
|
|
+ {
|
|
|
+ if(!sds.sem_otime)
|
|
|
+ {
|
|
|
+ bool fCreateArr = !pInitArr;
|
|
|
+
|
|
|
+ if(fCreateArr)
|
|
|
+ {
|
|
|
+ pInitArr = new unsigned short[sds.sem_nsems];
|
|
|
+
|
|
|
+ for(unsigned long i = 0; i < sds.sem_nsems; i++)
|
|
|
+ {
|
|
|
+ pInitArr[i] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ SetAll(pInitArr);
|
|
|
+
|
|
|
+ if(fCreateArr)
|
|
|
+ delete [] pInitArr;
|
|
|
+
|
|
|
+ struct sembuf sb[2] = {{0, 1, IPC_NOWAIT}, {0, -1, IPC_NOWAIT}};
|
|
|
+ Op(sb, 2);
|
|
|
+
|
|
|
+ TRACE("CSemaphore::Create: Created new Semaphore!\n");
|
|
|
+ nRet = 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: Opened existing Semaphore!\n");
|
|
|
+ nRet = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: IpcStat failed - errno: %d!\n", errno);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: Failed to create Semaphore - errno: %d!\n", errno);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: Failed to create semKey - errno: %d!\n", errno);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::flock(nFdSema, LOCK_UN);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: Failed to create Lock on '%s' - errno: %d!\n", pszFilename, errno);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::close(nFdSema);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::Create: Failed to create '%s' - errno: %d!\n", pszFilename, errno);
|
|
|
+ }
|
|
|
+
|
|
|
+ return nRet;
|
|
|
+}
|
|
|
+
|
|
|
+void CSemaphore::Release(void)
|
|
|
+{
|
|
|
+ if(_IS_VALID_SEMID(m_nSemID))
|
|
|
+ {
|
|
|
+ m_nSemID = _INVALID_ID;
|
|
|
+ TRACE("CSemaphore::Release\n");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int cmd)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.val = 0;
|
|
|
+ return Ctl(0, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int semnum, int cmd)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.val = 0;
|
|
|
+ return Ctl(semnum, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int semnum, int cmd, int val)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.val = val;
|
|
|
+ return Ctl(semnum, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int cmd, struct semid_ds *buf)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.buf = buf;
|
|
|
+ return Ctl(0, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int cmd, unsigned short *arr)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.array = arr;
|
|
|
+ return Ctl(0, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int cmd, struct seminfo *si)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.__buf = si;
|
|
|
+ return Ctl(0, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::Ctl(int semnum, int cmd, union semun su)
|
|
|
+{
|
|
|
+ if(!_IS_VALID_SEMID(m_nSemID))
|
|
|
+ {
|
|
|
+// TRACE("CSemaphore::Ctl: Invalid SemID: %d!\n", m_nSemID);
|
|
|
+ errno = EINVAL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ::semctl(m_nSemID, semnum, cmd, su);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::IpcStat(struct semid_ds *buf)
|
|
|
+{
|
|
|
+ return Ctl(IPC_STAT, buf);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::IpcSet(struct semid_ds *buf)
|
|
|
+{
|
|
|
+ return Ctl(IPC_SET, buf);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::IpcRmID(void)
|
|
|
+{
|
|
|
+ int nRet = Ctl(IPC_RMID);
|
|
|
+ Release();
|
|
|
+ return nRet;
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::IpcInfo(struct seminfo *si)
|
|
|
+{
|
|
|
+ return Ctl(IPC_INFO, si);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::SemStat(int index, struct semid_ds *buf)
|
|
|
+{
|
|
|
+ union semun su;
|
|
|
+ su.buf = buf;
|
|
|
+ return ::semctl(index, 0, SEM_STAT, su);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::SemInfo(struct seminfo *si)
|
|
|
+{
|
|
|
+ return Ctl(SEM_INFO, si);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::GetVal(int semnum)
|
|
|
+{
|
|
|
+ return Ctl(semnum, GETVAL);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::SetVal(int semnum, int val)
|
|
|
+{
|
|
|
+ return Ctl(semnum, SETVAL, val);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::GetAll(unsigned short *arr)
|
|
|
+{
|
|
|
+ return Ctl(GETALL, arr);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::SetAll(unsigned short *arr)
|
|
|
+{
|
|
|
+ return Ctl(SETALL, arr);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int CSemaphore::GetPid(int semnum)
|
|
|
+{
|
|
|
+ return Ctl(semnum, GETPID);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::GetNCnt(int semnum)
|
|
|
+{
|
|
|
+ return Ctl(semnum, GETNCNT);
|
|
|
+}
|
|
|
+
|
|
|
+int CSemaphore::GetZCnt(int semnum)
|
|
|
+{
|
|
|
+ return Ctl(semnum, GETZCNT);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+bool CSemaphore::Op(struct sembuf *sops, size_t nsops)
|
|
|
+{
|
|
|
+ if(!_IS_VALID_SEMID(m_nSemID))
|
|
|
+ {
|
|
|
+// TRACE("CSemaphore::Op: Invalid SemID: %d!\n", m_nSemID);
|
|
|
+ errno = EINVAL;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return !::semop(m_nSemID, sops, nsops);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::TimedOp(struct sembuf *sops, size_t nsops, const struct timespec *timeout)
|
|
|
+{
|
|
|
+ if(!_IS_VALID_SEMID(m_nSemID))
|
|
|
+ {
|
|
|
+ TRACE("CSemaphore::TimedOp: Invalid SemID: %d!\n", m_nSemID);
|
|
|
+ errno = EINVAL;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return !::semtimedop(m_nSemID, sops, nsops, timeout);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+bool CSemaphore::Lock(int semnum)
|
|
|
+{
|
|
|
+ struct sembuf sb;
|
|
|
+ sb.sem_num = (unsigned short)semnum;
|
|
|
+ sb.sem_op = -1;
|
|
|
+ sb.sem_flg = SEM_UNDO;
|
|
|
+ return Op(&sb, 1);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::LockTimeout(const struct timespec *timeout, int semnum)
|
|
|
+{
|
|
|
+ struct sembuf sb;
|
|
|
+ sb.sem_num = (unsigned short)semnum;
|
|
|
+ sb.sem_op = -1;
|
|
|
+ sb.sem_flg = SEM_UNDO;
|
|
|
+ return TimedOp(&sb, 1, timeout);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::LockTimeout(unsigned long msec, int semnum)
|
|
|
+{
|
|
|
+ struct timespec to;
|
|
|
+ to.tv_sec = msec / 1000;
|
|
|
+ to.tv_nsec = (msec % 1000) * 1000000;
|
|
|
+ return LockTimeout(&to, semnum);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::Unlock(int semnum)
|
|
|
+{
|
|
|
+ struct sembuf sb;
|
|
|
+ sb.sem_num = (unsigned short)semnum;
|
|
|
+ sb.sem_op = 1;
|
|
|
+ sb.sem_flg = SEM_UNDO;
|
|
|
+ return Op(&sb, 1);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::WaitZero(int semnum)
|
|
|
+{
|
|
|
+ struct sembuf sb;
|
|
|
+ sb.sem_num = (unsigned short)semnum;
|
|
|
+ sb.sem_op = 0;
|
|
|
+ sb.sem_flg = SEM_UNDO;
|
|
|
+ return Op(&sb, 1);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::WaitZeroTimeout(const struct timespec *timeout, int semnum)
|
|
|
+{
|
|
|
+ struct sembuf sb;
|
|
|
+ sb.sem_num = (unsigned short)semnum;
|
|
|
+ sb.sem_op = 0;
|
|
|
+ sb.sem_flg = SEM_UNDO;
|
|
|
+ return TimedOp(&sb, 1, timeout);
|
|
|
+}
|
|
|
+
|
|
|
+bool CSemaphore::WaitZeroTimeout(unsigned long msec, int semnum)
|
|
|
+{
|
|
|
+ struct timespec to;
|
|
|
+ to.tv_sec = msec / 1000;
|
|
|
+ to.tv_nsec = (msec % 1000) * 1000000;
|
|
|
+ return WaitZeroTimeout(&to, semnum);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void CSemaphore::DumpIpcPerm(struct ipc_perm *ip)
|
|
|
+{
|
|
|
+ printf("__key: 0x%X\n", ip->__key);
|
|
|
+ printf("uid: %d\n", ip->uid);
|
|
|
+ printf("gid: %d\n", ip->gid);
|
|
|
+ printf("cuid: %d\n", ip->cuid);
|
|
|
+ printf("cgid: %d\n", ip->cgid);
|
|
|
+ printf("mode: %hu\n", ip->mode);
|
|
|
+ printf("__seq: %hu\n", ip->__seq);
|
|
|
+}
|
|
|
+
|
|
|
+void CSemaphore::DumpSemidDs(struct semid_ds *sid)
|
|
|
+{
|
|
|
+ CSemaphore::DumpIpcPerm(&sid->sem_perm);
|
|
|
+ printf("sem_otime: %lu\n", sid->sem_otime);
|
|
|
+ printf("sem_ctime: %lu\n", sid->sem_ctime);
|
|
|
+ printf("sem_nsems: %lu\n", sid->sem_nsems);
|
|
|
+}
|
|
|
+
|
|
|
+void CSemaphore::DumpSeminfo(struct seminfo *psi)
|
|
|
+{
|
|
|
+ printf("semmap: %d\n", psi->semmap);
|
|
|
+ printf("semmni: %d\n", psi->semmni);
|
|
|
+ printf("semmns: %d\n", psi->semmns);
|
|
|
+ printf("semmnu: %d\n", psi->semmnu);
|
|
|
+ printf("semmsl: %d\n", psi->semmsl);
|
|
|
+ printf("semopm: %d\n", psi->semopm);
|
|
|
+ printf("semume: %d\n", psi->semume);
|
|
|
+ printf("semusz: %d\n", psi->semusz);
|
|
|
+ printf("semvmx: %d\n", psi->semvmx);
|
|
|
+ printf("semaem: %d\n\n", psi->semaem);
|
|
|
+}
|
|
|
+
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+/////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+CShmSemaphore::CShmSemaphore(void)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+CShmSemaphore::~CShmSemaphore(void)
|
|
|
+{
|
|
|
+ Release();
|
|
|
+}
|
|
|
+
|
|
|
+int CShmSemaphore::Create(const char *pszFilename)
|
|
|
+{
|
|
|
+ int nRet;
|
|
|
+ unsigned short nVals[2] = {1, 0};
|
|
|
+ if((nRet = CSemaphore::Create(pszFilename, 2, nVals)) < 0)
|
|
|
+ return nRet;
|
|
|
+ Unlock(1);
|
|
|
+ TRACE("CShmSemaphore::Create\n");
|
|
|
+ return nRet;
|
|
|
+}
|
|
|
+
|
|
|
+int CShmSemaphore::Create(const uuid_t &ruuid, const char *pszDir)
|
|
|
+{
|
|
|
+ if(!pszDir)
|
|
|
+ pszDir = "";
|
|
|
+
|
|
|
+ size_t nLenReq = strlen(pszDir) + _UUID_STRING_LEN + 2;
|
|
|
+
|
|
|
+ if(nLenReq > PATH_MAX)
|
|
|
+ {
|
|
|
+ TRACE("CShmSemaphore::Create: directory name too long\n");
|
|
|
+ errno = EINVAL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ char szUuid[_UUID_STRING_LEN + 1];
|
|
|
+ char szSema[PATH_MAX];
|
|
|
+ _uuid_unparse(&ruuid, szUuid, sizeof(szUuid));
|
|
|
+ sprintf(szSema, "%s/%s.sem", pszDir, szUuid);
|
|
|
+ return Create(szSema);
|
|
|
+}
|
|
|
+
|
|
|
+void CShmSemaphore::Release(void)
|
|
|
+{
|
|
|
+ if(_IS_VALID_SEMID(m_nSemID))
|
|
|
+ {
|
|
|
+ int nRefs = GetVal(1);
|
|
|
+
|
|
|
+ if(nRefs > 1)
|
|
|
+ {
|
|
|
+ TRACE("CShmSemaphore::Release: remaining References: %d\n", nRefs - 1);
|
|
|
+ Lock(1);
|
|
|
+ }
|
|
|
+ else if(nRefs == 1)
|
|
|
+ {
|
|
|
+ TRACE("CShmSemaphore::Release: remaining References: %d - Semaphore removed!\n", nRefs - 1);
|
|
|
+ IpcRmID();
|
|
|
+ }
|
|
|
+
|
|
|
+ CSemaphore::Release();
|
|
|
+ }
|
|
|
+}
|