#include #include #include #include #include "../include/shm.h" void *SHMNew(int length, int *id); void *SHMRef(int id, int *length); void SHMUnref(void *ptr); int SHMGetLength(int id); int SHMGetRefs(int id); #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define ABSOLUTE(x) (((x) < 0) ? ((x) * -1) : (x)) /* * Allocates a new shared memory segment with the specified length * in bytes. The new shared memory segment will have exactly 1 * reference (attachment) count. * * Returns the pointer and id of the new shared memory segment with * one attachment to this process on success, or NULL on error. */ void *SHMNew(int length, int *id) { void *ptr; if((length <= 0) || (id == NULL)) return(NULL); /* Create a new shared memory segment. */ *id = shmget( IPC_PRIVATE, length, IPC_CREAT | 0777 ); if(*id < 0) return(NULL); /* Attach shared memory to this process, this is to increase * the number of attaches to 1 on this new segment. */ ptr = shmat(*id, NULL, 0); if(ptr == (void *)-1) return(NULL); /* Destroy this new shared memory segment, since we have one * attach to it, this shared memory segment will not actually * be destroyed until the total number of detaches reaches 0. */ shmctl(*id, IPC_RMID, NULL); return(ptr); } /* * Attaches the shared memory segment specified by id to this * process. * * On success the shared memory segment pointer and length in bytes * are returned, or NULL is returned on error. */ void *SHMRef(int id, int *length) { void *ptr; struct shmid_ds shm_stat; if(length != NULL) *length = 0; if(id < 0) return(NULL); /* Attach shared memory to this process. */ ptr = shmat(id, NULL, 0); if(ptr == (void *)-1) return(NULL); /* Get statistics of newly attached shared memory segment. */ if(!shmctl(id, IPC_STAT, &shm_stat)) { if(length != NULL) *length = shm_stat.shm_segsz; } return(ptr); } /* * Detaches the shared memory segment specified by the pointer. * * If the number of references (attachments) reaches 0 then the * shared memory segment will be destroyed. */ void SHMUnref(void *ptr) { if((ptr == NULL) || (ptr == (void *)-1)) return; shmdt(ptr); } /* * Returns the length of the shared memory segment specified by id * in bytes. */ int SHMGetLength(int id) { struct shmid_ds stat_buf; if(id < 0) return(0); if(shmctl(id, IPC_STAT, &stat_buf)) return(0); else return(stat_buf.shm_segsz); } /* * Returns the number of references (attachments) of the shared * memory segment specified by id. */ int SHMGetRefs(int id) { struct shmid_ds stat_buf; if(id < 0) return(0); if(shmctl(id, IPC_STAT, &stat_buf)) return(0); else return((int)stat_buf.shm_nattch); }