[comp.unix.programmer] Shared Memory

andrew@gestetner.oz (Andrew Hunt) (09/21/90)

I am having problems with UNIX shared memory system functions
(shmget, shmctl, shmop) - our system is SUN O/S 4.0.x.  
I am trying to attach some data to a shared memory identifier.

	assign global_start_address
	assign global_size

	global_shmid = shmget(IPC_PRIVATE,global_size,0777|IPC_CREAT);

	shmat(global_shmid,global_start_address,SHM_RDONLY);

The shmget is always successful but the shmat fails.  I have tried 
to assign the global_start_address to many different sizes and 
addresses.  The addresses I have tried have been from malloc'ed memory,
stack space, initialised data space, uninitialised data space....
I have experimented with changing permissions and have changed most of
the parameters but the only thing that has worked is to set

	global_start_address = (char *)0;

which allow the system to find some space for me.

Does anyone know what areas of memory can be legally attached to 
shared memory?

Thanks,
	Andrew Hunt

PS: if it helps we are trying to set up the global data space of
several UNIX processes to use common memory so that we can simulate
the shared memory of an imbedded controller.

mark@DRD.Com (Mark Lawrence) (09/22/90)

andrew@gestetner.oz (Andrew Hunt) wrote:
} I am having problems with UNIX shared memory system functions
} (shmget, shmctl, shmop) - our system is SUN O/S 4.0.x.  
} I am trying to attach some data to a shared memory identifier.
} 
} 	assign global_start_address
} 	assign global_size
} 
} 	global_shmid = shmget(IPC_PRIVATE,global_size,0777|IPC_CREAT);
} 
} 	shmat(global_shmid,global_start_address,SHM_RDONLY);

shmat returns the address.  You can't tell it where you want it.  Then 
dereference the members of interest in each process using the Psh pointer.

An example:

#include <sys/types.h>
#include <sys/shm.h>
#include <memory.h>
/*
    +-----------------------------------------------------------------
    | declarations of scope process
*/
extern int      errno;      /* system call err status */
extern const char *strerror(int);
typedef struct {
    int             foo;
    float           bar;
    short           gex;
    double          snark;
}               SHMEM;
#define SHMEM_k          0x4444 /* arbitrary key */
#define SHMEM_PERMISSION  0666  /* rw-rw-rw  */
SHMEM   *Psh;
/*
    +-----------------------------------------------------------------
    | declarations of scope file
*/
static int      shmid;
/*
    +-----------------------------------------------------------------
    | executable code begins here
*/
static void
CrynDie(char *who, char *what)
{
    fprintf(stderr,
         "\n\n%s: Fatal error from %s, %s", who, what, strerror(errno));
    exit(1);
}
 /*
  * The CreateShMem function is to be called only by one process at system
  * startup.  It will create shared memory for the system.  That process must
  * then AttachShMem.  All other processes must use the AttachShMem function
  * only which will get and attach shared memory.
  */
void
CreateShMem(char *caller)
{
    SHMEM          *pshmem;

    if ((shmid = shmget(SHMEM_k, sizeof(SHMEM),
                IPC_CREAT | SHMEM_PERMISSION)) == -1)
        CrynDie(caller, "Shared memory creation failed -- fatal error");

 /* initialize the shared memory block to all NULLs  */
    if ((pshmem = (SHMEM *) shmat(shmid, 0, 0)) == (SHMEM *) - 1)
        CrynDie(caller, "attach failed");
    memset((char *) pshmem, '\0', sizeof(SHMEM));
    shmdt((char *) pshmem);
}

void
AttachShMem(char *caller)
{
    if ((shmid = shmget(SHMEM_k, sizeof(SHMEM), SHMEM_PERMISSION)) == -1)
        CrynDie(caller, "Get shared memory id failed");
    if ((Psh = (SHMEM *) shmat(shmid, 0, 0)) == (SHMEM *) - 1)
        CrynDie(caller, "attach failed");
}

-- 
mark@DRD.Com uunet!apctrc!drd!mark$B!J%^!<%/!!!&%m!<%l%s%9!K(B

cpcahil@virtech.uucp (Conor P. Cahill) (09/22/90)

In article <566@gestetner.oz> andrew@gestetner.oz (Andrew Hunt) writes:
>Does anyone know what areas of memory can be legally attached to 
>shared memory?

This is a very OS dependent portion of the code.  What I usually do
is attach a segment at the default address and compare the value of the
pointer to the value of a malloc'd pointer (yes I know that comparing
pointers to unrelated objects is not always defined).  If the two 
are too close, I detach the segment and re-attache it at a much 
higher address (like 1MB higher).


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

gt0178a@prism.gatech.EDU (BURNS,JIM) (09/22/90)

in article <1990Sep21.183326.13116@DRD.Com>, mark@DRD.Com (Mark Lawrence) says:

> shmat returns the address.  You can't tell it where you want it.  Then 

Machine dependent.

