bagpiper@oxy.edu (Michael Paul Hunter) (01/31/89)
I am currently writing a multi-user game on a Prime under Primix. I am going to be using a shared segment (a fixed location "array"). I am interested how similar things are done on real machines so that I can code my game in a way that will be most portable. Mike ps. please reply to me directly if at all possible... (particularly in comp.unix.questions as I don't read that group...) Michael Hunter UUCP : ....{rutgers, ames}!cit-vax!oxy!bagpiper Box 241 ARPA : bagpiper@oxy.edu Occidental College Los Angeles, CA 90041 I also hack for MicroCosm, Inc.
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 |
mark@DRD.Com (Mark Lawrence) (09/24/90)
} in article <1990Sep21.183326.13116@DRD.Com>, mark@DRD.Com (Mark Lawrence) says: } > extern const char *strerror(int); gt0178a@prism.gatech.EDU (BURNS,JIM) wrote: } I had more compile troubles w/this last line then any other in the program. } I had to substitute: } } extern char *sys_errlist[]; The following thanks to Chris Torek: /* * >From: chris@mimsy.UUCP (Chris Torek) * * In article <349@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes: *Grumble * bitch* please use "sys_errlist[]" next time, thank you.... It might even * make it easier to figure out what's wrong. * * Actually, use strerror(): This should be in your dpANS-conformant * C library (what, you have no dpANS-conformant *compiler*? :-) ) * */ #include <ANSIPrototypes.h> const char *strerror(int err) { extern const char *sys_errlist[]; extern const int sys_nerr; static char expand[40]; if ((unsigned) err < sys_nerr) return (sys_errlist[err]); (void) sprintf(expand, "unknown error code %d", err); return (expand); } -- mark@DRD.Com uunet!apctrc!drd!mark$B!J%^!<%/!!!&%m!<%l%s%9!K(B
karl@haddock.ima.isc.com (Karl Heuer) (09/25/90)
In article <1990Sep24.135530.405@DRD.Com> mark@DRD.Com (Mark Lawrence) writes: >[In response to a complaint about code using `strerror()'] >The following thanks to Chris Torek: >const char *strerror(int err) { ... } The prototype is wrong: strerror() returns an unqualified `char *' according to the ANS. The characters are *not* constant: out-of-range error values are stored in a buffer that gets overwritten by subsequent calls. (Acceptable behavior, but incompatible with the declaration.) Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
dab@myrias.com (Danny Boulet) (09/26/90)
In article <josef.654158001@peun11> josef@nixpbe.UUCP (Moellers) writes: >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. Here's another suggestion: in the systems that I have experience with their SysV shared memory facilities (Convergent Technologies Miniframe, Pyramid, Sun 3's and 386's running SCO Xenix), the system wouldn't allow me to place shared memory just anywhere. There was only a limited part of the address space in which shared memory could appear. If you specified an address outside of this limited range then the shmat call would fail. Now for my suggestion: make a call to shmat using the form that allows the system to pick where the memory will appear. Once you know where the system would like to put the memory, change your program to always ask for it to be placed at that location. This allows your program to know in advance where the memory will land although it means that you have to repeat this experiment when you try to port the code to some other system. Now for the catch: my experience with SCO Xenix (version 2.3) is quite limited but I did discover that the system would not allow me to specify where the memory should appear. It insisted on being able to chose the location itself. I wasn't able to find a work around for this (not too suprising since the manuals listed this as one of the deviations from SVR3). Note that my experience is with SCO Xenix (not SCO UNIX). The SCO UNIX may or may not be more flexible. One of the problems is that the Intel 80386 MMU only allows sharing of segments that are multiples of 4M in size and located on 4M boundaries (actually, you can share less than 4M but everything within any given 4M block is either shared or unshared). One of the consequences of this is that any implementation of shared memory on this architecture needs to keep this in mind. Since every MMU that you're every likely to encounter has some alignment requirements and such, you need to be careful about what assumptions you make if you want your code to be portable. If your software really needs to be able to insist on where the memory lands then you might have a problem (depending on whether your system allows you to say where it goes). > >-- >| 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
reidc@eliot.UUCP (Reid Carson/Development) (09/27/90)
Let me just add a few observations about shared memory, from our experiences in porting to a number of different systems. It's generally easiest to let the point of attachment be selected by the system, unless you have some reason to do otherwise. Unfortunately, one such reason is that if you need to malloc more than 20 or 30K after attaching the shared memory, the malloc may fail, since the address at which the segment gets mapped effectively limits your process's maximum break point (and can also limit the size of your stack). This varies from system to system. Under SunOS, the segment maps quite high in your address space, so there's no problem. Under Ultrix 3.0 (on our system, anyway), the segment is mapped about 33K above the current break point, which is fine unless you need to malloc more than that, or your stack gets pretty big, both of which are true for us. Our solution is to run a small test program in our Configure script when starting the port. The test program attaches a segment, checks the address it maps at, and defines a symbol in the generated config.h to indicate whether a shared memory segment maps sufficiently high or not. Thus the real program can know whether to let the segment map at the default address, or attach it up near the maximum break value. I should also mention that if you need to select the address yourself, you should put the shmat() in a loop, decrementing the address each time through, since some systems have limitations on how high you may attach a segment. You may need to decrease the address by several million on a system like a Silicon Graphics (if my memory serves me correctly).
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