//**************************************************************************
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc.h"
//**************************************************************************
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
        int val;                    /* value for SETVAL */
        struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
        unsigned short int *array;  /* array for GETALL, SETALL */
        struct seminfo *__buf;      /* buffer for IPC_INFO */
};
#endif
//**************************************************************************
inline int CreateSem(int key)
{
int semid;
union semun arg;

/* create a semaphore set with 1 semaphore: */
if ((semid = semget((key_t) key, 1, 0660 | IPC_CREAT)) == -1) {
        perror("semget");
        exit(1);
    }

/* initialize semaphore #0 to 1: */
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("semctl");
        exit(1);
    }

return 0;
}
//**************************************************************************
inline int ShmSemLock(int key)
{
int semid;
struct sembuf sb = {0, -1, 0};  /* set to allocate resource */

/* grab the semaphore set created by seminit.c: */
if ((semid = semget(key, 1, 0)) == -1) {
        perror("semget");
        exit(1);
}

if (semop(semid, &sb, 1) == -1) {
        perror("semop");
        exit(1);
    }

return 0;
}
//**************************************************************************
inline int ShmSemUnlock(int key)
{
int semid;
struct sembuf sb = {0, 1, 0};  /* set to allocate resource */

/* grab the semaphore set created by seminit.c: */
if ((semid = semget(key, 1, 0)) == -1) {
        perror("semget");
        exit(1);
}

if (semop(semid, &sb, 1) == -1) {
        perror("semop");
        exit(1);
}

return 0;
}
//**************************************************************************
inline void DeleteShm(int key)
{
int shmid;
unsigned char *shm;

if ((shmid = shmget((key_t) key, sizeof(int), IPC_CREAT | 0660)) < 0) {
        perror("shmget");
        exit(1);
    }
shmctl(shmid, IPC_RMID, NULL);  // Delete shared memory segment
}
//**************************************************************************
inline void PutIntoShm(int key, unsigned char *data, int size, int lockkey = 0)
{
int shmid;
unsigned char *shm;
int totsize = size+sizeof(int);

if (lockkey)
        ShmSemLock(lockkey);

DeleteShm(key);

if ((shmid = shmget((key_t) key, totsize, IPC_CREAT | 0660)) < 0) {
        perror("shmget");
        exit(1);
    }
if ((shm = (unsigned char *) shmat(shmid, NULL, 0)) == (unsigned char *) -1) {
        perror("shmat");
        exit(1);
    }

memcpy(shm, &size, sizeof(int));
memcpy(shm+sizeof(int), data, size);

shmdt((char *) shm);    // Detach shared memory segment

if (lockkey)
        ShmSemUnlock(lockkey);
}
//**************************************************************************
inline void GetFromShm(int key, unsigned char **dataptr, int *size, int lockkey = 0)
{
int shmid;
unsigned char *shm;

if (lockkey)
        ShmSemLock(lockkey);

if ((shmid = shmget((key_t) key, sizeof(int), IPC_CREAT | 0660)) < 0) {
        perror("shmget");
        exit(1);
    }
if ((shm = (unsigned char *) shmat(shmid, NULL, SHM_RDONLY)) == (unsigned char *) -1) {
        perror("shmat");
        exit(1);
    }

memcpy(size, shm, sizeof(int));

shmdt((char *) shm);    // Detach shared memory segment

if ((shmid = shmget((key_t) key, *size+sizeof(int), IPC_CREAT | 0660)) < 0) {
        perror("shmget");
        exit(1);
    }
if ((shm = (unsigned char *) shmat(shmid, NULL, 0)) == (unsigned char *) -1) {
        perror("shmat");
        exit(1);
    }

unsigned char *data = NULL;
ALLOC1D(&data, *size);
*dataptr = data;
memcpy(data, shm+sizeof(int), *size);

shmdt((char *) shm);    // Detach shared memory segment

if (lockkey)
        ShmSemUnlock(lockkey);
}
//**************************************************************************
inline void DeleteSem(int key)
{
int semid;
union semun arg;

/* grab the semaphore set created by seminit.c: */
if ((semid = semget((key_t) key, 1, 0)) == -1) {
        perror("semget");
        exit(1);
    }

/* remove it: */
if (semctl(semid, 0, IPC_RMID, arg) == -1) {
        perror("semctl");
        exit(1);
    }
}
//**************************************************************************