Examples
Example 9. Data In Virtual
The data in virtual services provides analogous functionality to an LUW memory file. When used with a VSAM linear data set, data persistence can be achieved. DIV services processes application data in 4096-byte (4K-byte) units on 4K-byte boundaries called blocks. The application data resides in what is called a data-in-virtual object. The DIV is a contiguous stream of data, with no record boundaries. The data object can be either a VSAM linear data set or a non-shared standard hiperspace. Using a VSAM LDS provides persistence, whereas a hyperspace only provides temporary storage. For large data sets with random access to the data, a DIV may provide a good data access mechanism.
This routine was developed to create a DIV using Metal-C. The routine takes three input parameters, ddname, entry size and number of entries to create. It then creates and saves the DIV in the associated VSAM LDS.
DIV Services
The DIV services invoked are:- IDENTIFY - Identifies routine as a user of a data-in-virtual object.
- ACCESS - Provides access to the data-in-virtual object.
- MAP - Makes the data-in-virtual object addressable through a virtual window.
- SAVE - Saves changed data that is in the window.
- UNMAP -Eliminates the correspondence between the data-in-virtual object and the virtual window.
- UNACCESS - Eliminates the routines access to the data-in-virtual object.
- UNIDENTIFY -Ends the routines use of the data-in-virtual object.
Execution JCL
The execution JCL would look something like this:
//TESTQUE EXEC PGM=DIV, // PARM='ENTRIES=1000,DDNAME=TESTQUE1,LENGTH=80' //STEPLIB DD DSN=DEVEL.XXXXX.LOAD,DISP=SHR //TESTQUE1 DD DSN=DEVEL.TESTQUE,DISP=SHR <== VSAM LDS //SYSUDUMP DD SYSOUT=* //SYSPRINT DD SYSOUT=*
Where:
- ENTRIES - is the number of DIV entries to allocate space for
- LENGTH - is the length of each DIV entry
- DDDNAME - The ddname of the associated VSAM LDS
C Source
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ihadcb.h"
#ifndef __MVS__
#include <stdbool.h>
#endif
#ifdef __MVS__
#define __CSE_CURRENT_VERSION __CSE_VERSION_1
#define __CSE_VERSION_1 1
#include "env.h"
__csysenv_t __cinit(struct __csysenv_s * csysenv);
void __cterm(__csysenv_t csysenvtkn);
#endif
#ifdef __MVS__
#pragma export(init)
#pragma export(open)
#pragma export(put)
#pragma export(close)
#pragma export(term)
#endif
#define true 1
#define false 0
#define pageSize 4096
#ifdef __MVS__
#pragma insert_asm("MODELDCB DCB DDNAME=MODELDCB,MACRF=PM,DSORG=PS")
#endif
struct ddname
{
char length;
char name[9];
} ;
struct options
{
int entries;
int length;
char ddname[9];
} ;
struct storage
{
char dcb[96];
} ;
struct dcb
{
char ddname[8];
int lrecl;
int blksize;
void *storage;
int size;
void *currentRecord;
void *token;
__csysenv_t _envtkn;
} ;
void replace(char *name)
{
int i;
int length;
length = strlen(name) + 1;
for (i = 0; i < length; i++)
{
if (name[i] == 0x00)
{
name[i] = ' ';
}
}
}
extern int init(struct dcb *_dcb)
{
int returnCode;
returnCode = 0;
#ifdef __MVS__
struct __csysenv_s _sysenv;
/* The __cinit() function establishes a Metal C
environment based on the characteristics in the input
csysenv structure.*/
// Initialize the csysenv structure.
memset(&_sysenv, 0x0, sizeof(_sysenv));
_sysenv.__cseversion = __CSE_VERSION_1;
// Set heap initial and increment sizes.
_sysenv.__cseheap31initsize = 65536;
_sysenv.__cseheap31incrsize = 8192;
_sysenv.__cseheap64initsize = 20;
_sysenv.__cseheap64incrsize = 1;
// Create a Metal C environment. */
_dcb->_envtkn = __cinit(&_sysenv);
#endif
#ifdef __MVS__
__asm(" ST 15,%0 "
: "=m"(_dcb->token)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int term(struct dcb *_dcb)
{
int returnCode;
int storageSize;
void *storagePtr;
returnCode = 0;
storageSize = _dcb->size;
storagePtr = _dcb->storage;
#ifdef __MVS__
__asm( (" STORAGE RELEASE"
",LENGTH=(%0)"
",ADDR=(%1)")
:
: "r"(storageSize), "r"(storagePtr)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
#ifdef __MVS__
__cterm((__csysenv_t) _dcb->_envtkn);
#endif
return returnCode;
}
extern int open(struct dcb *_dcb)
{
int storageSize;
char wrkarea[256];
int returnCode;
struct storage *_storage;
struct ihadcb *_ihadcb;
returnCode = 0;
storageSize = 96;
#ifdef __MVS__
__asm( (" STORAGE OBTAIN,LOC=BELOW"
",LENGTH=(%1)"
",ADDR=%0")
: "=m"(_dcb->storage)
: "r"(storageSize)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(_dcb->size)
:
: "r0", "r1", "r14", "r15");
#endif
_storage = _dcb->storage;
memset(wrkarea, 0, sizeof(wrkarea));
wrkarea[0] = 0x80;
#ifdef __MVS__
__asm(" MVC 0(96,%0),MODELDCB"
:
: "r"(_storage->dcb)
: "r0", "r1", "r14", "r15");
#endif
_ihadcb = (void*) _storage->dcb;
memcpy(_ihadcb->dcbddnam, _dcb->ddname, 8);
_ihadcb->dcblrecl = _dcb->lrecl;
_ihadcb->dcbblksi = _dcb->blksize;
#ifdef __MVS__
__asm( (" OPEN (%1,(OUTPUT)),MODE=31,MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(_storage->dcb)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int put(struct dcb *_dcb)
{
char wrkarea[256];
int returnCode;
int i;
void *outputPtr;
struct storage *_storage;
returnCode = 0;
_storage = _dcb->storage;
replace(_dcb->currentRecord);
outputPtr = _dcb->currentRecord;
#ifdef __MVS__
__asm( (" PUT (%0),(%1)")
:
: "r"(_storage->dcb), "r"(outputPtr)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int close(struct dcb *_dcb)
{
int storageSize;
char wrkarea[256];
int returnCode;
struct storage *_storage;
_storage = _dcb->storage;
memset(wrkarea, 0, sizeof(wrkarea));
wrkarea[0] = 0x80;
#ifdef __MVS__
__asm( (" CLOSE (%1),MODE=31,MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(_storage->dcb)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
void programDump(int returnCode)
{
//PROGRAM TERMINATION - ABNORMAL
#ifdef __MVS__
__asm( (" ABEND (%0),DUMP")
:
: "r"(returnCode)
: "r0", "r1", "r14", "r15"); // clobber list
#endif
}
_Bool numeric (char* text)
{
int i;
_Bool result;
result = true;
for (i = 0; i < strlen(text); i++)
{
if (text[i] >= '0' && text[i] <= '9')
{
result = true;
}
else
{
return false;
}
}
return result;
}
/* Options:
slots=####,
length=####,
ddname=cccccccc
*/
int getOptions(struct options *_options, int number, char *options)
{
char optionsString[100];
int i;
int j;
char delim[4] = "=, ";
char *token;
char *saveptr;
memset(optionsString, 0, sizeof(optionsString));
strcpy(optionsString, (char *) options);
#ifdef __MVS__
struct __csysenv_s _sysenv;
__csysenv_t _envtkn;
/* The __cinit() function establishes a Metal C
environment based on the characteristics in the input
csysenv structure.*/
// Initialize the csysenv structure.
memset(&_sysenv, 0x0, sizeof(_sysenv));
_sysenv.__cseversion = __CSE_VERSION_1;
// Set heap initial and increment sizes.
_sysenv.__cseheap31initsize = 65536;
_sysenv.__cseheap31incrsize = 8192;
_sysenv.__cseheap64initsize = 20;
_sysenv.__cseheap64incrsize = 1;
// Create a Metal C environment. */
_envtkn = __cinit(&_sysenv);
#endif
for (j = 1; j < 10; j++)
{
if (j == 1)
{
token = strtok_r(optionsString, delim, &saveptr);
}
if (token == NULL)
{
break;
}
if (strcmp(token, "ENTRIES") == 0)
{
token = strtok_r(NULL, delim, &saveptr);
if (numeric(token))
{
_options->entries = atoi((const char*) token);
}
else
{
// Error
return -1;
}
}
else if (strcmp(token, "LENGTH") == 0)
{
token = strtok_r(NULL, delim, &saveptr);
if (numeric(token))
{
_options->length = atoi((const char*) token);
}
else
{
// Error
return -1;
}
}
else if (strcmp(token, "DDNAME") == 0)
{
token = strtok_r(NULL, delim, &saveptr);
strcpy(_options->ddname, token);
}
else
{
// Error
return -1;
}
token = strtok_r(NULL, delim, &saveptr);
}
#ifdef __MVS__
__cterm((__csysenv_t) _envtkn);
#endif
return 0;
}
int main(int argc, char** argv)
{
char token[8];
char wrkarea[256];
int i;
int numberOfEntries;
int numberOfPages;
int entryLength;
int rc;
int reasonCode;
int returnCode;
int size;
int storageSize;
int totalSpace;
char *queuePtr;
char *tempPtr;
struct ddname _ddname;
struct options _options;
struct dcb _dcb;
char message[133];
rc = 0;
memset(&_dcb, 0, sizeof(struct dcb));
memcpy(_dcb.ddname, "SYSPRINT", 8);
_dcb.lrecl = 133;
_dcb.blksize = 1330;
rc = init(&_dcb);
rc = open(&_dcb);
memset(&message, ' ', sizeof(message));
strcpy(message, "DIV Program Start");
_dcb.currentRecord = &message;
rc = put(&_dcb);
numberOfPages = 0;
rc = 0;
reasonCode = 0;
returnCode = 0;
size = 0;
storageSize = 0;
entryLength = 0;
memset(&_options, 0, sizeof(struct options));
if (argc > 1)
{
rc = getOptions(&_options, argc, argv[1]);
}
else
{
strcpy(message, "No Program Options Supplied");
_dcb.currentRecord = &message;
rc = put(&_dcb);
return(16);
}
if (_options.entries == 0)
{
memset(&message, ' ', sizeof(message));
strcpy(message, "Number of Entries = 0");
_dcb.currentRecord = &message;
rc = put(&_dcb);
return(16);
}
if (_options.length == 0)
{
memset(&message, ' ', sizeof(message));
strcpy(message, "Entry Length = 0");
_dcb.currentRecord = &message;
rc = put(&_dcb);
return(16);
}
if (strlen(_options.ddname) == 0)
{
memset(&message, ' ', sizeof(message));
strcpy(message, "No DDNAME supplied for VSAM LDS");
_dcb.currentRecord = &message;
rc = put(&_dcb);
return(16);
}
numberOfEntries = _options.entries;
entryLength = _options.length;
totalSpace = numberOfEntries * entryLength;
numberOfPages = (totalSpace / pageSize) + 1;
storageSize = numberOfPages * pageSize;
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DDNAME: %s. Number of Entries: %i Entry Length: %i Total Space: %i",
_options.ddname, numberOfEntries, entryLength, totalSpace);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "Number of Pages: %i Total Allocated Space: %i",
numberOfPages, storageSize);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&token, 0, 8);
memset(&_ddname, 0, sizeof(struct ddname));
memcpy(&_ddname.name, _options.ddname , 8);
replace((char*) &_ddname.name);
_ddname.length = 8;
#ifdef __MVS__
__asm( (" STORAGE OBTAIN,LOC=(31,64),BNDRY=PAGE"
",LENGTH=(%1)"
",ADDR=%0")
: "=m"(queuePtr)
: "r"(storageSize)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(queuePtr, 0, storageSize);
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV IDENTIFY,TYPE=DA,ID=%0"
",DDNAME=%2"
",MF=(E,%1)")
: "=m"(token[0]), "=m"(wrkarea[0])
: "m"(_ddname)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV IDENTIFY RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV ACCESS,ID=%2"
",MODE=UPDATE,SIZE=%0"
",MF=(E,%1)")
: "=m"(size), "=m"(wrkarea[0])
: "m"(token)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV ACCESS RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV MAP,ID=%1"
",AREA=%2"
",SPAN=%3"
",MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(token), "m"(queuePtr), "m"(numberOfPages)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV MAP RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
tempPtr = queuePtr;
for (i = 0; i < storageSize; i++)
{
memset(tempPtr, 0xff, 1);
tempPtr++;
}
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV SAVE,ID=%1"
",SIZE=%2"
",SPAN=%3"
",MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(token), "m"(numberOfPages), "m"(numberOfPages)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV SAVE RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV UNMAP,ID=%1"
",AREA=%2"
",MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(token), "m"(queuePtr)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV UNMAP RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
#ifdef __MVS__
__asm( (" STORAGE RELEASE"
",LENGTH=(%0)"
",ADDR=(%1)")
:
: "r"(storageSize), "r"(queuePtr)
: "r0", "r1", "r14", "r15"); // clobber list
#endif
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV UNACCESS,ID=%1"
",MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(token)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV UNACCESS RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
memset(&wrkarea, 0, 256);
#ifdef __MVS__
__asm( (" DIV UNIDENTIFY,ID=%1"
",MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(token)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(reasonCode)
:
: "r0", "r1", "r14", "r15");
#endif
memset(&message, ' ', sizeof(message));
sprintf((char*) &message, "DIV UNIDENTIFY RC: %i", returnCode);
_dcb.currentRecord = &message;
rc = put(&_dcb);
rc = close(&_dcb);
rc = term(&_dcb);
return (returnCode);
}