> /*
>     +-----------------------------------------------------------------
>     | declarations of scope process
> */
> extern int      errno;      /* system call err status */
> extern const char *strerror(int);

I had more compile troubles w/this last line then any other in the program.
I had to substitute:

extern char *sys_errlist[];

and for:

    fprintf(stderr,
         "\n%s: Fatal error from %s, %s\n", who, what, strerror(errno));*/

in CrynDie, I had to substitute:

    fprintf(stderr,
         "\n%s: Fatal error from %s, %s\n", who, what, sys_errlist[errno]);

to get it to compile and load on Dynix, SunOS 4.0.3, A/UX 1.1, & Ultrix
4.0.

>   * The CreateShMem function is to be called only by one process at system
>   * startup.  It will create shared memory for the system.  That process must
>   * then AttachShMem.  All other processes must use the AttachShMem function
>   * only which will get and attach shared memory.
   [...]
>     if ((shmid = shmget(SHMEM_k, sizeof(SHMEM),
>                 IPC_CREAT | SHMEM_PERMISSION)) == -1)
   [...]
>     memset((char *) pshmem, '\0', sizeof(SHMEM));

Just to avoid misunderstandings, these instructions are correct NOT
because of the way he's calling shmget(2), but simply because he's
initializing the shm seg. (Of course, he's also immediately doing a
shmdt(). ) It would only be an error to call shmget(2) w/IPC_CREAT or'd
in w/SHMEM_PERMISSION in the 2nd process if it ALSO had IPC_EXCL or'd in
as well, as the man pages on the above systems state.

I mention this because some systems guarantee that the first shmat() will
zero out the shm seg. From the HP 9000/800 HP-UX Real Time Programmers
Manual:

[example program omitted]

"Note that the fields of the tallytab entries that were not written in
subroutine write_and_read_shm() have values of 0. This is because the
first shmat called (by any process) on that shared memory identifier will
zero out all of the contents of shared memory."

I have not seen this documented in the man pages of the other above
systems, altho' a simple:

main() {
   CreateShMem("main");   /* I commented out the memset in here */
   AttachShMem("main");
   printf("%d %f %d %f\n",Psh->foo,Psh->bar,Psh->gex,Psh->snark);
   printf("%d\n",shmctl(shmid,IPC_RMID,0));
   printf("main exiting\n");
   exit(0);
}

added to the end of the posted subroutines shows all zeroes on A/UX and
Ultrix. Anybody know if this is standard?
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

josef@nixpbe.UUCP (Moellers) (09/24/90)

In <566@gestetner.oz> andrew@gestetner.oz (Andrew Hunt) writes:

>I am having problems with UNIX shared memory system functions
>(shmget, shmctl, shmop) - our system is SUN O/S 4.0.x.  
>I am trying to attach some data to a shared memory identifier.

>	assign global_start_address
>	assign global_size

>	global_shmid = shmget(IPC_PRIVATE,global_size,0777|IPC_CREAT);

>	shmat(global_shmid,global_start_address,SHM_RDONLY);

>The shmget is always successful but the shmat fails.  I have tried 
>to assign the global_start_address to many different sizes and 
>addresses.  The addresses I have tried have been from malloc'ed memory,
>stack space, initialised data space, uninitialised data space....
>I have experimented with changing permissions and have changed most of
>the parameters but the only thing that has worked is to set

>	global_start_address = (char *)0;

>which allow the system to find some space for me.

>Does anyone know what areas of memory can be legally attached to 
>shared memory?

The system will ALLWAYS find space for You. It's YOUR task to tell it
			     ^^^^^
where to put it.
^^^^^
The address where to put it ("global_start_address") must not result in
part or all of the shared memory segment overlaying part or all of Your
allocated virtual address space.
So:
	break <= global_start_address < SP - global_size
Try something like global_start_address = 0x80000000, which, on a 32 bit
system, should put the shared memory segment in the middle of Your 4GB
virtual address space.

--
| Josef Moellers		|	c/o Nixdorf Computer AG	|
|  USA: mollers.pad@nixdorf.com	|	Abt. PXD-S14		|
| !USA: mollers.pad@nixdorf.de	|	Heinz-Nixdorf-Ring	|
| Phone: (+49) 5251 104662	|	D-4790 Paderborn	|

gt0178a@prism.gatech.EDU (BURNS,JIM) (09/26/90)

in article <13991@hydra.gatech.EDU>, gt0178a@prism.gatech.EDU (BURNS,JIM) says:
[deleted]

In my above reply, for some reason, it got marked as Followup:
comp.lang.c, which is NOT what I intended. I don't normally read that
group, but I suscribed to it just to find out if my question at the end of
that post got answered, and it didn't. So one more time:

HP-UX documents it; it tests out on A/UX 1.1 and Ultrix 4.0 : the first
call to shmat() (by any process) automatically zeroes out the shm seg, so
explicit initialization is NOT necessary. Is this standard? Which one?

-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

cpcahil@virtech.uucp (Conor P. Cahill) (09/27/90)

