*BSD News Article 72637


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!munnari.OZ.AU!metro!metro!asstdc.scgt.oz.au!nsw.news.telstra.net!act.news.telstra.net!psgrain!usenet.eel.ufl.edu!spool.mu.edu!howland.reston.ans.net!newsfeed.internetmci.com!hunter.premier.net!netnews.worldnet.att.net!ix.netcom.com!netcom.net.uk!dispatch.news.demon.net!demon!awfulhak.demon.co.uk!awfulhak.demon.co.uk!awfulhak.demon.co.uk!not-for-mail
From: brian@awfulhak.demon.co.uk (Brian Somers)
Newsgroups: comp.unix.bsd.misc,comp.unix.programmer
Subject: Re: Using Shared memory...
Date: 29 Jun 1996 22:50:11 -0500
Organization: Coverform Ltd.
Lines: 177
Message-ID: <4r4thj$102@anorak.coverform.lan>
References: <4qt6l2$4o6@taurus.adnc.com>
NNTP-Posting-Host: localhost.coverform.lan
X-NNTP-Posting-Host: awfulhak.demon.co.uk
X-Newsreader: TIN [version 1.2 PL2]
Xref: euryale.cc.adfa.oz.au comp.unix.bsd.misc:1195 comp.unix.programmer:39034

Joe Avila (avila@adnc.com) wrote:
: Can someone post an example of how shared memory works between two processes?
: I need to implement this into some programs I'm writing but I just can get the
: jist of it through reading the man pages.  All help is greatly appreciated.

This isn't really the correct news group - this is not a bsd specific thing.
I've cross-posted to comp.unix.programmer.

Think of it like creating a file for ipc.  Usually, your server creates a
"file" of a given size and writes something to it - your client can then read
the file.  You need some sort of co-ordination too.  A good mechanism for this
would be a semaphore (although it depends on your application).  The server
sets it to one after creating the shared memory.  When someone wants to 
muck around with it, they down it to zero, do their mucking around, then
up it to one again.  A second semaphore is used to make sure that only
one server can be started.

The example client writes some data (passed on the command line) to the
shared memory after outputing what was there.  There are three modules
in my example, server.h, server.c and client.c:

server.h:
#define IPCKEY 1234 /* my (well known) shared memory & semaphore key */
#define SHMSIZE 4096

server.c:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include "server.h"

void Finish( int sig )
{
    signal( sig, SIG_IGN );
}

int main()
{
    /* Note: SEM_R & SEM_W aren't defined - despite docs */
    int sAccess = ((IPC_R|IPC_W)>>6) + ((IPC_R|IPC_W)>>3) + (IPC_R|IPC_W);
    int semid = semget( (key_t)IPCKEY, 2, sAccess|IPC_CREAT );

    signal( SIGTERM, Finish );

    if( semid == -1 )
        perror( "semget" );
    else
    {
        int mAccess, shmid;
        struct sembuf op;

        op.sem_num = 1;
        op.sem_flg = IPC_NOWAIT|SEM_UNDO;
        op.sem_op = 1;
        if( semop( semid, &op, 1 ) == -1 )
        {
            perror( "semup(1)" );
            return 1;
        }
        op.sem_op = -2;
        if( !(semop( semid, &op, 1 ) == -1 && errno == EAGAIN) )
        {
            fputs( "A server is already running\n", stderr );
            return 1;
        }

        mAccess = ((SHM_R|SHM_W)>>6) + ((SHM_R|SHM_W)>>3) + (SHM_R|SHM_W);
        shmid = shmget( (key_t)IPCKEY, SHMSIZE, mAccess|IPC_CREAT );

        if( shmid == -1 )
            perror( "shmget" );
        else
        {
            char *Ptr = (char *)shmat( shmid, 0, 0 );
            if( !Ptr )
                perror( "shmat" );
            else
            {
                *Ptr = '\0';
                /* We've set things up */
                op.sem_num = 0;
                op.sem_flg = SEM_UNDO;
                op.sem_op = 1;
                if( semop( semid, &op, 1 ) == -1 )
                    perror( "semup(0)" );

                /* Hang around for a signal */
                pause();

                /* If someone's in, let them out */
                op.sem_op = -1;
                if( semop( semid, &op, 1 ) == -1 )
                    perror( "semdown" );
                if( shmdt( Ptr ) == -1 )
                    perror( "shmdt" );
            }
            if( shmctl( shmid, IPC_RMID, 0 ) )
                perror( "shmctl(IPC_RMID)" );
        }
        if( semctl( semid, 0, IPC_RMID, 0 ) == -1 )
            perror( "semctl(IPC_RMID)" );
    }
    return 0;
}

client.c:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <stdio.h>
#include "server.h"

int main( int argc, char *argv[] )
{
    int Result = -1;
    int semid;

    if( argc != 2 )
    {
        fputs( "Usage: client Message\n", stderr );
        return 1;
    }

    if( semid = semget( (key_t)IPCKEY, 0, 0 ), semid == -1 )
        perror( "semget" );
    else
    {
        int shmid;
        struct sembuf op;

        op.sem_num = 0;
        op.sem_flg = IPC_NOWAIT|SEM_UNDO;
        op.sem_op = -1;
        if( semop( semid, &op, 1 ) == -1 )
        {
            perror( "semdown" );
            return 1;
        }

        shmid = shmget( (key_t)IPCKEY, 0, 0 );

        if( shmid == -1 )
            perror( "shmget" );
        else
        {
            /* My go */
            char *Ptr = (char *)shmat( shmid, 0, 0 );
            if( Ptr )
            {
                printf( "Message was \"%s\"\n", Ptr );
                strncpy( Ptr, argv[1], SHMSIZE );
                Ptr[ SHMSIZE - 1 ] = '\0';

                if( shmdt( Ptr ) == -1 )
                    perror( "shmdt" );
            }
        }
        op.sem_op = 1;
        if( semop( semid, &op, 1 ) == -1 )
        {
            perror( "semup" );
            return 1;
        }
    }
    return Result;
}


--
Brian <brian@awfulhak.demon.co.uk>
Don't _EVER_ lose your sense of humour....