IPC 通讯接口封装使用介绍
l IPC 初始化
成功返回对应的结果体指针,失败返回 NULL 。
1. 初始化消息队列 ipcMsq_p ipc_initialize_msq(key_t key, int msglen )
msglen 表示该消息队列可以接受的单个消息的最大长度
2. 初始化共享内存 ipcShm_p ipc_initialize_shm(key_t key, key_t semkey, enum SHMTYPE type, int size, int elemsize)
参数说明 key -共享内存 key 值; semkey -共享内存使用的信号量 key 值; type -共享内存类型; size -申请的共享内存大小; elemsize -共享内存每个元素大小
3. 初始化数组型共享内存,由于数组需要维数和每维的大小,故需独立的初始化函数
ipcShm_p ipc_initialize_array_shm(key_t key, key_t semkey, int elemsize, int dim, ...)
key -共享内存 key ; semkey -共享内存使用的信号量 key 值; dim -数组维数;后面是 dim 个整型数分别表示每维大小
4. 初始化信号量 ipcSem_p ipc_initialize_sem(key_t key, int nsems)
Key -信号量 key ; nsems -该信号量集合的信号量数
l IPC 操作
统一的接口函数 int ipc_op(ipcComm_p ipc, enum IPCOP op, int semnum, void *buf, ...)
Ipc -对应的 ipc ; op -操作类型; semnum -信号量集合中的成员号; buf -存储操作数据空间; buf 后的参数因 IPC 类型不同而异,具体参考下面的细节。
1. 读消息队列调用方式 ipc_op(ipc, READ, 0, NULL) ,读取的信息不直接返回给用户,而是作为参数传递给用户自定义的一个函数进行处理,参考 IPC 配置接口。
2. 写消息队列 ipc_op(ipc, WRITE, 0, buf, len) , buf 指向需要写入消息队列的数据, len 是需要写入的数据长度。
3. 写消息队列 ipc_op(ipcComm_p ipc, WRITE, 0, void *buf, int buflen, long mtype)
参数说明 :buf 是要放入消息队列的数据, buflen 是该数据区的大小, mtype 用于指定这条消息的类型
4. 读消息队列 ipc_op(ipcComm_p ipc, READ, 0, void *buf, long *mtype)
参数说明: buf 是返回参数,函数执行后将指向从消息队列取到的数据; mtype 既是输入参数又是输出参数,作为输入参数,它指定了要取的消息的类型,作为返回参数,它返回了取到的消息的实际类型,当该值为 0 时,表示取队列中第一条数据;返回值:本次读取消息的实际长度。
5. 读消息队列深度 int msq_get_depth(ipcComm_p ipc)
6. 读写普通型共享内存 ipc_ip(ipc, READ/WRITE, 0, buf, len, off) ,从 off 偏移处读或写 len 长字节
7. 读写堆栈型或循环队列型共享内存 ipc_op(ipc, READ/WRITE, 0, buf)
8. 读写数组型共享内存 ipc_ip(ipc, READ/WRITE, 0, buf, dim1, dim2, …) , dim 是各维数组下标
9. 信号量锁操作 ipc_op(ipc, LOCK, semnm, NULL) ,使用第 semnm 信号量上锁。
10. 信号量解锁操作 ipc_op(ipc, LOCK, semnm, NULL) ,解锁第 semnm 信号量。
11. Ipc_op(ipc, FREE/RMIT, 0, NULL)
释放只能 FREE 和 RMIT 之一, RMIT 释放资源后同时会删除 IPC 。
l IPC 配置接口
1. 消息队列
1) 设置函数处理指针 int msq_set_handles(ipcMsq_p msq, comm_fn1 handle_read, comm_fn2 empty, comm_fn2 full)
n 函数原型 typedef void *(*comm_fn1)(void *); typedef int (*comm_fn2)(void *);
n Handle_read ――处理从消息队列读取的信息函数指针,如果未定义则读取消息队列函数消息队列中下一条消息或返回 0 ,如果该函数处理返回 NULL 则读取消息队列操作认为出错返回- 1 。
n Empty ――读取消息队列操作处理消息队列为空的函数指针,如果未定义则读取消息队列操作返回 -2 ,如果该函数返回- 1 则读取消息队列操作也返回- 1 ,否则返回 0
n Full ――写取消息队列操作处理消息队列满的函数指针,返回处理同 empty
2) 设置每次读取消息队列消息数 int msq_set_readbatch(ipcMsq_p msq, int batch)
3) 设置读写消息队列时不等待模式 int msq_set_nowait(ipcMsq_p msq)
4) 设置读写消息队列时等待模式 int msq_set_wait(ipcMsq_p msq)
l 待解决的地方
1 )将 ipc_op 函数中的参数 semun 作为变长参数;
2 )设法解决变长参数个数判断问题;
3 )是否需要将各种共享内存描述结构体 ipcShm_t 放入共享内存,让其他进程获取。这
个结构体保存了如何组织共享内存的信息。
4 )完善成线程安全
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include "ipc_comm.h"
void Free(void **ptr)
{
if(*ptr)
{
free(*ptr);
*ptr = NULL;
}
}
/*return NULL if error
*malloc memory for common ipc struct
*/
ipcComm_p ipc_initialize(enum IPCTYPE type)
{
ipcComm_p name;
name = (ipcComm_p)malloc(sizeof(ipcComm_t));
if(NULL == name)
{
/*error*/
return NULL;
}
memset(name, 0, sizeof(ipcComm_t));
switch(type)
{
case MSQ:
name->private = malloc(sizeof(ipcMsq_t));
break;
case SHM:
name->private = malloc(sizeof(ipcShm_t));
break;
case SEM:
name->private = malloc(sizeof(ipcSem_t));
break;
}
if(NULL == name->private)
{
/*error*/
Free((void **)(&name));
return NULL;
}
return name;
}
int ipc_free(ipcComm_p ipc)
{
ipcMsq_p msq;
if(MSQ == ipc->ipctype)
{
msq = (ipcMsq_p)(ipc->private);
Free((void**)(&(msq->msg)));
}/*
if(SHM == ipc->ipctype)
{
shm = (ipcShm_p)(ipc->private);
if(ISARRAYSHM(shm->type))
{
Free((void **)(&(shm->array.bounds)));
Free((void **)(&(shm->array.constants)));
}
}*/
Free((void **)(&(ipc->private)));
Free((void **)(&ipc));
return 0;
}
/*call this before read or write*/
int ipc_create_msq(ipcComm_p ipc)
{
int msqid;
if(NULL == ipc)
{
/*error*/
return -1;
}
if(0 == ipc->key)
{
/*IPC_PRIVATE, dangerous*/
return -1;
}
msqid = msgget(ipc->key, IPC_CREAT | IPC_EXCL | ipc->mode);
if(-1 == msqid)
{
/* queue exist already */
if(EEXIST == errno)
{
msqid = msgget(ipc->key, ipc->mode);
if(-1 == msqid)
{
/*error*/
return -1;
}
}
else{
/*error*/
return -1;
}
}
ipc->id = msqid;
return 0;
}
/*initial msq, return NULL if fail else return allocated ipcMsq_p*/
/*ipcMsq_p ipc_initialize_msq(key_t key)*/
ipcMsq_p ipc_initialize_msq(key_t key, int msglen)
{
ipcMsq_p msq;
ipcComm_p ipc;
ipc = ipc_initialize(MSQ);
if(NULL == ipc)
{
/*error*/
return NULL;
}
ipc->ipctype = MSQ;
ipc->key = key;
ipc->mode = 0666;
memset(ipc->private, 0, sizeof(ipcMsq_p));
msq = (ipcMsq_p)(ipc->private);
/*msq->msglen = MAXMSGLEN;*/
msq->msglen = msglen; /*mod by lxs*/
msq->comm = ipc;
msq->batch = 1;
msq->mtype = 1;
msq->nowait = 0; /*wait if no message*/
msq->msq_handle_read = NULL;
msq->msq_empty = NULL;
msq->msq_full = NULL;
msq->msg = malloc(msglen + 4); /*del by lxs*/
memset(msq->msg, 0, msglen + 4);
/*if(NULL == msq->msg)
{
ipc_free(ipc);
return NULL;
}
memset(msq->msg, 0, sizeof(msqMsg_t));
msq->msg->mtype = msq->mtype;*/
if(-1 == ipc_create_msq(ipc))
{
/*error*/
ipc_free(ipc);
return NULL;
}
return msq;
}
/*set handle functions*/
int msq_set_handles(ipcMsq_p msq, comm_fn1 handle_read, comm_fn2 empty, comm_fn2 full)
{
if(NULL == msq)
{
/*error*/
return -1;
}
msq->msq_empty = empty;
msq->msq_full = full;
msq->msq_handle_read = handle_read;
return 0;
}
/*set batch messages each ipc_op*/
int msq_set_readbatch(ipcMsq_p msq, int batch)
{
if(NULL == msq)
{
/*error*/
return -1;
}
if(batch > 0)
{
msq->batch = batch;
}
/*msq->batch = MAX_MSQDEP;
msq->batch = msq_get_depth(msq->comm);*/
return 0;
}
/*read or write return immediatly*/
int msq_set_nowait(ipcMsq_p msq)
{
if(NULL == msq)
{
/*error*/
return -1;
}
msq->nowait |= IPC_NOWAIT;
return 0;
}
/*wait until read or write finish*/
int msq_set_wait(ipcMsq_p msq)
{
if(NULL == msq)
{
/*error*/
return -1;
}
msq->nowait &= ~IPC_NOWAIT;
return 0;
}
/*get queue depth*/
int msq_get_depth(ipcComm_p ipc)
{
struct msqid_ds buf;
if(-1 == msgctl(ipc->id, IPC_STAT, &buf))
{
/*error*/
return -1;
}
return buf.msg_qnum;
}
/*read batch msq each time
*return if no message in queue
*/
int ipc_read_msq(ipcComm_p ipc, void *buf, va_list ap)
{
int i;
ipcMsq_p msq;
int ret = 0;
int retcode = 0;
long *mtype; /*add by lxs, input and output*/
if(NULL == ipc)
{
/*error*/
}
msq = (ipcMsq_p)(ipc->private);
/*add by lxs*/
mtype = va_arg(ap, long *);
/*add by lxs*/
/*tmp->mtext = (char *)malloc(sizeof(char) * (msq->msglen));*/
i = 0;
/* using this to avoid read empty msq
batch = msq_get_depth(ipc);
(batch <= msq->batch) ? (batch) : (batch = msq->batch);
while(i < batch)*/
while(i < msq->batch)
{
RETRY:
memset(msq->msg, 0, sizeof(char) * (msq->msglen + 4));
ret = msgrcv(ipc->id, msq->msg, msq->msglen, *mtype, msq->nowait); /*mod by lxs*/
if(ret == -1)
{
/*interrupt by signal*/
if(EINTR == errno)
{
goto RETRY;
}
/* no message */
if(ENOMSG == errno)
{
if(msq->msq_empty)
{
if(-1 == msq->msq_empty(NULL))
{
/*error*/
retcode = -1;
}
}else{
/*not define empty function*/
retcode = -2;
}
break;
}
else{
/*queue was delete*/
if(EIDRM == errno)
{
retcode = -3;
}else{
/*read error*/
retcode = -1;
}
break;
}
}
/*add by lxs*/
*mtype = *(long *)msq->msg;
memcpy(buf, msq->msg + sizeof(long), ret);
retcode = ret;
/*add by lxs*/
/*if(msq->msq_handle_read)
{
if(NULL == msq->msq_handle_read((void*)tmp))
{
retcode = -1;
break;
}
}*/
i++;
}
return retcode;
}
int ipc_write_msq(ipcComm_p ipc, void *buf, va_list ap)
{
ipcMsq_p msq;
/*msqMsg_p tmp;*/
int ret = 0;
int retcode = 0;
int len;
long mtype; /*add by lxs*/
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
len = va_arg(ap, int);
mtype = va_arg(ap, long); /*add by lxs*/
msq = (ipcMsq_p)(ipc->private);
if(len > msq->msglen) /*add by lxs*/
{
/*error*/
return -1;
}
/*mod by lxs*/
memset(msq->msg, 0x00, msq->msglen + sizeof(long));
*(long *)msq->msg = mtype;
memcpy(msq->msg + sizeof(long), buf, len);
/*mod by lxs*/
RETRY:
/*ret = msgsnd(ipc->id, tmp, MAXMSGLEN, msq->nowait);*/
ret = msgsnd(ipc->id, msq->msg, len, msq->nowait); /*mod by lxs, write actual len*/
if(-1 == ret)
{
/*interrupt by signal*/
if(EINTR == errno)
{
goto RETRY;
}
if(EAGAIN == errno)
{
/*queue is full, clear up queue*/
if(msq->msq_full)
{
if(-1 == msq->msq_full(NULL))
{
/*error*/
retcode = -1;
}
}else{
retcode = -2;
}
}else{
/*queue was delete*/
if(EIDRM == errno)
{
retcode = -3;
}else{
/*write error*/
retcode = -1;
}
}
}
return retcode;
}
int ipc_ctl_msq()
{
/*TODO...*/
return 0;
}
int ipc_delete_msq(ipcComm_p ipc)
{
struct msqid_ds buf;
if(-1 == msgctl(ipc->id, IPC_RMID, &buf)){
/*error*/
return -1;
}
return 0;
}
int ipc_create_shm(ipcComm_p ipc)
{
ipcShm_p shm;
int shmid;
void *shmOffset;
#ifdef ENABLE_SHMSEM
int semid;
union semun sem;
int ret;
#endif
int flag = 0; /*create or not*/
if(NULL == ipc)
{
/*error*/
return -1;
}
if(0 == ipc->key)
{
/*IPC_PRIVATE, dangerous*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
shmid = shmget(ipc->key, shm->size, IPC_CREAT | IPC_EXCL | ipc->mode);
if(-1 == shmid)
{
if(EEXIST == errno)
{
shmid = shmget(ipc->key, 0, 0666);
if(-1 == shmid)
{
/*error*/
return -1;
}
ipc->id = shmid;
shmOffset = shmat(shmid, 0, 0);
if((void *)-1 == shmOffset)
{
/*error*/
return -1;
}
shm->shmaddr = shmOffset;
}else{
/*error*/
return -1;
}
}else{
flag = 1;
ipc->id = shmid;
shmOffset = shmat(ipc->id, 0, 0);
if((void *)-1 == shmOffset){
/*error*/
shmctl(ipc->id, IPC_RMID, NULL);
return -1;
}
shm->shmaddr = shmOffset;
memset(shm->shmaddr, 0, shm->size);
}
#ifdef ENABLE_SHMSEM
/*init sem protect shm*/
errno = 0;
shm->mode= 0666;
semid = semget(ipc->semkey, 1, IPC_CREAT | IPC_EXCL | shm->mode);
if(-1 == semid){
if(errno == EEXIST){
semid = semget(ipc->semkey, 0, 0666);
if(-1 == semid){
/*error*/
if(flag)
{
shmdt(shm->shmaddr);
shmctl(ipc->id, IPC_RMID, NULL);
}
return -1;
}
shm->semid = semid;
}else{
/*error*/
if(flag)
{
shmdt(shm->shmaddr);
shmctl(ipc->id, IPC_RMID, NULL);
}
return -1;
}
}else{
shm->semid = semid;
sem.val = 1;
ret = semctl(shm->semid, 0, SETVAL, sem);
if(ret == -1){
/*error*/
ipc_delete_shm(ipc);
return -1;
}
}
#endif
return 0;
}
/*initial shm, return NULL if fail else return allocated ipcShm_p*/
ipcShm_p ipc_initialize_shm(key_t key, key_t semkey, enum SHMTYPE type, int size, int elemsize)
{
ipcShm_p shm;
ipcComm_p ipc;
ipc = ipc_initialize(SHM);
if(NULL == ipc)
{
/*error*/
return NULL;
}
ipc->ipctype = SHM;
ipc->key = key;
#ifdef ENABLE_SHMSEM
ipc->semkey = semkey;
#endif
ipc->mode = 0666;
memset(ipc->private, 0, sizeof(ipcShm_p));
shm = (ipcShm_p)(ipc->private);
shm->comm = ipc;
shm->size = size;
shm->elemsize = elemsize;
switch(type)
{
case ORDINARY:
SETORDINARYSHM(shm->type);
break;
case ARRAY:
SETARRAYSHM(shm->type);
break;
case STACK:
SETSTACKYSHM(shm->type);
shm->stack.top = 0;
shm->stack.depth = size / elemsize;
shm->size = size + 4; /*first 4bytes is top*/
break;
case ROUNDQ:
SETROUNDQSHM(shm->type);
shm->roundq.front = 0;
shm->roundq.rear = 0;
shm->roundq.depth = size / elemsize + 1; /*a addition elem for distinguish full queue and empty queue*/
shm->size = size + elemsize + 8; /*first 8bytes is front and rear*/
break;
default:
/*unknow shm type*/
return NULL;
}
if(-1 == ipc_create_shm(ipc))
{
/*error*/
ipc_free(ipc);
return NULL;
}
return shm;
}
#ifdef ENABLE_SHMSEM
int shmsemlock(int semid)
{
struct sembuf sbuf;
int ret;
memset(&sbuf, 0, sizeof(struct sembuf));
sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
retry_lock:
ret = semop(semid, &sbuf, 1);
if(-1 == ret){
if(EINTR == errno){
goto retry_lock;
}
/*error*/
return -1;
}
return 0;
}
int shmsemunlock(int semid)
{
struct sembuf sbuf;
int ret;
sbuf.sem_num = 0;
sbuf.sem_op = 1;
sbuf.sem_flg = SEM_UNDO;
retry_unlock:
ret = semop(semid, &sbuf, 1);
if(-1 == ret){
if(EINTR == errno){
goto retry_unlock;
}
/*error*/
return -1;
}
}
#endif
/*off is relative offset*/
static int ipc_read_ordinary_shm(ipcComm_p ipc, void *buf, int len, int off)
{
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
/*len = va_arg(ap, int);
off = va_arg(ap, int);*/
if(off + len > shm->size)
{
/*error*/
return -1;
}
#ifdef ENABLE_SHMSEM
/*lock*//*
if(READLOCK(shm->type))
{*/
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
/*}*/
#endif
memmove((char *)(buf), (char *)(shm->shmaddr) + off, len);
#ifdef ENABLE_SHMSEM
/*unlock*//*
if(READLOCK(shm->type))
{*/
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
/*}*/
#endif
return 0;
}
static int ipc_write_ordinary_shm(ipcComm_p ipc, void *buf, int len, int off)
{
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
/*len = va_arg(ap, int);
off = va_arg(ap, int);*/
if(off + len > shm->size)
{
/*error*/
}
#ifdef ENABLE_SHMSEM
/*lock*/
/*if(WRITELOCK(shm->type))
{*/
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
/*}*/
#endif
memmove((char *)(shm->shmaddr) + off, (char *)buf, len);
#ifdef ENABLE_SHMSEM
/*lock*//*
if(WRITELOCK(shm->type))
{*/
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
/*}*/
#endif
return 0;
}
#ifdef ENABLE_ARRAYSHM
int ipc_locate_array_shm(ipcShm_p shm, va_list ap, int *off)
{
int ind;
int i;
*off = 0;
for(i = 0; i < shm->array.dim; i++)
{
ind = va_arg(ap, int);
if((ind <=0) || (ind > shm->array.bounds[i]))
{
/*error, overflow*/
return -1;
}
*off = *off + ind * shm->array.constants[i];
}
}
/*initial array shm, return NULL if fail else return allocated ipcShm_p*/
ipcShm_p ipc_initialize_array_shm(key_t key, key_t semkey, int elemsize, int dim, ...)
{
va_list ap;
ipcShm_p shm;
int i;
int ind;
int *bounds;
int *constants;
int size = 1;;
bounds = (int *)malloc(sizeof(int) * dim);
if(NULL == bounds)
{
/*error*/
return NULL;
}
memset(bounds, 0, sizeof(int) * dim);
i = 0;
va_start(ap, dim);
while(i < dim)
{
ind = va_arg(ap, int);
if(ind <= 0)
{
/*error*/
Free((void **)(&bounds));
return NULL;
}
bounds[i] = ind;
size *= ind;
i++;
}
constants = (int *)malloc(sizeof(int) * dim);
if(NULL == constants)
{
/*error*/
Free((void **)(&bounds));
return NULL;
}
memset(constants, 0, sizeof(int) * dim);
constants[dim - 1] = 1;
i = dim - 2;
while(i >= 0)
{
constants[i] = bounds[i + 1] * constants[i + 1];
i--;
}
shm = ipc_initialize_shm(key, semkey, ARRAY, size * elemsize, elemsize);
if(NULL == shm)
{
/*error*/
Free((void **)(&bounds));
Free((void **)(&constants));
ipc_free(shm->comm);
return NULL;
}
shm->array.dim = dim;
shm->array.bounds = bounds;
shm->array.constants = constants;
return shm;
}
/*
ipcShm_p ipc_initialize_array_shm(key_t key, key_t semkey, int size, int elemsize, int dim, ...)
{
va_list ap;
ipcShm_p shm;
int i;
int ind;
shm = ipc_initialize_shm(key, semkey, ARRAY, size, elemsize);
if(NULL == shm)
{
return NULL;
}
shm->array.dim = dim;
shm->array.bounds = (int *)malloc(sizeof(int) * dim);
if(NULL == shm->array.bounds)
{
ipc_free(shm->comm);
return NULL;
}
memset(shm->array.bounds, 0, sizeof(int) * dim);
i = 0;
va_start(ap, dim);
while(i < dim)
{
ind = va_arg(ap, int);
if(ind <= 0)
{
Free((void **)(&(shm->array.bounds)));
ipc_free(shm->comm);
return NULL;
}
shm->array.bounds[i] = ind;
i++;
}
shm->array.constants = (int *)malloc(sizeof(int) * dim);
if(NULL == shm->array.constants)
{
Free((void **)(&(shm->array.bounds)));
ipc_free(shm->comm);
return NULL;
}
memset(shm->array.constants, 0, sizeof(int) * dim);
shm->array.constants[dim - 1] = 1;
i = dim - 2;
while(i >= 0)
{
shm->array.constants[i] = shm->array.bounds[i] * shm->array.bounds[i + 1];
i--;
}
return shm;
}*/
int ipc_read_array_shm(ipcComm_p ipc, void *buf, va_list ap)
{
int off;
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(-1 == ipc_locate_array_shm(shm, ap, &off))
{
/*error*/
return -1;
}
off = off * shm->elemsize;
if(-1 == ipc_read_ordinary_shm(ipc, buf, shm->elemsize, off))
{
/*error*/
return -1;
}
return 0;
}
int ipc_write_array_shm(ipcComm_p ipc, void *buf, va_list ap)
{
int off;
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(-1 == ipc_locate_array_shm(shm, ap, &off))
{
/*error*/
return -1;
}
off = off * shm->elemsize;
if(-1 == ipc_write_ordinary_shm(ipc, buf, shm->elemsize, off))
{
/*error*/
return -1;
}
return 0;
}
int ipc_free_array_shm(ipcComm_p ipc)
{
ipcShm_p shm;
if(NULL == ipc)
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(ISARRAYSHM(shm->type))
{
Free((void **)(&(shm->array.bounds)));
Free((void **)(&(shm->array.constants)));
}
/*
Free((void **)(&(shm->array.bounds)));
Free((void **)(&(shm->array.constants)));
*/
return 0;
}
#endif
#ifdef ENABLE_STACKSHM
/*-2/stack is empty, -1/error, 0/suc*/
int ipc_stack_pop_shm(ipcComm_p ipc, void *buf)
{
int off;
ipcShm_p shm;
int retcode = 0;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(READLOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
/*memmove((char *)(top), (char *)(shm->shmaddr), 4);
shm->stack.top = atoi(top);*/
shm->stack.top = *((int *)(shm->shmaddr));
if(0 == shm->stack.top)
{
/*error*/
retcode = -2;
goto out;
}
off = (shm->stack.top - 1) * (shm->elemsize) + 4;
memmove((char *)(buf), (char *)(shm->shmaddr) + off, shm->elemsize);
/*sprintf(top, "%d", --shm->stack.top);
memmove((char *)(shm->shmaddr), top, 4);*/
*((int *)(shm->shmaddr)) = --(shm->stack.top);
out:
#ifdef ENABLE_SHMSEM
/*unlock*/
if(READLOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return retcode;
}
/*-2/stack is full, -1/error, 0/suc*/
int ipc_stack_push_shm(ipcComm_p ipc, void *buf)
{
int off;
ipcShm_p shm;
char top[5] = {'/0'};
int retcode = 0;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(READLOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
/*memmove((char *)(top), (char *)(shm->shmaddr), 4);
shm->stack.top = atoi(top);*/
shm->stack.top = *((int *)(shm->shmaddr));
if(shm->stack.depth <= shm->stack.top)
{
/*error*/
retcode = -2;
goto out;
}
off = (shm->stack.top) * (shm->elemsize) + 4;
memmove((char *)(shm->shmaddr) + off, (char *)(buf), shm->elemsize);
/*sprintf(top, "%d", ++shm->stack.top);
memmove((char *)(shm->shmaddr), top, 4);*/
*((int *)(shm->shmaddr)) = ++(shm->stack.top);
out:
#ifdef ENABLE_SHMSEM
/*unlock*/
if(READLOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return retcode;
}
/*return top, -1/error*/
int shm_stack_get_top(ipcComm_p ipc)
{
ipcShm_p shm;
int top;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(READLOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
top = *((int *)(shm->shmaddr));
/*memmove((char *)(top), (char *)(shm->shmaddr), 4);*/
out:
#ifdef ENABLE_SHMSEM
/*unlock*/
if(READLOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return top;
}
/*emptyfull = 0 set stack empty, else set stack full;-1/fail, 0/suc*/
int shm_stack_set_emptyfull(ipcComm_p ipc, int emptyfull)
{
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(READLOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
if(0 == emptyfull)
{
*((int *)(shm->shmaddr)) = 0;
}else{
*((int *)(shm->shmaddr)) = shm->stack.depth;
}
/*memmove((char *)(shm->shmaddr), top, 4);*/
out:
#ifdef ENABLE_SHMSEM
/*unlock*/
if(READLOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return 0;
}
#endif
#ifdef ENABLE_ROUNDQSHM
/*use depth-1 elems to distinguish full queue and empty queue*/
int ipc_deroundq_shm(ipcComm_p ipc, void *buf)
{
int off;
ipcShm_p shm;
/*char front[5] = {'/0'};
char rear[5] = {'/0'};*/
int retcode = 0;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
/*memmove((char *)(front), (char *)(shm->shmaddr), 4);
memmove((char *)(rear), (char *)(shm->shmaddr) + 4, 4);
shm->roundq.front = atoi(front);
shm->roundq.rear = atoi(rear);*/
shm->roundq.front = *((int *)(shm->shmaddr));
shm->roundq.rear = *((int *)(shm->shmaddr + 4));
if(shm->roundq.front == shm->roundq.rear) /*check queue is empty?*/
{
/*error, queue if empty*/
retcode = -2;
goto out;
}
off = (shm->roundq.front) * (shm->elemsize) + 8;
memmove((char *)(buf), (char *)(shm->shmaddr) + off, shm->elemsize);
shm->roundq.front = (shm->roundq.front + 1) % (shm->roundq.depth);
/*sprintf(front, "%d", shm->roundq.front);
memmove((char *)(shm->shmaddr), (char *)front, 4);*/
*((int *)(shm->shmaddr)) = shm->roundq.front;
out:
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return retcode;
}
/*use depth-1 elems to distinguish full queue and empty queue*/
int ipc_enroundq_shm(ipcComm_p ipc, void *buf)
{
int off;
ipcShm_p shm;
/*char front[5] = {'/0'};
char rear[5] = {'/0'};*/
int retcode = 0;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
/*memmove((char *)(front), (char *)(shm->shmaddr), 4);
memmove((char *)(rear), (char *)(shm->shmaddr) + 4, 4);
shm->roundq.front = atoi(front);
shm->roundq.rear = atoi(rear);*/
shm->roundq.front = *((int *)(shm->shmaddr));
shm->roundq.rear = *((int *)(shm->shmaddr + 4));
if(((shm->roundq.rear + 1) % shm->roundq.depth) == (shm->roundq.front))
{
/*error, queue if full*/
retcode = -2;
goto out;
}
off = (shm->roundq.rear) * (shm->elemsize) + 8;
memmove((char *)(shm->shmaddr) + off, (char *)(buf), shm->elemsize);
shm->roundq.rear = (shm->roundq.rear + 1) % (shm->roundq.depth);
/*sprintf(rear, "%d", shm->roundq.rear);
memmove((char *)(shm->shmaddr) + 4, (char *)rear, 4);*/
*((int *)(shm->shmaddr + 4)) = shm->roundq.rear;
out:
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return retcode;
}
/*frontrear=0 to get front, else rear; return -1 at error*/
int shm_deroundq_get_front(ipcComm_p ipc, int frontrear)
{
int pos;
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
if(0 == frontrear)
{
pos = *((int *)(shm->shmaddr));
}else{
pos = *((int *)(shm->shmaddr + 4));
}
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return pos;
}
/*emptyfull=0 to set empty round queue, else full; return -1 at error*/
int shm_deroundq_set_emptyfull(ipcComm_p ipc, int emptyfull)
{
int pos;
ipcShm_p shm;
if((NULL == ipc) || (NULL == buf))
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
if(0 == emptyfull)
{
/*front = rear = 0, set queue empty*/
*((int *)(shm->shmaddr)) = 0;
*((int *)(shm->shmaddr + 4)) = 0;
}else{
/*front = 1, rear = 0, set queue full*/
*((int *)(shm->shmaddr)) = 1;
*((int *)(shm->shmaddr + 4)) = 0;
}
#ifdef ENABLE_SHMSEM
/*lock*/
if(WRITELOCK(shm->type))
{
if(0 != shmsemunlock(shm->semid))
{
/*error*/
return -1;
}
}
#endif
return pos;
}
#endif
int ipc_read_shm(ipcComm_p ipc, void *buf, va_list ap)
{
ipcShm_p shm;
int len;
int off;
if(NULL == ipc)
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(ISORDINARYSHM(shm->type))
{
len = va_arg(ap, int);
off = va_arg(ap, int);
return ipc_read_ordinary_shm(ipc, buf, len, off);
}
#ifdef ENABLE_ARRAYSHM
if(ISARRAYSHM(shm->type))
{
return ipc_read_array_shm(ipc, buf, ap);
}
#endif
#ifdef ENABLE_STACKSHM
if(ISSTACKYSHM(shm->type))
{
return ipc_stack_pop_shm(ipc, buf);
}
#endif
#ifdef ENABLE_ROUNDQSHM
if(ISROUNDQSHM(shm->type))
{
return ipc_deroundq_shm(ipc, buf);
}
#endif
/*not support type*/
return -1;
}
int ipc_write_shm(ipcComm_p ipc, void *buf, va_list ap)
{
ipcShm_p shm;
int len;
int off;
if(NULL == ipc)
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(ISORDINARYSHM(shm->type))
{
len = va_arg(ap, int);
off = va_arg(ap, int);
return ipc_write_ordinary_shm(ipc, buf, len, off);
}
#ifdef ENABLE_ARRAYSHM
if(ISARRAYSHM(shm->type))
{
return ipc_write_array_shm(ipc, buf, ap);
}
#endif
#ifdef ENABLE_STACKSHM
if(ISSTACKYSHM(shm->type))
{
return ipc_stack_push_shm(ipc, buf);
}
#endif
#ifdef ENABLE_ROUNDQSHM
if(ISROUNDQSHM(shm->type))
{
return ipc_enroundq_shm(ipc, buf);
}
#endif
/*not support type*/
return -1;
}
int ipc_delete_shm(ipcComm_p ipc)
{
ipcShm_p shm;
if(NULL == ipc)
{
/*error*/
return -1;
}
shm = (ipcShm_p)(ipc->private);
if(-1 == shmdt(shm->shmaddr)){
/*error*/
return -1;
}
#ifdef ENABLE_SHMSEM
if(-1 == semctl(shm->semid, 0, IPC_RMID)){
/*error*/
return -1;
}
#endif
if(-1 == shmctl(ipc->id, IPC_RMID, NULL)){
/*error*/
return -1;
}
return 0;
}
int ipc_delete_sem(ipcComm_p ipc)
{
/*union semun sem;
int i;
i = 0;
while(i < ipc->sem.nsems)
{
ret = semctl(ipc->id, i, IPC_RMID, sem);
if(ret == -1){
return -1;
}
i++;
}*/
ipcSem_p sem;
int ret;
if(NULL == ipc)
{
/*error*/
return -1;
}
sem = (ipcSem_p)(ipc->private);
retry_rmid:
ret = semctl(ipc->id, sem->nsems, IPC_RMID, 0);
if(ret == -1)
{
if(EINTR == errno)
{
goto retry_rmid;
}
/*error*/
return -1;
}
return 0;
}
int ipc_create_sem(ipcComm_p ipc)
{
int semid;
union semun arg;
int ret;
int i;
ipcSem_p sem;
if(NULL == ipc)
{
/*error*/
return -1;
}
if(0 == ipc->key)
{
/*IPC_PRIVATE, dangerous*/
return -1;
}
sem = (ipcSem_p)(ipc->private);
/*init sem protect shm*/
semid = semget(ipc->key, sem->nsems, IPC_CREAT | IPC_EXCL | 0666);
if(-1 == semid)
{
if(errno == EEXIST)
{
semid = semget(ipc->key, 0, 0666);
if(-1 == semid)
{
/*error*/
return -1;
}
ipc->id = semid;
}else{
/*error*/
return -1;
}
}else{
ipc->id = semid;
i=0;
arg.val = 1;
while(i < sem->nsems)
{
ret = semctl(ipc->id, i, SETVAL, arg);
if(ret == -1){
/*error*/
ipc_delete_sem(ipc); /*create suc, but init fail, so delete it*/
return -1;
}
i++;
}
}
return 0;
}
/*initial sem, return NULL if fail else return allocated ipcSem_p*/
ipcSem_p ipc_initialize_sem(key_t key, int nsems)
{
ipcSem_p sem;
ipcComm_p ipc;
ipc = ipc_initialize(SEM);
if(NULL == ipc)
{
/*error*/
return NULL;
}
ipc->ipctype = SEM;
ipc->key = key;
ipc->mode = 0666;
memset(ipc->private, 0, sizeof(ipcSem_p));
sem = (ipcSem_p)(ipc->private);
sem->comm = ipc;
sem->nsems = nsems;
if(-1 == ipc_create_sem(ipc))
{
/*error*/
ipc_free(ipc);
return NULL;
}
return sem;
}
int ipc_lock_sem(ipcComm_p ipc, int semnum)
{
ipcSem_p sem;
struct sembuf sbuf;
int ret;
if(NULL == ipc)
{
/*error*/
return -1;
}
sem = (ipcSem_p)(ipc->private);
if((semnum < 0) || (semnum >= sem->nsems))
{
/*error*/
return -1;
}
memset(&sbuf, 0, sizeof(struct sembuf));
sbuf.sem_num = semnum;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
retry_lock:
ret = semop(ipc->id, &sbuf, 1);
if(-1 == ret){
if(EINTR == errno){
goto retry_lock;
}
/*error*/
return -1;
}
return 0;
}
int ipc_unlock_sem(ipcComm_p ipc, int semnum)
{
ipcSem_p sem;
struct sembuf sbuf;
int ret;
if(NULL == ipc)
{
/*error*/
return -1;
}
sem = (ipcSem_p)(ipc->private);
if((semnum < 0) || (semnum >= sem->nsems))
{
/*error*/
return -1;
}
memset(&sbuf, 0, sizeof(struct sembuf));
sbuf.sem_num = semnum;
sbuf.sem_op = 1;
sbuf.sem_flg = SEM_UNDO;
retry_unlock:
ret = semop(ipc->id, &sbuf, 1);
if(-1 == ret){
if(EINTR == errno){
goto retry_unlock;
}
/*error*/
return -1;
}
return 0;
}
int ipc_ctl_sem()
{
/*TODO...*/
return 0;
}
/*
* free malloc space and ipcs also
* call neither this or ipc_free at last
*/
int ipc_rmit(ipcComm_p ipc)
{
switch(ipc->ipctype)
{
case MSQ:
ipc_delete_msq(ipc);
break;
case SHM:
ipc_delete_shm(ipc);
break;
case SEM:
ipc_delete_sem(ipc);
break;
default:
/*unknow ipctype*/
break;
}
ipc_free(ipc);
return 0;
}
/*
*call like ipc_op(ipc, READ, 0, NULL, mtype) to read msq by mtype;
*call like ipc_op(ipc, WRITE, 0, buf, len, mtype) to write buf to msq;
*set buf=NULL whem lock or unlock the semnum sem, call like ipc_op(ipc, op, semnum, NULL);
*read shm to buf, or write buf to shm,
*call like ipc_op(ipc, op, 0, buf, len, off) when ordinary shm ops;
*call like ipc_op(ipc, op, 0, buf, dim1, dim2, dim3, ...) when array shm ops, dims are array 下标;
*call like ipc_op(ipc, op, 0, buf) when stack or roundq shm ops.
*/
int ipc_op(ipcComm_p ipc, enum IPCOP op, int semnum, void *buf, ...)
{
va_list ap;
ipc->op = op;
switch(ipc->ipctype)
{
case MSQ:
switch(op)
{
case CREATE:
return ipc_create_msq(ipc);
case READ:
va_start(ap, buf);
return ipc_read_msq(ipc, buf, ap);
case WRITE:
va_start(ap, buf);
return ipc_write_msq(ipc, buf, ap);
case DEPTH:
return msq_get_depth(ipc);
case FREE:
return ipc_free(ipc);
case RMIT:
return ipc_rmit(ipc);
default:
/*unsupport op*/
return -1;
}
break;
case SHM:
va_start(ap, buf);
switch(op)
{
case CREATE:
return ipc_create_shm(ipc);
case READ:
return ipc_read_shm(ipc, buf, ap);
case WRITE:
return ipc_write_shm(ipc, buf, ap);
case FREE:
#ifdef ENABLE_ARRAYSHM
ipc_free_array_shm(ipc);
#endif
return ipc_free(ipc);
case RMIT:
return ipc_rmit(ipc);
default:
/*unsurpport op*/
return -1;
}
break;
case SEM:
switch(op)
{
case CREATE:
return ipc_create_sem(ipc);
case LOCK:
return ipc_lock_sem(ipc, semnum);
case UNLOCK:
return ipc_unlock_sem(ipc, semnum);
case FREE:
return ipc_free(ipc);
case RMIT:
return ipc_rmit(ipc);
default:
/*unsupport op*/
return -1;
}
break;
default:
/*unsupport ipctype*/
return -1;
}
return 0;
}
#ifndef __IPC_CONN_H
#define __IPC_CONN_H
#include <sys/types.h>
/*#define MAXMSGLEN 1024
typedef struct msqMsg_s{
long int mtype;
char mtext[MAXMSGLEN];
}msqMsg_t, *msqMsg_p;*/
typedef int (*comm_fn)(void *, void *);
typedef void *(*comm_fn1)(void *);
typedef int (*comm_fn2)(void *);
typedef int (*comm_fn3)(int);
enum IPCTYPE{
MSQ = 1,
SHM,
SEM,
};
enum IPCOP{
INIT = 1,
CREATE,
READ,
WRITE,
DEPTH,
LOCK,
UNLOCK,
FREE, /*free struct ipc*/
RMIT, /*rmit ipc, and free struct ipc*/
};
#define MAX_MSQDEP (~(1 << 31)) /*0x7FFFFFFF*/
#define DECLARE_ARRAYSHM
typedef struct ipcComm_s{
enum IPCTYPE ipctype; /*msq, shm, sem*/
enum IPCOP op; /*create , read , write, lock , unlock*/
key_t key;
#ifdef ENABLE_SHMSEM
int semkey; /*for write shm*/
#endif
int id;
int status;
int mode; /**/
/*msq, shm, sem private date
*after initilize, it point to ipcMsq_p or ipcShm_p or ipcSem_p
*/
void * private;
#if ENABLE_STATISTIC
/*statistic interface*/
#endif
#if ENABLE_MONITOR
/*monitor interface*/
#endif
}ipcComm_t, *ipcComm_p;
typedef struct ipcMsq_s{
ipcComm_p comm; /*point back*/
int batch; /*read messages once*/
int msglen;
int nowait;
comm_fn1 msq_handle_read; /*handle messages*/
comm_fn2 msq_empty; /*read empty queue*/
comm_fn2 msq_full; /*write full queue*/
long int mtype;
void *msg;
}ipcMsq_t, *ipcMsq_p;
enum SHMTYPE{
ORDINARY,
ARRAY,
STACK,
ROUNDQ,
};
union semun{
int val;
struct semid_ds *buf;
ushort *array;
};
#define ISORDINARYSHM(type) ((type) & 0x100)
#define ISARRAYSHM(type) ((type) & 0x200)
#define ISSTACKYSHM(type) ((type) & 0x400)
#define ISROUNDQSHM(type) ((type) & 0x800)
#define SETORDINARYSHM(type) ((type) |= 0x100)
#define SETARRAYSHM(type) ((type) |= 0x200)
#define SETSTACKYSHM(type) ((type) |= 0x400)
#define SETROUNDQSHM(type) ((type) |= 0x800)
typedef struct ipcShm_s{
ipcComm_p comm; /*point back*/
int size;
int elemsize;
void *shmaddr;
/*bit0 read lock
*bit1 write lock
*bit8 ordinary shm
*bit9 array shm
*bit10 stack shm
*bit11 round queue shm
*bit12 ...
*/
int type;
union{
struct{
int dim; /*array dimension*/
int *bounds; /*array dimension bound*/
int *constants; /**/
}array;
struct{
int top; /*stack top*/
int depth; /*max elems*/
}stack;
struct{ /*use depth - 1 elems*/
int front; /*dequeue*/
int rear; /*enqueue*/
int depth;
}roundq;
};
#ifdef ENABLE_SHMSEM
int semid;
int mode;/*
#define READLOCK(x) ((x) & 0x1)
#define WRITELOCK(x) ((x) & 0x2)*/
#endif
}ipcShm_t, *ipcShm_p;
typedef struct ipcSem_s{
ipcComm_p comm; /*point back*/
int nsems;
}ipcSem_t, *ipcSem_p;
extern int ipc_op(ipcComm_p ipc, enum IPCOP op, int semnum, void *buf, ...);
/*extern ipcMsq_p ipc_initialize_msq(key_t key);*/
extern ipcMsq_p ipc_initialize_msq(key_t key, int msglen); /*mod by lxs*/
extern int msq_set_readbatch(ipcMsq_p msq, int batch);
extern int msq_set_handles(ipcMsq_p msq, comm_fn1 handle_read, comm_fn2 empty, comm_fn2 full);
extern int msq_set_wait(ipcMsq_p msq);
extern int msq_set_nowait(ipcMsq_p msq);
extern ipcComm_p ipc_initialize(enum IPCTYPE type);
extern ipcShm_p ipc_initialize_shm(key_t key, key_t semkey, enum SHMTYPE type, int size, int elemsize);
extern ipcShm_p ipc_initialize_array_shm(key_t key, key_t semkey, int elemsize, int dim, ...);
extern ipcSem_p ipc_initialize_sem(key_t key, int nsems);
#endif