#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "sharelite.h"
#include "sharelite_shm.h"
Node *_shmseg_shmat(
int
shmid ) {
char
*shmaddr;
Node *node;
if
( ( shmaddr = shmat( shmid, (
char
*) NULL, 0 ) ) == (
void
*) -1 )
return
NULL;
if
( ( node =
malloc
(
sizeof
( Node ) ) ) == NULL ) {
shmid =
errno
;
shmdt( shmaddr );
errno
= shmid;
return
NULL;
}
node->shmid = shmid;
node->shmhead = (Header *) shmaddr;
node->shmdata = shmaddr +
sizeof
( Header );
node->next = NULL;
node->shminfo = NULL;
return
node;
}
int
_shmseg_shmdt( Node *node,
int
remove
) {
if
(
remove
) {
node->shminfo->data_chunks--;
if
( shmctl( node->shmid, IPC_RMID, NULL ) == -1 )
if
( shmctl( node->shmid, IPC_RMID, NULL ) == -1 )
return
-1;
}
if
( shmdt( node->shmhead ) == -1 )
return
-1;
free
( node );
return
0;
}
Node *_shmseg_alloc( key_t key,
int
size,
int
flags,
int
is_top_node ) {
Node *node;
int
myflags, shmid;
flags = flags & 0x01FF;
myflags = flags | IPC_CREAT | IPC_EXCL;
if
( ( shmid = shmget( key, size, myflags ) ) == -1 )
return
NULL;
if
( ( node = _shmseg_shmat( shmid ) ) == NULL ) {
shmctl( shmid, IPC_RMID, NULL );
return
NULL;
}
node->shmhead->shm_magic = SHARELITE_MAGIC;
node->shmhead->next_shmid = -1;
if
( is_top_node ) {
node->shminfo = (Descriptor *) node->shmdata;
node->shmdata +=
sizeof
( Descriptor );
node->shminfo->seg_perms = flags;
node->shminfo->size_topseg = size;
node->shminfo->size_chunkseg = size;
node->shminfo->seg_semid = -1;
node->shminfo->data_chunks = 0;
node->shminfo->data_serial = 1;
node->shminfo->data_length = 0;
node->shminfo->nrefs = 0;
if
( key != IPC_PRIVATE )
node->shminfo->nrefs = 1;
}
return
node;
}
int
_sharelite_shm_attach( Share *share ) {
Node *node;
int
shmid;
if
( ( shmid = share->shmid ) == -1 ) {
if
( ( shmid = shmget( share->key, 0, 0 ) ) == -1 )
return
-1;
share->shmid = shmid;
}
if
( ( node = _shmseg_shmat( shmid ) ) == NULL )
return
-1;
if
( node->shmhead->shm_magic != SHARELITE_MAGIC ) {
_shmseg_shmdt( node, 0 );
errno
= EFAULT;
return
-1;
}
node->shminfo = (Descriptor *) node->shmdata;
node->shmdata +=
sizeof
( Descriptor );
share->head = share->tail = node;
return
0;
}
int
_sharelite_shm_create( Share *share,
int
size ) {
Node *node;
int
flags;
flags = share->flags;
if
( ( node = _shmseg_alloc( share->key, size, flags, 1 ) ) == NULL )
return
-1;
share->shmid = node->shmid;
share->size_data = node->shminfo->size_topseg
- (
sizeof
( Header ) +
sizeof
( Descriptor ) );
share->head = share->tail = node;
return
0;
}
int
_sharelite_shm_append( Share *share ) {
Node *node;
int
shmid;
if
( ( shmid = share->tail->shmhead->next_shmid ) != -1 ) {
if
( ( node = _shmseg_shmat( shmid ) ) == NULL )
return
-1;
if
( node->shmhead->shm_magic != SHARELITE_MAGIC ) {
_shmseg_shmdt( node, 0 );
errno
= EFAULT;
return
-1;
}
share->tail->next = node;
share->tail = node;
}
else
{
int
key, size, mode;
key = IPC_PRIVATE;
size = share->head->shminfo->size_chunkseg;
mode = share->head->shminfo->seg_perms;
if
( ( node = _shmseg_alloc( key, size, mode, 0 ) ) == NULL )
return
-1;
share->tail->shmhead->next_shmid = node->shmid;
share->tail->next = node;
share->tail = node;
}
node->shminfo = share->head->shminfo;
node->shminfo->data_chunks++;
return
0;
}
#define _SHMSEG_TRUNC_SETUP_MACRO_ \
if
( last == NULL ) { \
node = share->head; \
share->head = NULL; \
share->tail = NULL; \
}
else
{ \
node = last->next; \
last->next = NULL; \
share->tail = last; \
}
int
_sharelite_shm_forget( Share *share, Node *last ) {
Node *node, *next;
if
( share->tail == last )
return
0;
_SHMSEG_TRUNC_SETUP_MACRO_
while
( node != NULL ) {
next = node->next;
if
( _shmseg_shmdt( node, 0 ) == -1 )
return
-1;
node = next;
}
return
0;
}
int
_sharelite_shm_remove( Share *share, Node *last ) {
Node *node, *next;
_SHMSEG_TRUNC_SETUP_MACRO_
if
( last != NULL )
last->shmhead->next_shmid = -1;
while
( node != NULL ) {
next = node->next;
if
( _shmseg_shmdt( node, 1 ) == -1 )
return
-1;
node = next;
}
return
0;
}
int
_sharelite_shm_nconns( Share *share ) {
struct
shmid_ds buf;
if
( shmctl( share->shmid, IPC_STAT, &buf ) == -1 )
return
-1;
return
(
int
) buf.shm_nattch;
}