Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 *   xfermem.c
 *
 *   Oliver Fromme  <oliver.fromme@heim3.tu-clausthal.de>
 *   Sun Apr  6 02:26:26 MET DST 1997
 *
 *   See xfermem.h for documentation/description.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <fcntl.h>

#include "xfermem.h"
#include "mpg123.h"

#ifndef USE_MMAP
#include <sys/ipc.h>
#include <sys/shm.h>
#endif

extern int errno;

#if defined (USE_MMAP) && defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
#define MAP_ANON MAP_ANONYMOUS
#endif

void xfermem_init (txfermem **xf, int bufsize, int msize)
{
        int regsize = bufsize + msize + sizeof(txfermem);

#ifdef USE_MMAP
#  ifdef MAP_ANON
        if ((*xf = (txfermem *) mmap(0, regsize, PROT_READ | PROT_WRITE,
                        MAP_ANON | MAP_SHARED, -1, 0)) == (txfermem *) -1) {
                perror ("mmap()");
                exit (1);
        }
#  else
        int devzero;
        if ((devzero = open("/dev/zero", O_RDWR, 0)) == -1) {
                perror ("open(/dev/zero)");
                exit (1);
        }
        if ((*xf = (txfermem *) mmap(0, regsize, PROT_READ | PROT_WRITE,
                        MAP_SHARED, devzero, 0)) == (txfermem *) -1) {
                perror ("mmap()");
                exit (1);
        }
        close (devzero);
#  endif
#else
        struct shmid_ds shmemds;
        int shmemid;
        if ((shmemid = shmget(IPC_PRIVATE, regsize, IPC_CREAT | 0600)) == -1) {
                perror ("shmget()");
                exit (1);
        }
        if ((*xf = (txfermem *) shmat(shmemid, 0, 0)) == (txfermem *) -1) {
                perror ("shmat()");
                shmctl (shmemid, IPC_RMID, &shmemds);
                exit (1);
        }
        if (shmctl(shmemid, IPC_RMID, &shmemds) == -1) {
                perror ("shmctl()");
                xfermem_done (*xf);
                exit (1);
        }
#endif
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, (*xf)->fd) < 0) {
                perror ("socketpair()");
                xfermem_done (*xf);
                exit (1);
        }
        (*xf)->freeindex = (*xf)->readindex = 0;
        (*xf)->wakeme[0] = (*xf)->wakeme[1] = FALSE;
        (*xf)->data = ((byte *) *xf) + sizeof(txfermem) + msize;
        (*xf)->metadata = ((byte *) *xf) + sizeof(txfermem);
        (*xf)->size = bufsize;
        (*xf)->metasize = msize;
}

void xfermem_done (txfermem *xf)
{
#ifdef USE_MMAP
        munmap ((caddr_t) xf, xf->size + xf->metasize + sizeof(txfermem));
#else
        if (shmdt((void *) xf) == -1) {
                perror ("shmdt()");
                exit (1);
        }
#endif
}

void xfermem_init_writer (txfermem *xf)
{
        close (xf->fd[XF_READER]);
}

void xfermem_init_reader (txfermem *xf)
{
        close (xf->fd[XF_WRITER]);
}

int xfermem_get_freespace (txfermem *xf)
{
        int freeindex, readindex;
       
        if ((freeindex = xf->freeindex) < 0
                        || (readindex = xf->readindex) < 0)
                return (0);
        if (readindex > freeindex)
                return ((readindex - freeindex) - 1);
        else
                return ((xf->size - (freeindex - readindex)) - 1);
}

int xfermem_get_usedspace (txfermem *xf)
{
        int freeindex, readindex;

        if ((freeindex = xf->freeindex) < 0
                        || (readindex = xf->readindex) < 0)
                return (0);
        if (freeindex >= readindex)
                return (freeindex - readindex);
        else
                return (xf->size - (readindex - freeindex));
}

int xfermem_write (txfermem *xf, byte *data, int count)
{
        int nbytes;

        if ((nbytes = xfermem_get_freespace(xf))> count)
                nbytes = count;
        if (nbytes) {
                if (xf->freeindex + nbytes > xf->size) {
                        int first = xf->size - xf->freeindex;
                        memcpy (xf->data + xf->freeindex, data, first);
                        memcpy (xf->data, data + first, nbytes - first);
                }
                else
                        memcpy (xf->data + xf->freeindex, data, nbytes);
                xf->freeindex = (xf->freeindex + nbytes) % xf->size;
        }
        return (nbytes);
}

int xfermem_read (txfermem *xf, byte *data, int count)
{
        int nbytes;

        if ((nbytes = xfermem_get_usedspace(xf))> count)
                nbytes = count;
        if (nbytes) {
                if (xf->readindex + nbytes > xf->size) {
                        int first = xf->size - xf->readindex;
                        memcpy (data, xf->data + xf->readindex, first);
                        memcpy (data + first, xf->data, nbytes - first);
                }
                else
                        memcpy (data, xf->data + xf->readindex, nbytes);
                xf->readindex = (xf->readindex + nbytes) % xf->size;
        }
        return (nbytes);
}

int xfermem_getcmd (int fd, int block)
{
        fd_set selfds;
        struct timeval selto = {0, 0};
        byte cmd;

        for (;;) {
                FD_ZERO (&selfds);
                FD_SET (fd, &selfds);
                switch (select(FD_SETSIZE, &selfds, NULL, NULL, block ? NULL : &selto)) {
                        case 0:
                                if (!block)
                                        return (0);
                                continue;
                        case -1:
                                if (errno == EINTR)
                                        continue;
                                return (-2);
                        case 1:
                                if (FD_ISSET(fd, &selfds))
                                        switch (read(fd, &cmd, 1)) {
                                                case 0: /* EOF */
                                                        return (-1);
                                                case -1:
                                                        if (errno == EINTR)
                                                                continue;
                                                        return (-3);
                                                case 1:
                                                        return (cmd);
                                                default: /* ?!? */
                                                        return (-4);
                                        }
                                else /* ?!? */
                                        return (-5);
                        default: /* ?!? */
                                return (-6);
                }
        }
}

int xfermem_putcmd (int fd, byte cmd)
{
        for (;;)
                switch (write(fd, &cmd, 1)) {
                        case 1:
                                return (1);
                        case -1:
                                if (errno != EINTR)
                                        return (-1);
                }
}

int xfermem_block (int readwrite, txfermem *xf)
{
        int myfd = xf->fd[readwrite];
        int result;

        xf->wakeme[readwrite] = TRUE;
        if (xf->wakeme[1 - readwrite])
                xfermem_putcmd (myfd, XF_CMD_WAKEUP);
        result = xfermem_getcmd(myfd, TRUE);
        xf->wakeme[readwrite] = FALSE;
        return ((result <= 0) ? -1 : result);
}

/* EOF */