From:	SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 15-JUN-1993 14:17:09.42
To:	EVERHART
CC:	
Subj:	RE: shared memory under VMS: HOW?

Message-Id: <9306151411.AA26692@uu3.psi.com>
Date: Tue, 15 Jun 93 09:48:18 EDT
From: Jerry Leichter <leichter@lrw.com>
To: INFO-VAX@sri.com
Subject: RE: shared memory under VMS: HOW?
X-Vms-Mail-To: UUCP%"tom@finwds01.tu-graz.ac.at"

	I need to port my BSd app. to VMS. It requires shared memory to
	exchange data between two processes. The BSD code uses the "shmget,
	shmop" and the like to allocate and map a shared memory region.

	Is there any kind soul who could tell me if this can easily be done
	under VMS and VAX-C using some of the VMS system services. I already
	found SYS$MGBLSC to "map a global section" between the physical
	address space and the processes virtual address space. Is a "global
	section" that what I need anyway?

Yes.  However, you need to use $CRMPSC to create the section - $MGBLSC will
map to a section that already exists.

VMS global section operations are similar to the BSD mmap() operations.  Both
are a better interface than the crappy shmap stuff inherited from System V.

	I'd appreciate if someone could mail me a short explanation what
	system services I need to achieve that.

It's not really all that complicated, but a little beyond what I can easily
describe in an Email message.  The discussion in the System Services books
is fairly straightforward.  I've enclosed a piece of code extracted from a
much larger system that creates global sections.  You won't be able to compile
this - it requires too many other pieces that aren't worth explaining, much
less including - but it should give you an idea of what's involved.

							-- Jerry


/*
 *		Copyright ) 1987, 1988 by Jerrold Leichter
 *
 *			All Rights Reserved
 */

/*
 * Routines to manipulate global sections
 *
 * EDITLEVEL=35
 */

#include rms
#include secdef
#include "common.h"
#include "comsec.h"
#include "sections.h"

static struct FAB fab;
static struct XABFHC xab;

/*
 * Map to a new section, creating it if necessary.  The actual creation must
 * take place under mutual exclusion, handled through the LOCK_NEWSECTION bit
 * in the common section.  This is necessary to avoid the following (unlikely,
 * but it actually occured during an early test) race condition:
 *
 *	Process A executes SYS$CREATE, creating a new file.
 *	Process B executes SYS$CREATE, finds the file already exists, hence
 *		does not set DZRO in flags.  It then executes SYS$CRMPSC.
 *	Process A DOES set DZRO, but by now the section exists, so this has
 *		no effect on its call to SYS$CRMPSC.
 *
 * At this point, whatever garbage was in the newly-created file is found in
 * the section.  In particular, the "ready" byte is probably set, but various
 * locks are not initialized, and everything falls apart.
 *
 * Note that we perhaps should be using a sync lock, not a spin lock, but
 * leads to added complex dependencies in rarely-executed code.
 *
 * There is one special case:  Since NewSection also creates the common
 * section, it cannot use it for locking!  So, no attempt is made to do any
 * locking if global Common is NULL; it's then the caller's responsibility.
 */
COND
NewSection(base,name,pages,fspec)
SECTION **base;				/* Base address of section	*/
char name[];				/* (Base) name of section	*/
LONG pages;				/* Number of pages		*/
char fspec[];				/* Optional associated file	*/
{	COND status;
	ADDR_RANGE inadr = {0 , 0};	/* Input address range (P0)	*/
	ADDR_RANGE retadr;		/* Returned address range	*/
	LONG flags = SEC$M_GBL | SEC$M_EXPREG | SEC$M_WRT;
	struct match {
		LONG criteria;
		LONG version;
		} match;
	CHANNEL chan = 0;		/* Channel number		*/
	FILE_PROT prot = 0xFF0F;	/* Protection - OWNER only	*/

	if (strlen(name) > MAXSECTIONNAME)
		BUGCHECK("Section name is too long");

	match.criteria = SEC$K_MATALL;
	match.version = 0;

	if (Common != NULL)
		Spinlock(&Common->locks,CS$V_LOCK_NEWSECTION);
	if (nargs() < 4 || fspec == 0)
		flags |= SEC$M_DZRO | SEC$M_PAGFIL;
	else
	{	fab = cc$rms_fab;
		fab.fab$l_fna = fspec;
		fab.fab$b_fns = strlen(fspec);

		fab.fab$l_alq = pages;
		fab.fab$b_fac = FAB$M_GET | FAB$M_PUT;
		fab.fab$l_fop = FAB$M_CIF | FAB$M_UFO;
		fab.fab$w_mrs = 512;
		fab.fab$b_org = FAB$C_SEQ;
		fab.fab$b_rat = 0;
		fab.fab$b_rfm = FAB$C_FIX;
		fab.fab$b_rtv = 255;
		fab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_UPI;
		fab.fab$l_xab = &xab;

		xab = cc$rms_xabfhc;		/* File header XAB	*/
		xab.xab$l_nxt = 0;		/* (input only)		*/

		TEST(status = SYS$CREATE(&fab));
		chan = fab.fab$l_stv;
		if (status == RMS$_CREATED)	/* New file		*/
			flags |= SEC$M_DZRO;	/* Start with 0's	*/
		else	pages = xab.xab$l_ebk - 1;
			/* Get length.  The "- 1" is there because we	*/
			/* always allocate an even number of pages, so	*/
			/* FFB would be 0 and EBK is the NEXT block.	*/
	}

	TEST(status = SYS$CRMPSC(&inadr,	/* inadr	*/
			&retadr,		/* retadr	*/
			0,			/* acmode	*/
			flags,			/* flags	*/
			descr(PfxName(name)),	/* gsdname	*/
			&match,			/* ident	*/
			0,			/* relpage	*/
			chan,			/* chan		*/
			pages,			/* pagcnt	*/
			0,			/* vbn		*/
			prot,			/* protection	*/
			0));			/* pfc		*/

	if (Common != NULL)
		ClearSpin(&Common->locks,CS$V_LOCK_NEWSECTION);

	*base = retadr.start;

	if (status == SS$_CREATED)		/* New section		*/
	{	(*base)->creator = ProcID;
		(*base)->chan = chan;
		(*base)->pages = pages;
		strcpy((*base)->name,name);
	}
	else					/* Old section		*/
	{	if (chan != 0)			/* File-based section	*/
			TEST(SYS$DASSGN(chan));	/* Don't need it	*/
	}

	return(status);
}

