rdm@cernapo (Alphonse Rademakers) (04/24/91)
Hi, I have a problem using shared memory (shm calls) on the HP 9000/720. I've made a little program that creates a shared memory segment and accesses it via an offset from a base array (in Fortran). The offset from the base array was returned by the routine that created the shared memory segment (in C). The creation of the shared memory seems to be fine. Ipcs shows that it has been created with the right protections. I can write nicely into the shared memory segment, but as soon as I try to access it I get a 'memory fault'. Could somebody (HP?) maybe solve this problem? Attached is a small shar file containing the sample programs. Unpack and run make_server and execute server. Commenting out the line K = IAAP(IOFFST+I) in server.f makes the program run fine. This example runs fine on DecStations and Silicon Graphics machines. Thanks in advance, Fons Rademakers. ========= cut here ====== # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Fons Rademakers <rdm@snake> on Wed Apr 17 20:09:11 1991 # # This archive contains: # hcreateg.f hcreates.c make_server server.f # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo x - hcreateg.f cat >hcreateg.f <<'@EOF' *CMZ : 26/03/91 16.21.48 by Fons Rademakers *-- Author : Fons Rademakers 20/03/91 INTEGER FUNCTION HCREATEG(MFILE, IBASE, ISIZE, ICOMAD, IOFFST) ************************************************************************ * * * HCREATEG * * * * Create a global section. This routine causes the pages at ICOMAD * * and continuing for at most ISIZE words (1 word = 4 bytes) to be * * mapped from file MFILE. MFILE will be created in the /tmp directory. * * IOFFST is the offset between the address of the common starting at * * IBASE and the address of ICOMAD. The space in ICOMAD can then be * * addressed like: IBASE(IOFFST+1,...). * * On successful completion this function returns 0. In case of an * * error -ERRNO is returned. * * HCREATEG is an interface routine that calls the C routine HCREATEI. * * * * After a global section has been created by this function, other * * processes can use the data in this global section via the functions * * HMAPG and HFREEG. * * * ************************************************************************ * CHARACTER*(*) MFILE INTEGER ICOMAD, ISIZE, IBASE, IOFFST, HCREATEI * CHARACTER*4 MKEY * MKEY = MFILE HCREATEG = HCREATEI(MKEY, IBASE, ISIZE, ICOMAD, IOFFST) * END @EOF chmod 644 hcreateg.f echo x - hcreates.c cat >hcreates.c <<'@EOF' /*CMZ : 03/04/91 17.29.25 by Fons Rademakers*/ /*-- Author : Fons Rademakers 20/03/91*/ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shm_pawc; long len; int hcreatei_(mkey, base_common, size, comaddr, offset) /* * mkey identifier for the shared segment * base_common address of base (PAW) common * size length of common in 32 bit words * comaddr starting address of the mapping (*) * offset offset of comaddr in respect to the base_common (*) * (*) = output variables */ long base_common, *comaddr, *offset; int *size; key_t *mkey; { int istat; int flag = IPC_CREAT | 0666; unsigned long off; char *paddr, *shmat(); len = *size * 4; /* create shared memory segment */ if ((shm_pawc = shmget(*mkey, len, flag)) < 0) { perror("shmget"); istat = -errno; return(istat); } /* attach shared memory segment */ if ((paddr = shmat(shm_pawc, 0, SHM_RND)) == (char *)-1) { perror("shmat"); istat = -errno; } else { istat = 0; *comaddr = (long) paddr; off = (*comaddr - base_common); *offset = off >> 2; } return(istat); } @EOF chmod 644 hcreates.c echo x - make_server cat >make_server <<'@EOF' #! /bin/sh cc -g -c hcreates.c f77 -g +ppu -o server *.f *.o @EOF chmod 755 make_server echo x - server.f cat >server.f <<'@EOF' PROGRAM PRODUCE PARAMETER (LCOM = 10) CHARACTER*4 GNAME INTEGER HCREATEG COMMON /AAP/ IAAP(LCOM) GNAME = 'pawg' IS = HCREATEG(GNAME, IAAP, LCOM, IGL, IOFFST) IF (IS .EQ. 0) THEN PRINT *, 'GLOBAL SECTION CREATED, begin address =',IGL, + ' offset from AAP =', ioffst ELSE PRINT *, 'GLOBAL SECTION ERROR = ',IS STOP ENDIF J = 0 5 DO 10 I = 1, LCOM IAAP(IOFFST+I) = J K = IAAP(IOFFST+I) 10 CONTINUE PRINT *, IAAP(IOFFST+1) J = J + 1 IF (J .LT. 5010000) GOTO 5 END @EOF chmod 644 server.f exit 0 -- Org: CERN, European Organization for Nuclear Research. Mail: 1123 Geneve, Switzerland Fax: +22 7677155 Phone: +22 7674886 or 7675049 UUCP: rdm@cernapo.cern.ch BITNET: rdm@cernvm.bitnet
jimp@cognos.UUCP (Jim Patterson) (04/29/91)
In article <RDM.91Apr24145822@aposalo.cern.ch> rdm@cernapo (Alphonse Rademakers) writes: >Hi, > I have a problem using shared memory (shm calls) on the HP 9000/720. >I've made a little program that creates a shared memory segment and >accesses it via an offset from a base array (in Fortran). >The offset from the base array was returned by the routine >that created the shared memory segment (in C). I came across a similar problem on an HP3000/935 (also HP-PA architecture, completely different O/S). It may be related to the fact that the HP-PA 32 bit address really isn't a 32-bit flat address, but a reference to one of 4 30-bit address spaces. The high order 2 bits of an address are in fact segment selectors. (There's a 32-bit address space lower down, but you can only get at it via 64-bit pointers which aren't exposed in the HP-UX system). With your test program, it appears that shmget() returns an address with the segment bits set to 3 (e.g. 0xc0019000). Addresses in the data space have the segment set to 1 (e.g. 0x40004bb8). So, your offset is trying to cross segments which is causing your memory fault. It turns out that this problem doesn't always appear, but does appear where the BASE address is in one segment but the BASE+INDEX address is in a different segment when using an indexed instruction mode. This didn't come up that much in C but often enough. Looking at your code, it looks like it will come up often or always because references are always via indexes to IBASE. This behaviour is all perfectly legitimate as near as I can tell. It doesn't appear to violate anything in ANSI C or, I suspect, standard Fortran. It's the program which is illegitimate as I suspect you know. The C program is setting up a situation where a reference to one object (the shared space) is being disguised as a reference to another completely unrelated object (the BASE array). This violates the 'contract' the compiler is fulfilling, which assumes that BASE is an array of known size in the data area. You might be able to fool the FORTRAN compiler into separating the address calculation from the dereference. (Once the machine loads the actual address into a register, it's okay; it only has trouble if the actual address is arrived at from a base/index instruction mode). If you pass an array-slice to a SUBROUTINE which points to the area you want to access, FORTRAN should generate code to reference it directly in the correct segment. Sorry, my FORTRAN is pretty rusty so I'm not going to attempt to construct code to do this. -- Jim Patterson Cognos Incorporated UUCP:uunet!mitel!cunews!cognos!jimp P.O. BOX 9707 PHONE:(613)738-1440 x6112 3755 Riverside Drive Ottawa, Ont K1G 3Z4
dhandly@hpcupt3.cup.hp.com (Dennis Handly) (05/02/91)
>/ jimp@cognos.UUCP (Jim Patterson) / 7:36 am Apr 29, 1991 /
Jim is right. The following is being discussed in an internal news
group. I'm surprised you haven't gotten a response from someone in HP.
What would cause the instruction:
LDWX,S r19(0,r20),r21
to memory fault, while the instruction sequence works:
SH2ADD r19,r20,r1
LDW 0(0,r1),r21
I'm not sure if there are any good solutions except passing the address
of the shared common from C directly to Fortran. I.e. C will have to
drive the Fortran code and Fortran will have to reference the arrays
as parameters.
I'll let someone more official than me, give you the 'bad news' or
'good news', if any :-).
jimp@cognos.UUCP (Jim Patterson) (05/08/91)
In article <48580026@hpcupt3.cup.hp.com> dhandly@hpcupt3.cup.hp.com (Dennis Handly) writes: >I'm not sure if there are any good solutions except passing the address >of the shared common from C directly to Fortran. Another solution here might be to modify the definition of the common area 'aap' from your example so that it's in the third quadrant (where shared memory is allocated) rather than the first (where data variables normally reside). You can do this at the assembly level. E.g. if you compile server to a .s file via f77 -S server.f then you can change the definition of aap as follows (context diff follows). The "QUAD=3" specification locates this area in the third 'quadrant', so it's in the same 'segment' as the shared memory area allocated by the C program. Ideally, you would want to do this once and reference it as an extern in each fortran module that needs it, but I don't think the fortran compiler works that way. The other alternative would be to edit each fortran assembly file as below (I know, Yuch!). It appears to work though. *** server.s Wed May 8 09:10:09 1991 --- server.s-changed Wed May 8 09:08:21 1991 *************** *** 189,196 **** .SPACE $TEXT$ .SUBSPA $CODE$ .EXPORT produce,PRIV_LEV=3 ! .SPACE $PRIVATE$ ! .SUBSPA $DATA$ aap .COMM 40 .SPACE $TEXT$ .SUBSPA $CODE$ --- 189,196 ---- .SPACE $TEXT$ .SUBSPA $CODE$ .EXPORT produce,PRIV_LEV=3 ! .SPACE $PRIVATE_SHARED$ ! .SUBSPA $SHARED$,QUAD=3,ALIGN=8,ACCESS=31 aap .COMM 40 .SPACE $TEXT$ .SUBSPA $CODE$ --------------------- -- Jim Patterson Cognos Incorporated UUCP:uunet!mitel!cunews!cognos!jimp P.O. BOX 9707 PHONE:(613)738-1440 x6112 3755 Riverside Drive Ottawa, Ont K1G 3Z4