[comp.unix.wizards] Motorola shared memory questions

ftw@datacube.UUCP (11/19/87)

Anyone out there have experience with shared memory in Sys V.3?  I'm porting
a driver from a Sun 3 environment, and one of the requirements is that a
large chunk of physical address space be mapped into a users' virtual
address space.  This range of address may not swapped or cached.

In Sun land, the driver did this by calling valloc(), and passing the pointer
returned by valloc() to a function that calls mmap() enough times to get all
the addresses mapped.

In Motorola's Sys V port, they have added extensions to the shmget() function
that allows physical addresses to be mapped.  The default parameters for
my system allow up to 128K bytes to be bought per-call.  I need more space
than this, so I call shmget() more than once, and I call shmat() to get
back the corresponding virtual addresses.  The addresses that come out of
shmat() result in a non-contiguous virtual address space.  I really need
it to be contiguous.  The second argument to shmat() can be NULL, or a
valid user virtual address.  I've tried buying memory with malloc() and
passing that pointer to shmat, but I always get EINVAL from shmat().

Any Motorola Sys V gurus out there?


				Farrell T. Woods 

Datacube Inc. Systems / Software Group	4 Dearborn Rd. Peabody, Ma 01960
VOICE:	617-535-6644;	FAX: (617) 535-5643;  TWX: (710) 347-0125
INTERNET: ftw@datacube.COM
UUCP: {rutgers, ihnp4, mirror}!datacube!ftw

allbery@ncoast.UUCP (11/26/87)

As quoted from <106600017@datacube> by ftw@datacube.UUCP:
+---------------
| In Motorola's Sys V port, they have added extensions to the shmget() function
| that allows physical addresses to be mapped.  The default parameters for
| my system allow up to 128K bytes to be bought per-call.  I need more space
| than this, so I call shmget() more than once, and I call shmat() to get
| back the corresponding virtual addresses.  The addresses that come out of
| shmat() result in a non-contiguous virtual address space.  I really need
| it to be contiguous.  The second argument to shmat() can be NULL, or a
| valid user virtual address.  I've tried buying memory with malloc() and
| passing that pointer to shmat, but I always get EINVAL from shmat().
+---------------

You're trying to attach two pieces of memory to the same address.  The way to
do this is to call shmat() with NULL the first time, then for the others
pass the virtual address immediately following the end of the previous segment
(i.e. for the second, pass the address returned by shmat() plus the size of
the segment, and so on).
-- 
Brandon S. Allbery		      necntc!ncoast!allbery@harvard.harvard.edu
{hoptoad,harvard!necntc,{sun,cbosgd}!mandrill!hal,uunet!hnsurg3}!ncoast!allbery
			Moderator of comp.sources.misc

archer@elysium.SGI.COM (Archer Sully) (11/28/87)

In article <5809@ncoast.UUCP>, allbery@ncoast.UUCP (Brandon Allbery) writes:

> You're trying to attach two pieces of memory to the same address.  The way to
> do this is to call shmat() with NULL the first time, then for the others
> pass the virtual address immediately following the end of the previous segment
> (i.e. for the second, pass the address returned by shmat() plus the size of
> the segment, and so on).
> -- 
> Brandon S. Allbery


Although Brandon doesn't mention it explicitly, there is a gotcha
here.  Shared segments need to be segment aligned, so if you try
this trick on small segments, terrible things will happen.  If the
segment size on you machine is smaller that SHMMAX, then you're really
in trouble.

archer

ftw@datacube.UUCP (11/30/87)

Just wanted to take a moment and thank the folks who responded to my
questions about shared memory on Sys V.  To summarize:

When I call shmget(), I should grab as much memory as I can, and that size
arg. should be a multiple of a "shared memory block size".

When I call shmat() for the first time, use a NULL arg. for the attach
address; shmat() gives out virtual addresses that are always (shared memory)
block aligned, even if the corresponding shmat() asked for a smaller chunk
of memory.

Successive calls to shmat() should have an arg of whatever the first shmat()
returned for the virtual address, plus the number of bytes requested so far.
This ensures a nice, flat virtual address space.

The Sun scheme of valloc()/mmap() isn't applicable because shmat() needs
an address that's not already in use (allocated my malloc()).  Almost
everyone who responded pointed this out.

A virtual address given to shmat() MUST always be (shared memory) block
aligned.  If you specify through the third arg that you don't want shmat()
to align the address for you, and you don't give it one that is already
properly aligned, the call will fail.