In article <14140@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS,JIM) writes:
>HP-UX documents it; it tests out on A/UX 1.1 and Ultrix 4.0 : the first
>call to shmat() (by any process) automatically zeroes out the shm seg, so
>explicit initialization is NOT necessary. Is this standard? Which one?

This is a basic rule of unix: 

	All memory given to a program by the kernel must be cleared to 
	zero.  This applies to new sbrk()'d areas (not always to areas that
	you previously had and then released and then got back) uninitialized
	static data areas, and shared memory segments. It even applies to stack
	the first time it is used.

This is a security measure (makes sure you can't see someone elses data).

Note that it also applies to disk "memory" (if you seek past the end of a
file, write a byte, seek back to the skipped portion and read, you will get
all nulls).

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

pthonda@bgsuvax.UUCP (Killer B) (02/28/91)

I am trying to use 'Shmget' call to get shared memory.I am getting
the error message 'Invalid argument' even though the same program is
working on Sun .Could anyone tell me what's happening on Vax 785.


Thanx in advance


Pratap.

pthonda@bgsuvax.UUCP (Killer B) (03/01/91)

The program  given below is running fine on SPARC station, however when I
tried to execute the same program on Vax 785 with Unix 4.3 BSD,Iam 
encountering the message "Shmget failed :Invalid argument".I tried to 
typecast the argumnets to call 'shmget' to the right types but the 
problem is still persistent. However after going through manuals I figured
out that 'shmget' gives this whenever the programs specifies a 
shared memory segment size which is less than or greater than the system 
imposed limits.Could anyone tell me how to get the system information 
about default allowable shared memory segment sizes.

Thanx in advance.

Pratap.

And here is the code..
/*=========================================================================*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define SHMKEY  (key_t)0x10	/* Establish a key for shared memory */
#define IPCFLAGS IPC_CREAT | IPC_EXCL 
#define RDWR  0666
#define ERROR 	-1

struct shmid_ds *buf ;

static int  shmId ;	
static int  prId;
long	*shmPtr ;

main(argc,argv)
int	argc ;
char	*argv[] ;
{
	char *shmat(), *malloc() ;
	int	retValue ;

	
	/* Get the shared memory segment */
	shmId = shmget(SHMKEY,sizeof(long),RDWR|IPCFLAGS) ;
	if(shmId < 0) {

/* It's failing here. *********/
		perror("shmget failed") ;
		exit(ERROR) ;
	}

/* Set the required permissions */
/*	buf = (struct shmid_ds *) malloc(sizeof(struct shmid_ds)) ;
	buf->shm_perm.cuid = getpid() ;
	buf->shm_perm.mode = 0600 ;
	if(shmctl(shmId,IPC_SET,buf) < 0) {
		perror("Shmctl failed");
		exit(ERROR) ;
	}
*/
	/* Attach the shared memory segment */
	shmPtr =  (long *) shmat(shmId,0,0) ;	
	if((char *) shmPtr  == (char *)-1) {
		perror("Shmat failed") ;
		exit(ERROR) ;
	}

/* Initialize to a value for testing ....*/
	*shmPtr = 120L ;
 
	if((prId = fork()) < 0) {
		perror("Fork failed") ;
		exit(ERROR) ;
	}


	if(prId == 0) 
		consumer() ;
	else
		producer() ;
	shmdt(shmPtr) ;
	shmctl(shmId,IPC_RMID,0) ;
}


int producer() 
{
	int i ;
	
	for(i = 0 ; i < 100 ; i++) {
		++*shmPtr  ;
		printf("Producer incremented. Current value is %ld\n",*shmPtr);
	}
}

int consumer()
{
	int k ;

	for(k = 0 ; k < 100 ; k++) {
		--*shmPtr ;
		printf("Consumer decremented. Current value is %ld\n",*shmPtr);
	}
}

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (03/01/91)

pthonda@bgsuvax.UUCP (Killer B) wrote:
>encountering the message "Shmget failed :Invalid argument".I tried to 
>typecast the argumnets to call 'shmget' to the right types but the 
>problem is still persistent. However after going through manuals I figured

That has nothing to do with it, as you probably figured out.  The
program wouldn't have gotten past compilation if typecasting were the
answer.

>out that 'shmget' gives this whenever the programs specifies a 
>shared memory segment size which is less than or greater than the system 
>imposed limits.Could anyone tell me how to get the system information 
>about default allowable shared memory segment sizes.

SunOS #defines the minimum shared memory segment size as SHMMIN, in
/usr/include/sys/shm.h.  Your VAX probably doesn't have this, though.  A
nonportable solution is to do "adb /vmunix" and type "_shminfo+4?X" to
get the minimum page size in hex.  If all else fails, you're probably
not losing much by simply setting your shared memory segment size to
whatever the page size is on your machine.

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
How DO you delete a file called "-"?  For viewers at home, the answer is
coming up on your screen.  For those of you who wish to play it the hard
way, stand upside down with your head in a bucket of piranha fish.