[comp.sys.hp] Problem using shared memory on a HP 9000/720...

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