Jonathan Creighton (pyrnj!oracle!jcreight) has an interesting suggestion:
he suggests that I choose a virtual address that is closer to the midpoint
between the current stack and heap, so that I won't run out of space for
malloc() or lotsa nested funtion calls.

Thank you all for the help!



				Farrell T. Woods 

Datacube Inc. Systems / Software Group	4 Dearborn Rd. Peabody, Ma 01960
VOICE:	617-535-6644;	FAX: (617) 535-5643;  TWX: (710) 347-0125
INTERNET: ftw@datacube.COM
UUCP: {rutgers, ihnp4, mirror}!datacube!ftw

crp@cci632.UUCP (12/03/87)

In article <106600019@datacube>, ftw@datacube.UUCP writes:
> 
> When I call shmat() for the first time, use a NULL arg. for the attach
> address; shmat() gives out virtual addresses that are always (shared memory)
> block aligned, even if the corresponding shmat() asked for a smaller chunk
> of memory.
> 
> Successive calls to shmat() should have an arg of whatever the first shmat()
> returned for the virtual address, plus the number of bytes requested so far.
				    ^^^^

Be warned that some implementations allocate segments like this
(i.e. progressively higher addresses), while others allocate segments
from higher to lower addresses. In which case, the virtual address of the
second and subsequent segments the address of the previous segment *minus*
the *size* of that segment. Note that in this scenario, the address of the
contiguous memory is actually the address of the *last* segment allocated;
while with progressive addresses it's the address of the *first* segment.

In any case, you should always attach any partial segment required last
(i.e. size_of_all_shared_memory % segment_size), so that all segments
are properly aligned. For example, to attach 600,000 bytes of shared
memory on a machine with 128K segments and progressive addresses:

	start = attach 128K segment at first available address
	nextaddr = start + 128K
	nextaddr = attach 128K segment at nextaddr
	nextaddr += 128K
	nextaddr = attach 128K segment at nextaddr
	nextaddr += 128K
	nextaddr = attach 128K segment at nextaddr
	nextaddr += 128K
	nextaddr = attach 88000 byte segment at nextaddr
	return(start)

> This ensures a nice, flat virtual address space.
> 
> Jonathan Creighton (pyrnj!oracle!jcreight) has an interesting suggestion:
> he suggests that I choose a virtual address that is closer to the midpoint
> between the current stack and heap, so that I won't run out of space for
> malloc() or lotsa nested funtion calls.

Also be warned that dynamic stack growth or heap growth can trash (or detach)
shared memory in certain implementations. You'll have to test your own
configurations to learn this. An easy way out of problems like this is to
pre-allocate stack and heap by calling an initialization function with 
*lots* of local variables (to grow the stack) and then malloc(lots_of_mem).

Chuck Privitera		(... !rochester!cci632!crp)
Computer Consoles Inc.
Rochester, New York
variable

lwv@n8emr.UUCP (Larry W. Virden) (12/05/87)

One warning!  Shared memory , even accessed via SVID compatible routines, 
are not all equal!  So for a truely compatible product, one needs to write
quite a sophisticated set of routines to call OVERTOP of shared memory, then
let them have different #ifdefs or modules for the different o/s.

Here are just TWO of the differences:

1. Under one well known and widely used CPU architecture, one is limited to
either 32k or 64k shared memory segments per call.  I forget which it is
right now... sorry!

2. Under another well known system, the vendor requires shared memory to 
be within one's program-breakpoint.  That is, you have to do a malloc() of
the appropriate size and then map the appropriately aligned address into
the shared memory environment.  Note that this is a NICE feature in one
sense, since you end up with a less restrictive environment interacting wih
stdio, other routines, etc. - as long as EVERYONE uses malloc and not
brk directly.

Since the internal implementation is not described within the SVID description,
vendors are free to implement it in many different ways.  For instance,
I have always wondered why shared memory wasnt implemented OUTSIDE of the
maximum breakpoint value; that would be another way to guarantee that
the program's use of malloc/etc would never interfere.


-- 
Larry W. Virden	 75046,606 (CIS)
674 Falls Place, Reynoldsburg, OH 43068 (614) 864-8817
cbosgd!n8emr!lwv (UUCP) 	cbosgd!n8emr!lwv@ucbvax.Berkeley.EDU (BITNET)
We haven't inherited the world from our parents, but borrowed it from our children.