[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference vaxaxp::vmsnotes

Title:VAX and Alpha VMS
Notice:This is a new VMSnotes, please read note 2.1
Moderator:VAXAXP::BERNARDO
Created:Wed Jan 22 1997
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:703
Total number of notes:3722

237.0. "memory-resident sections: new for OpenVMS Alpha V7.1" by CUJO::SAMPSON () Sat Feb 22 1997 16:32

	Hello,

	Memory-resident global sections are available as a new feature
of OpenVMS Alpha V7.1.  My belief is that VMS Engineering has accomplished
this at least partly in fulfillment of a "phase zero" request that I made a
number of years ago, on behalf of a customer.  Our thanks and appreciation
go to VMS Engineering for providing this new feature, which should prove
useful over the next several years for a wide variety of OpenVMS applications
and customers.  In order to encourage the customer (who has been requesting
this feature all these years) to actually start making use of it, I have
written a fairly simple demo program to take the new system services
through their paces, called memres.c, posted in my next reply.  Okay, I
admit it is somewhat lacking in both glamor and comments.  Feel free to
make whatever use of it you can.  As always, if you find typos, please
let me know about them; otherwise I don't have any way of checking it for
errors on this network.  Perhaps others may also want to reply with some
programs of their own, which illustrate the use of memory-resident global
sections.  This new feature, combined with 64-bit virtual addressing, can
and should be used as another technical "selling point" for OpenVMS as a
full-featured applications platform.  So, please tell all of your technical
customers (especially those with "real-time" requirements) about it!

	Thanks,
	Bob Sampson
T.RTitleUserPersonal
Name
DateLines
237.2AUSS::GARSONDECcharity Program OfficeSun Feb 23 1997 17:186
re .1
    
> * To use:     $ MEMRES :== $SYS$DISK:[]MEMRES.EXE ! (foreign command symbol)
> *             $ DEFINE/JOB DCL$PATH SYS$DISK:[]   ! (tell DCL where to find)
    
    These two DCL commands would appear to be alternatives.
237.3I'll change the comments to reflect that factCUJO::SAMPSONSun Feb 23 1997 20:331
    re .-1: Yes, that's true.  They're two ways of doing the same thing.
237.1memres.cCUJO::SAMPSONSun Feb 23 1997 20:50656
/*
 * MEMRES.C; demonstrate use of memory-resident sections.
 * This program is purported to work on OpenVMS Alpha V7.1 and higher.
 *
 * To compile: $ CC/PREFIX=ALL MEMRES
 * To link:    $ LINK/SYSEXE MEMRES
 * To define:  $! MEMRES can be provided as a command by either:
 *             $ MEMRES :== $SYS$DISK:[]MEMRES.EXE ! (foreign command symbol)
 *             $! or (only one of these two commands is necessary):
 *             $ DEFINE/JOB DCL$PATH SYS$DISK:[]   ! (tell DCL where to find)
 * To run:     $ MEMRES <section-name> <size-in-bytes>
 *
 * To delete a section, specify <section-name>, but omit <size-in-bytes>.
 *
 * *** Please Note:
 *
 * If the second argument specifies any number of bytes other than an
 * exact multiple of the page size, it is interpreted as <size-in-pages>.
 * Yes, that is a hazardous arrangement, however convenient it may be.
 * Take care not to deplete the available free memory on your system.
 * If I had known of a system data cell containing the current amount
 * of free memory, I would have checked it against the amount requested.
 *
 * If a third argument of "mb" is specified, the second argument is
 * interpreted as <size-in-Megabytes>.
 */
#include <builtins.h>		/* Alpha built-in functions	*/
#include <c_asm.h>		/* in-line assembler		*/
#include <descrip.h>		/* string descriptors		*/
#include <hwrpbdef.h>		/* H/W restart parameter block	*/
#include <ints.h>		/* integer types		*/
#include <lib$routines.h>	/* RTL LIB routines		*/
#include <secdef.h>		/* section flags		*/
#include <ssdef.h>		/* SS$_ message codes		*/
#include <starlet.h>		/* system services		*/
#include <stdio.h>		/* standard I/O			*/
#include <stdlib.h>		/* standard library		*/
#include <string.h>		/* string routines		*/
#include <stsdef.h>		/* message code format		*/
#include <vadef.h>		/* virtual address format/flags	*/

typedef struct
{
  uint32 cnt;
  uint32 off;
} pccs_t;

typedef union
{
  uint64 all;
  pccs_t pcc;
} pccu_t;

#pragma extern_model save
#pragma extern_model relaxed_refdef shr
extern const HWRPB *BOO$GA_HWRPB;	/* pointer to restart parameter block */
extern const uint32 MMG$GL_MEMSIZE;	/* actual memory size in pages */
extern const uint64 MMG$GQ_PAGE_SIZE;	/* system page size in bytes */
extern const uint64 MMG$GQ_PTES_PER_PAGE; /* # of PTEs that fit on 1 PT page */
extern const uint32 EXE$GL_SYSTICK;	/* # of 100-ns units per clock tick */
extern volatile int64 EXE$GQ_SYSTIME;	/* current quadword system time */
#pragma extern_model restore

#define one_KB 1024uL
#define one_MB (one_KB * one_KB)

static const $DESCRIPTOR(default_gs_name,"tst-mem-res-sec");

static const uint32 create_gdzro_flags =
	SEC$M_DZRO | SEC$M_GBL | SEC$M_PERM |
	SEC$M_SYSGBL | SEC$M_MRES | SEC$M_WRT;

static const uint32 mgblsc_flags =
	SEC$M_EXPREG | SEC$M_GBL | SEC$M_NO_OVERMAP | SEC$M_SYSGBL | SEC$M_WRT;

static const int64 systime_units_per_second = 10000000L;

static const char *access_mode_name[4] =
	{ "kernel", "executive", "supervisor", "user" };

void show_pcc(pccu_t pcc_beg, pccu_t pcc_end)
{
  pccu_t pcc_dif;
  double cpu_cycle_time_seconds, cpu_seconds, cpu_systime_units;
  int64 bintim;
  struct dsc$descriptor_s ascdsc;
  char asctim[24];

/* determine the CPU cycle time in seconds */
  cpu_cycle_time_seconds = BOO$GA_HWRPB->hwrpb$iq_cycle_count_freq;
  cpu_cycle_time_seconds = 1.0 / cpu_cycle_time_seconds;

/* calculate the elapsed and CPU times in cycles */
  pcc_dif.pcc.cnt = pcc_end.pcc.cnt - pcc_beg.pcc.cnt;
  pcc_dif.pcc.off = pcc_end.pcc.off - pcc_beg.pcc.off;
  pcc_dif.pcc.off += pcc_dif.pcc.cnt;

/* calculate the CPU time in seconds */
  cpu_seconds = cpu_cycle_time_seconds * (double)pcc_dif.pcc.off;

/* calculate the approximate CPU time in systime units */
  cpu_systime_units = (cpu_seconds+0.005) * (double)systime_units_per_second;
  bintim = -cpu_systime_units;

/* get text representation of CPU time interval */
  ascdsc.dsc$w_length  = sizeof(asctim) - 1;
  ascdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  ascdsc.dsc$b_class   = DSC$K_CLASS_S;
  ascdsc.dsc$a_pointer = asctim;
  sys$asctim(&ascdsc.dsc$w_length, &ascdsc, &bintim, 0);
  asctim[ascdsc.dsc$w_length] = '\0';

/* display only the CPU time (elapsed seems error-prone on SMP systems) */
  printf(" __RPCC() difference, CPU: %s; %E sec (%u cyc).\n",
	asctim, cpu_seconds, pcc_dif.pcc.off);
}

void report_lkwset_failure(int failure, int64 failed_va, uint64 failed_length)
{
  struct dsc$descriptor_s msgdsc;
  char msg[256];

  printf("Failed VA %016LX; %Lu page%s; ",
	failed_va, failed_length / MMG$GQ_PAGE_SIZE,
	(((failed_length / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"));
  msgdsc.dsc$w_length  = sizeof(msg) - 1;
  msgdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  msgdsc.dsc$b_class   = DSC$K_CLASS_S;
  msgdsc.dsc$a_pointer = msg;
  sys$getmsg(failure, &msgdsc.dsc$w_length, &msgdsc, 2, 0);
  msg[msgdsc.dsc$w_length] = '\0';
  printf("%s\n", msg);
}

int lock_all_regions()
{
  int status, failure;
  int64 region_start_va_64, lkwset_start_va_64, return_va_64, failed_va;
  uint64 lkwset_length_64, return_length_64, failed_length, locked_length;
  uint32 lregsum;
  regsum regsum;

  if (sizeof(regsum) != VA$C_REGSUM_LENGTH)
  {
    printf("    sizeof(regsum) = %u.\n", sizeof(regsum));
    printf("VA$C_REGSUM_LENGTH = %u.\n", VA$C_REGSUM_LENGTH);
  }

  region_start_va_64 = -1L;
  while ((status = sys$get_region_info(VA$_NEXT_REGSUM_BY_VA, 0,
	region_start_va_64, 0, sizeof(regsum), &regsum, &lregsum)) & 1)
  {
    if (lregsum != sizeof(regsum))
    {
      printf("      lregsum  = %u.\n", lregsum);
      printf("sizeof(regsum) = %u.\n", sizeof(regsum));
    }
    printf("\nRegion ID: %Lu.\n", *((uint64*)regsum.va$q_region_id));
    if (regsum.va$v_descend)
      printf("  descending\n");
    if (regsum.va$v_p0_space)
      printf("  in P0 space\n");
    if (regsum.va$v_p1_space)
      printf("  in P1 space\n");
    if (regsum.va$v_permanent)
      printf("  permanent\n");
/*
    if (regsum.va$v_no_clone)
      printf("  no clone\n");
 */
    if (regsum.va$v_shared_pts)
      printf("  shared page tables\n");
    printf("Region protection; owner mode: %s; create mode: %s\n",
	access_mode_name[regsum.va$v_owner_mode],
	access_mode_name[regsum.va$v_create_mode]);
    printf("   Start VA %016LX\n", regsum.va$pq_start_va);
    printf("1st Free VA %016LX\n", regsum.va$pq_first_free_va);
    printf("Region Size %Lu bytes; %Lu page%s; %Lu MB\n",
		*((uint64*)regsum.va$q_region_size),
		*((uint64*)regsum.va$q_region_size) / MMG$GQ_PAGE_SIZE,
(((*((uint64*)regsum.va$q_region_size) / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		*((uint64*)regsum.va$q_region_size) / one_MB);

    if (regsum.va$v_descend)
    {
      lkwset_start_va_64 = regsum.va$pq_first_free_va;
      lkwset_start_va_64 += MMG$GQ_PAGE_SIZE;
      lkwset_length_64 = regsum.va$pq_start_va;
      lkwset_length_64 += *((uint64*)regsum.va$q_region_size);
      lkwset_length_64 -= lkwset_start_va_64;
    }
    else
    {
      lkwset_start_va_64 = regsum.va$pq_start_va;
      lkwset_length_64 = regsum.va$pq_first_free_va - regsum.va$pq_start_va;
    }

    printf("LKWSET VA %016LX; %Lu bytes; %Lu page%s; %Lu MB\n",
		lkwset_start_va_64,
		lkwset_length_64,
		lkwset_length_64 / MMG$GQ_PAGE_SIZE,
		(((lkwset_length_64 / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		lkwset_length_64 / one_MB);

    failure = 0;
    failed_va = 0L;
    failed_length = 0uL;
    locked_length = 0uL;
    for (;;)
    {
      status = sys$lkwset_64(lkwset_start_va_64, lkwset_length_64, 0,
		&return_va_64, &return_length_64);

      if (return_va_64 == -1L)
      {
	return_length_64 = 0uL;
      }
      else
      {
	if (failed_length)
	{
	  report_lkwset_failure(failure, failed_va, failed_length);
	  failure = 0;
	  failed_va = 0L;
	  failed_length = 0uL;
	}
	printf("Locked VA %016LX; %Lu page%s into working set.\n",
		return_va_64, return_length_64 / MMG$GQ_PAGE_SIZE,
		(((return_length_64 / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"));

	lkwset_start_va_64 += return_length_64;
	lkwset_length_64   -= return_length_64;
	locked_length      += return_length_64;
      }

      if (!(status & 1))
      {
	if (failure == 0) failure = status;
	if (status != failure)
	{
	  report_lkwset_failure(failure, failed_va, failed_length);
	  failure = status;
	  failed_va = lkwset_start_va_64;
	  failed_length = 0uL;
	}
	else if (return_length_64)
	{
	  failed_va = lkwset_start_va_64;
	}

	lkwset_start_va_64 += MMG$GQ_PAGE_SIZE;
	lkwset_length_64   -= MMG$GQ_PAGE_SIZE;
	failed_length      += MMG$GQ_PAGE_SIZE;
      }

      if (status == SS$_LKWSETFUL) break;
      if (lkwset_length_64 == 0uL) break;
    } /* keep trying until done or lock limit reached */

    if (failed_length)
    {
      report_lkwset_failure(failure, failed_va, failed_length);
      failure = 0;
      failed_va = 0L;
      failed_length = 0uL;
    }

    printf("Total of %Lu bytes; %Lu page%s; %Lu MB locked in region ID %Lu.\n",
		locked_length,
		locked_length / MMG$GQ_PAGE_SIZE,
		(((locked_length / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		locked_length / one_MB,
		*((uint64*)regsum.va$q_region_id));

    region_start_va_64 = regsum.va$pq_start_va;
    region_start_va_64 += *((uint64*)regsum.va$q_region_size);
  }
  return status;
}

int memres(int argc, char *argv[])
#pragma nostandard
main_program
#pragma standard
{
  int status;
  int msgvec[2] = {1,0};
  int64 systime_units_per_clock_int;
  int64 d64;
  uint64 i64, n64, i64prv, i64dsp;
  uint64 nbytes, nclkint, kclkint;
  uint64 clear_length;
  uint64 region_id;
  uint64 region_length;
  uint64 mapped_length;
  uint64 unmapped_length;
  uint64 deleted_length;
  uint64 reserved_length;
  struct dsc$descriptor_s gs_name;
  register pccu_t pcc_beg, pcc_end;

#pragma required_pointer_size save
#pragma required_pointer_size long
  void *region_va;
  void *mapped_va;
  void *unmapped_va;
  void *deleted_va;
  int64 *p64;
  void *_memset64(void *__s, int __c, size_t __n);
#pragma required_pointer_size restore

/* determine the expected system time increment for each clock interrupt */
  systime_units_per_clock_int = systime_units_per_second;
  systime_units_per_clock_int <<= 12L; /* factor of 4096 */
  systime_units_per_clock_int /= BOO$GA_HWRPB->hwrpb$iq_clock_int_freq;

/* this *should* be the same as EXE$GL_SYSTICK */
  if (systime_units_per_clock_int != EXE$GL_SYSTICK)
  {
    printf("EXE$GL_SYSTICK = %u.\n", EXE$GL_SYSTICK);
    printf("expected value = %Ld.\n", systime_units_per_clock_int);
  }

/* determine the global section name */
  gs_name.dsc$b_dtype = DSC$K_DTYPE_T;
  gs_name.dsc$b_class = DSC$K_CLASS_S;
  if (argc < 2)
  {
    gs_name.dsc$w_length  = default_gs_name.dsc$w_length;
    gs_name.dsc$a_pointer = default_gs_name.dsc$a_pointer;
  }
  else
  {
    gs_name.dsc$w_length  = strlen(argv[1]);
    gs_name.dsc$a_pointer = argv[1];
  }

/* determine the section size in bytes */
  nbytes = 0uL;
  if (argc > 2)
  {
    nbytes = atoq(argv[2]);
    if ((argc > 3) && !strcmp(argv[3],"mb"))
    {
      nbytes *= one_MB;
    }
    else if (nbytes % MMG$GQ_PAGE_SIZE)
    {
      printf("Section size (second argument)\n");
      printf("  is not an exact multiple of the page size (%Lu bytes);\n",
		MMG$GQ_PAGE_SIZE);
      printf("  interpreting value as %Lu pages,\n", nbytes);
      nbytes *= MMG$GQ_PAGE_SIZE;
      printf("  or %Lu bytes.\n", nbytes);
    }

    if (nbytes > (MMG$GQ_PAGE_SIZE*(MMG$GL_MEMSIZE/2)))
    {
      printf("You asked for more than half the memory on the system.\n");
      printf("This seems unreasonable, so you will get only one page.\n");
      nbytes = MMG$GQ_PAGE_SIZE;
    }
  }

/*
  printf("System memory size: %Lu bytes; %Lu pages; %Lu MB\n",
		MMG$GL_MEMSIZE * MMG$GQ_PAGE_SIZE,
		MMG$GL_MEMSIZE,
		MMG$GL_MEMSIZE * MMG$GQ_PAGE_SIZE / one_MB);

  printf("Page table entry size: %Lu bytes.\n",
		MMG$GQ_PAGE_SIZE / MMG$GQ_PTES_PER_PAGE);

  printf("Memory mapped by one PTE page: %Lu bytes; %Lu pages; %Lu MB\n",
		MMG$GQ_PAGE_SIZE * MMG$GQ_PTES_PER_PAGE,
		MMG$GQ_PTES_PER_PAGE,
		MMG$GQ_PAGE_SIZE * MMG$GQ_PTES_PER_PAGE / one_MB);
 */

/*
 * If section size in bytes is non-zero, try to create a new section.
 * If a section with the same name already exists, use that one.
 * Map the section into (64-bit) process virtual address space.
 * Create a special region so that shared page tables can be used.
 */
  if (nbytes)
  {
/* try to create a new section */
try_create_gdzro:
    reserved_length = 0uL;
    printf("Trying to create a new section \"%s\"...\n", gs_name.dsc$a_pointer);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$create_gdzro(
		&gs_name,			/* gs_name_64		*/
		0uL,				/* ident_64		*/
		0,				/* prot			*/
		nbytes,				/* length_64		*/
		0,				/* acmode		*/
		create_gdzro_flags,		/* flags		*/
		&reserved_length);		/* reserved_length_64	*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (((status == SS$_MRES_PFNSMALL)
      || (status == SS$_INSFLPGS))
     && (reserved_length != 0uL)
     && (nbytes > reserved_length))
    {
      printf(
	"Trying again; reducing request from %Lu to reserved %Lu bytes.\n",
	nbytes, reserved_length);
      nbytes = reserved_length;
      goto try_create_gdzro;
    }
    else if (status == SS$_DUPLNAM)
    {
      printf("Section \"%s\" already exists;\n", gs_name.dsc$a_pointer);
    }
    else if (status & 1)
    {
      printf("New section \"%s\" created;\n", gs_name.dsc$a_pointer);
    }
    else
    {
      fprintf(stderr, "Failed to create section \"%s\".\n",
	gs_name.dsc$a_pointer);
      return status | STS$M_INHIB_MSG;
    }
    printf("  Reserved Length: %Lu bytes; %Lu pages; %Lu MB\n",
		reserved_length,
		reserved_length / MMG$GQ_PAGE_SIZE,
		reserved_length / one_MB);
/* create a region with suitable attributes */
    region_id = 0;
    region_va = 0;
    region_length = 0uL;
    printf("Trying to create a region for mapping the section...\n");
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$create_region_64(
		nbytes,				/* length_64		*/
		VA$C_REGION_UCREATE_UOWN,	/* region_prot		*/
		VA$M_SHARED_PTS,		/* flags		*/
		&region_id,			/* return_region_id_64	*/
		&region_va,			/* return_va_64		*/
		&region_length,			/* return_length_64	*/
		0uL);				/* start_va_64		*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to create region for section.\n");
      return status | STS$M_INHIB_MSG;
    }
    printf("Created region ID %Lu for section;\n", region_id);
    printf("  Region VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		region_va,
		region_length,
		region_length / MMG$GQ_PAGE_SIZE,
		region_length / one_MB);
/* use the region to map the section */
    mapped_va = 0;
    mapped_length = 0uL;
    printf("Trying to map the section using the region...\n");
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$mgblsc_64(
		&gs_name,			/* gs_name_64		*/
		0uL,				/* ident_64		*/
		&region_id,			/* region_id_64		*/
		0uL,				/* section_offset_64	*/
		nbytes,				/* length_64		*/
		0,				/* acmode		*/
		mgblsc_flags,			/* flags		*/
		&mapped_va,			/* return_va_64		*/
		&mapped_length,			/* return_length_64	*/
		0uL);				/* start_va_64		*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to map section.\n");
      return status | STS$M_INHIB_MSG;
    }
    printf("Mapped memory-resident section \"%s\";\n", gs_name.dsc$a_pointer);
    printf("  Mapped VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		mapped_va,
		mapped_length,
		mapped_length / MMG$GQ_PAGE_SIZE,
		mapped_length / one_MB);
/* try locking pages from all regions into working set (just for fun) */
    lock_all_regions();
/* describe the section as an array of signed quadword integers (time stamps) */
    n64 = mapped_length / sizeof(int64);
    p64 = mapped_va;
/* increment the mapping count in the lowest quadword */
    p64[0]++;
    i64 = p64[0];
    printf("This program has now mapped this section %Ld times.\n", i64);
/* clear any remaining section memory */
    clear_length = mapped_length - (sizeof(int64) * i64);
    if (clear_length < 0x100000000uL)
    {
      printf("Clearing %Lu section bytes...\n", clear_length);
      lib$init_timer(0);
      pcc_beg.all = __RPCC();
      _memset64(&p64[i64], 0, clear_length);
      pcc_end.all = __RPCC();
      lib$show_timer(0);
      show_pcc(pcc_beg, pcc_end);
    }
/* write some SYSTIME time stamps,
    printf("Writing %Lu quadword SYSTIME stamps...\n", n64-i64);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    for (i64 = p64[0]; i64 < n64; i64++) p64[i64] = EXE$GQ_SYSTIME;
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
/* look for and list changes in the time stamp values */
    nclkint = 0uL;
    i64prv = i64dsp = 1;
    for (i64 = 2; i64 < n64; i64++)
    {
      d64 = p64[i64] - p64[i64prv];
      if (d64)
      {
	kclkint = d64 / systime_units_per_clock_int;
	if (((kclkint < 0) ? -kclkint : kclkint) < 50)
	{
	  nclkint += kclkint;
	}
	else
	{
	  if (nclkint)
	  {
	    printf("(%Lu clock interrupts found in %Ld time stamps)\n",
		nclkint, i64-i64dsp);
	    nclkint = 0uL;
	  }
	  printf(
		"p64[%5Ld]: %+Ld.%07Lu seconds (%+Ld clock interrupts).\n",
		i64, d64 / systime_units_per_second,
		((d64 < 0L) ? -d64 : d64) % systime_units_per_second, kclkint);
	  i64dsp = i64;
	}
	i64prv = i64;
      }
    }
    if (nclkint)
    {
      printf("(%Lu clock interrupts found in %Ld time stamps)\n",
		nclkint, n64-i64dsp);
      nclkint = 0;
    }
/*
 * Delete the region (and any address space within it),  just to show
 * that it can be done.  Image rundown would have done this anyway.
 */
    printf("Trying to delete region ID %Lu...\n", region_id);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$delete_region_64(
		&region_id,			/* region_id_64		*/
		0,				/* acmode		*/
		&deleted_va,			/* return_va_64		*/
		&deleted_length);		/* return_length_64	*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to delete region ID %Lu.\n", region_id);
      return status | STS$M_INHIB_MSG;
    }
    printf("Deleted region ID %Lu.\n", region_id);
    printf(" Deleted VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		deleted_va,
		deleted_length,
		deleted_length / MMG$GQ_PAGE_SIZE,
		deleted_length / one_MB);
  }
/* section size is unspecified or zero; delete named system global section */
  else
  {
    printf("Trying to delete section \"%s\"...\n", gs_name.dsc$a_pointer);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$dgblsc(SEC$M_SYSGBL, &gs_name, 0);
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to delete system global section \"%s\".\n",
	gs_name.dsc$a_pointer);
      return status | STS$M_INHIB_MSG;
    }
    printf("Deleted system global section \"%s\".\n", gs_name.dsc$a_pointer);
  }
  return status;
}
/*
 * The sequence of calls to (1) sys$create_gdzro, (2) sys$create_region_64,
 * (3) sys$mgblsc_64 (which was used above) could have been replaced by a
 * sequence of calls to (1) sys$create_region_64, (2) sys$crmpsc_gdzro_64.
 * The single sys$crmpsc_gdzro_64 service combines the actions of both the
 * sys$create_gdzro and sys$mgblsc_64 services.  The call would have looked
 * something like the following:
 */
/*
    mapped_va = 0;
    mapped_length = 0uL;
    reserved_length = 0uL;
    status = sys$crmpsc_gdzro_64(
		&gs_name,
		0uL,
		0,
		nbytes,
		&region_id,
		0uL,
		0,
		create_gdzro_flags | mgblsc_flags,
		&mapped_va,
		&mapped_length,
		0uL,
		nbytes,
		&reserved_length);
 */
/*
 * The sys$deltva_64 service could have been used to unmap all or part
 * of the address space mapped to the section.  The call would have
 * looked something like the following:
 */
/*
    status = sys$deltva_64(
		&region_id,
		mapped_va,
		mapped_length,
		0,
		&unmapped_va,
		&unmapped_length);
 */
237.4further feedback welcomedEVMS::GRANTMon Feb 24 1997 10:1221
We hope 'better late than never' applies here. We had been trying to get this
work into the development schedule for a number of years.

You might be interested in knowing that we recently did testing on both a 16GB
system and a 28GB system. In both cases nearly all the available memory was
defined as a section for a database cache. We've pushed the limits as much as
we could on our own and we also worked with a major database vendor during
design, development, and testing. 

What we did for 7.1 may not be as general and some might like; it was directed
at a very specific set of requests collected over time. If you find
shortcomings, don't hesitate to let us know.

If it is not confidential, we'd be interested in knowing how your customer puts
memory resident sections to use.


Clair Grant
VMS Exec Group Project Leader

    
237.5"real-time" applicationCUJO::SAMPSONMon Feb 24 1997 22:035
	This particular customer uses global sections for a "real-time"
application.  Some of the sections are used to share large amounts of
application data, and some, I believe, are used to coordinate the use of
DECmessageQ, or whatever it is called once it is sold off.  Sounds kind
of vague, but those are the highlights.