#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <error.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include "shm.h"
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
//#define ENABLE_SHM_DEBUG
#ifdef ENABLE_SHM_DEBUG
#define YNC_SHM_DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"\n",__LINE__, ##__VA_ARGS__);
#else
#define YNC_SHM_DEBUG(format,...)
#endif
#define MAX_TRIES 10
namespace shmaddr
{
SharedShm::SharedShm(int shmkey,int semkey,int sharesize):
shm_key(-1),
sem_key(-1),
shm_shsize(-1),
sem_id(-1),
shm_id(-1),
shm_addr(NULL)
{
Configure(shmkey,semkey,sharesize);
}
SharedShm::~SharedShm()
{
if(shm_addr){
shm_mdt((void *)shm_addr);
}
if(-1 != sem_id){
del_sem(sem_id);
}
}
int SharedShm::sem_get(int key,int init_value)
{
int i;
union semun sem_union;
struct semid_ds seminfo;
sem_id = semget(key,1,0666 | IPC_CREAT | IPC_EXCL);
if(errno == EEXIST)
{
if(-1 == (sem_id = semget(key,1,0666 | IPC_CREAT)))
{
perror("Get semaphore!\n");
return -1;
} else {
sem_union.buf = &seminfo;
for(i= 1; i< MAX_TRIES; i++)
{
semctl(sem_id,0,IPC_STAT,sem_union);
if(sem_union.buf->sem_otime == 0)
usleep(10);
}
return 0;
}
}
sem_union.val = init_value;
if(semctl(sem_id,0,SETVAL,sem_union))
{
perror("Initialize semaphore!\n");
return -1;
}
return 0;
}
int SharedShm::sem_P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
YNC_SHM_DEBUG("the sem value is ---before P %d\n",semctl(sem_id,0,GETVAL));
if(-1 == semop(sem_id,&sem_b,1))
{
perror("P operation!\n");
return -1;
}
YNC_SHM_DEBUG("the sem value is ---after P %d\n",semctl(sem_id,0,GETVAL));
return 0;
}
int SharedShm::sem_V(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = +1;
sem_b.sem_flg = SEM_UNDO;
YNC_SHM_DEBUG("the sem value is ---before V %d\n",semctl(sem_id,0,GETVAL));
if(-1 == semop(sem_id,&sem_b,1))
{
perror("V operation!\n");
return -1;
}
YNC_SHM_DEBUG("the sem value is ---after V %d\n",semctl(sem_id,0,GETVAL));
return 0;
}
int SharedShm::del_sem(int sem_id)
{
union semun sem_union;
if(semctl(sem_id,0,IPC_RMID,sem_union))
{
perror("Delete semaphore!\n");
return -1;
}
return 0;
}
int SharedShm::shm_get(int key,int sharesize)
{
shm_key = key;
shm_shsize = sharesize;
if(-1 == (shm_id = shmget(shm_key,shm_shsize,0666|IPC_CREAT)))
{
perror("Get share memory!\n");
return -1;
}
return 0;
}
int SharedShm::shm_mat(int shm_id,void* shmaddr)
{
if((void*)-1 == shmat(shm_id,shmaddr,0))
{
perror("Shmat share memory!\n");
return -1;
}
shm_addr = (char*)shmat(shm_id,shmaddr,0);
return 0;
}
int SharedShm::shm_mdt(void* shmaddr)
{
if(-1 == shmdt(shmaddr))
{
perror("Shmdt share memory!\n");
return -1;
}
return 0;
}
int SharedShm::Configure(int shmkey,int semkey,int sharesize)
{
shm_get(shmkey,sharesize);
shm_mat(shm_id,NULL);
sem_get(semkey,1);
return 0;
}
int SharedShm::Read(char* dst,int offset,int len)
{
if(NULL == dst)
{
printf("dst addres is null,please request correct address!\n");
return -1;
}
if((offset + len) > shm_shsize)
{
printf("the request data beyond the share memory size!\n");
return -1;
}
if(-1 == shm_id)
{
printf("bad share memory file destriptor!\n");
return -1;
}
if(!sem_P(sem_id))
{
memcpy(dst,shm_addr+offset,len);
return sem_V(sem_id);
}
return -1;
}
int SharedShm::Write(char* src,int offset,int len)
{
if(NULL == src)
{
printf("src addres is null,please request correct address!\n");
return -1;
}
if((offset + len) > shm_shsize)
{
printf("the request data beyond the share memory size!\n");
return -1;
}
if(NULL == shm_addr)
{
printf("share memory address is null!\n");
return -1;
}
if(-1 == shm_id)
{
printf("bad share memory file destriptor!\n");
return -1;
}
if(!sem_P(sem_id))
{
memcpy(shm_addr+offset,src,len);
return sem_V(sem_id);
}
return -1;
}
}
shm.h
#include <stdlib.h>
#include <stdio.h>
namespace shmaddr
{
class SharedShm
{
public:
SharedShm(int shmkey,int semkey,int sharesize);
~SharedShm();
int Read(char *dst,int offset,int len);
int Write(char *src,int offset,int len);
private:
int shm_key;
int sem_key;
int shm_shsize;
int sem_id;
int shm_id;
char* shm_addr;
int Configure(int shmkey,int semkey,int sharesize);
int sem_get(int key,int sharesize);
int sem_init(int init_value);
int sem_P(int sem_id);
int sem_V(int sem_id);
int del_sem(int sem_id);
int shm_get(int key,int sharesize);
int shm_mat(int shm_id,void* shmaddr);
int shm_mdt(void* shmaddr);
};
}