From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 28-JUN-1989 20:24
To:	MRGATE::"ARISIA::EVERHART"
Subj:	RE: Use C to call SYS$CRMPSC?

Message-Id:  <8906290013.AA12475@crdgw1.ge.com>
Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed, 28 JUN 89 16:05:01 PDT
Received: from Venus.YCC.Yale.Edu by KL.SRI.COM with TCP; Wed, 28 Jun 89 15:42:20 PDT
Date: Wed, 28 Jun 89 18:44 EDT
From: "Jerry Leichter (LEICHTER-JERRY@CS.YALE.EDU)"
 <LEICHTER@Venus.YCC.Yale.Edu>
Subject: RE: Use C to call SYS$CRMPSC?
To: youngdale%v6550c.decnet@ccf3.nrl.navy.MIL, INFO-VAX@KL.SRI.COM
X-Vms-To: IN%"youngdale%v6550c.decnet@ccf3.nrl.navy.MIL"

	I have a question for all of the C gurus out there.  What I would like
	to do is map a file to virtual memory with a private section using the
	SYS$CRMPSC system service.  What I would like to know, is how do I
	find a range of virtual address that I can use, and set it aside such
	that the malloc function still works correctly.  The solution that I
	have come up with is a bit of a kluge, but it seems to work.  If for
	example I need BYT bytes, then I use malloc to allocate a region of
	memory of size BYT+1024.  I then find the first page boundary in that
	block, and use SYS$DELTVA to release the number of pages required to
	hold BYT bytes.  At this point I map the file to the pages that I
	have just deallocated.

	I have two questions:
		1) Is there a more natural way to do this?
		2) Is there any reason that what I am doing now will
			cause problems later.

Yes, there is a much simpler way to do this.  SYS$CRMPSC is perfectly happy
to find free space for you!  (It will actually extend your virtual address
space.)  This space will not interfere with malloc in any way.

Here's the relevant code for a function I use to do what you are doing.  (It's
a small piece of a large system, so many of the details - about locking, for
example - will make no sense in isolation.  But I think you should be able to
figure out the important stuff.)
							-- Jerry

/*
 * 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);
}

