|
HP OpenVMS systems documentation |
Previous | Contents | Index |
User-defined logical name tables can be created with either an explicit limited quota or no quota limit.
The presence of user-defined logical name table quotas eliminates the
need for a privilege (for example, SYSNAM or GRPNAM) to control
consumption of paged pool when you create logical names in a shareable
table.
34.8 Interprocess Communication
Although logical names typically represent device and file names, shareable logical names can also be used to pass information among cooperating processes. When a process creates a shareable logical name, it can store up to 255 bytes of information in each equivalence name. The processes can agree to any arbitrary form for the information. Cooperating processes can translate the shareable name to retrieve the data in its eqivalence names.
The operating system ensures one process cannot change a logical name at the same time another process is either translating the name or trying to change it. In other words, the synchronization provided by OpenVMS allows multiple concurrent readers or a single writer to access shared logical names that are not clusterwide.
Each instance of OpenVMS has its own shareable logical name database. When a process creates a new shareable logical name, that name can be translated immediately by any other process in the system with access to the containing table.
On an OpenVMS cluster, each node has its own shareable logical name database. In addition, the clusterwide tables and their names are replicated on each node of the cluster. Cluster communication and replication time can delay the time when a clusterwide logical name is visible on other cluster nodes. For increased performance, the default synchronization provided by OpenVMS for clusterwide logical names allows a single writer to access shared logical names, but it does not block concurrent readers.
Synchronization provided by OpenVMS may therefore be insufficient for a given application. In particular, the following circumstances require that an application provide additional synchronization:
If you have an application where a logical name translator must be certain of getting the most recent definition of a clusterwide logical name, you should specify in the application the LNM$M_INTERLOCKED attribute in the attr argument. Use of this attribute synchronizes the translation with any pending changes to clusterwide names and ensures that the translation retrieves the most recent definition of the name. Use of this attribute to translate a local name adds a small amount of overhead but is otherwise harmless.
No logical name service provides an atomic modify of a logical name, clusterwide or local; it is thus not possible in one system service call to read the information in a logical name's equivalence names and recreate it with updated information. This means that if you have an interprocess application in which multiple processes modify a logical name, you must provide additional synchronization to create a critical section containing the SYS$TRNLNM and SYS$CRELNM calls. For example, your application could take the following steps:
The operating system uses special conventions for assigning logical names to equivalence names and for translating logical names. These conventions are generally transparent to user programs; however, you should be aware of the programming considerations involved.
If a logical name string presented in I/O services is preceded by an underscore (_), the I/O services bypass logical name translation, drop the underscore, and treat the logical name as a physical device name.
When you log in, the system creates default logical name table entries for process-permanent files. The equivalence names for these entries (for example, SYS$INPUT and SYS$OUTPUT) are preceded by a 4-byte header that contains the following information:
Byte | Contents |
---|---|
0 | ^X1B (escape character) |
1 | ^X00 |
2--3 | OpenVMS RMS Internal File Identifier (IFI) |
This header is followed by the equivalence name string. If any of your program applications must translate system-assigned logical names, you must prepare the program both to check for the existence of this header and to use only the desired part of the equivalence string. The following program demonstrates how to do this:
#include <stdio.h> #include <lnmdef.h> #include <ssdef.h> #include <descrip.h> #include <ctype.h> #include <string.h> #define HEADER 4 /* Define an item descriptor */ struct { unsigned short buflen, item_code; void *bufaddr; void *retlenaddr; unsigned int terminator; }item_lst; main() { unsigned int status,len,i; char resstring[LNM$C_NAMLENGTH]; $DESCRIPTOR(tabdesc,"LNM$FILE_DEV"); $DESCRIPTOR(logdesc,"SYS$OUTPUT"); item_lst.buflen = LNM$C_NAMLENGTH; item_lst.item_code = LNM$_STRING; item_lst.bufaddr = resstring; item_lst.retlenaddr = 0; item_lst.terminator = 0; /* Translate the logical name */ status = SYS$TRNLNM( 0, /* attr - attributes of the logical name */ &tabdesc, /* tabnam - logical name table */ &logdesc, /* lognam - logical name */ 0, /* acmode - accessm mode */ &item_lst); /* itmlst - item list */ if((status & 1) != 1) LIB$SIGNAL( status ); /* Examine 4-byte header Is first character an escape char? If so, dump the header */ if( resstring[0] == 0x1B) { printf("\nDumping the header...\n"); for(i = 0; i < HEADER; i++) printf(" Byte %d: %X\n",i,resstring[i]); printf("\nEquivalence string: %s\n",(resstring + HEADER)); } else printf("Header not found\n"); } |
The following sections describe by programming examples how to use
SYS$CRELNM, SYS$CRELNT, SYS$DELLNM, and SYS$TRNLNM system services.
34.10.1 Using SYS$CRELNM to Create a Logical Name
To perform an assignment in a program, you must provide character-string descriptors for the name strings, select the table to contain the logical name, and use the SYS$CRELNM system service as shown in the following example. In either case, the result is the same: the logical name DISK is equated to the physical device name DUA2 in table LNM$JOB.
#include <stdio.h> #include <lnmdef.h> #include <descrip.h> #include <string.h> #include <ssdef.h> /* Define an item descriptor */ struct itm { unsigned short buflen, item_code; void *bufaddr; void *retlenaddr; }; /* Declare an item list */ struct { struct itm items2]; unsigned int terminator; }itm_lst; main() { static char eqvnam[] = "DUA2:"; unsigned int status, lnmattr; $DESCRIPTOR(logdesc,"DISK"); $DESCRIPTOR(tabdesc,"LNM$JOB"); lnmattr = LNM$M_TERMINAL; /* Initialize the item list */ itm_lst.items[0].buflen = 4; itm_lst.items[0].item_code = LNM$_ATTRIBUTES; itm_lst.items[0].bufaddr = &lnmattr; itm_lst.items[0].retlenaddr = 0; itm_lst.items[1].buflen = strlen(eqvnam); itm_lst.items[1].item_code = LNM$_STRING; itm_lst.items[1].bufaddr = eqvnam; itm_lst.items[1].retlenaddr = 0; itm_lst.terminator = 0; /* Create the logical name */ status = SYS$CRELNM(0, /* attr - attributes */ &tabdesc, /* tabnam - logical table name */ &logdesc, /* lognam - logical name */ 0, /* acmode - access mode 0 means use the */ /* access mode of the caller=user mode */ &itm_lst); /* itmlst - item list */ if((status & 1) != 1) LIB$SIGNAL(status); } |
Note that the translation attribute is specified as terminal. This attribute indicates that iterative translation of the logical name DISK ends when the equivalence string DUA2 is returned. In addition, because the acmode argument was not specified, the access mode of the logical name DISK is the access mode from which the image requested the SYS$CRELNM service.
The following example shows how a process-private logical name with multiple equivalence names can be created in user mode by an image:
#include <stdio.h> #include <lnmdef.h> #include <ssdef.h> #include <descrip.h> /* Define an item descriptor */ struct lst { unsigned short buflen, item_code; void *bufaddr; void *retlenaddr; }; /* Declare an item list */ struct { struct lst items[2]; unsigned int terminator; }item_lst; /* Equivalence name strings */ static char eqvnam1[] = "XYZ"; static char eqvnam2[] = "DEF"; main() { unsigned int status; $DESCRIPTOR(logdesc,"ABC"); $DESCRIPTOR(tabdesc,"LNM$PROCESS"); item_lst.items[0].buflen = strlen(eqvnam1); item_lst.items[0].item_code = LNM$_STRING; item_lst.items[0].bufaddr = eqvnam1; item_lst.items[0].retlenaddr = 0; item_lst.items[1].buflen = strlen(eqvnam2); item_lst.items[1].item_code = LNM$_STRING; item_lst.items[1].bufaddr = eqvnam2; item_lst.items[1].retlenaddr = 0; item_lst.terminator = 0; /* Create a logical name */ status = SYS$CRELNM( 0, /* attr - attributes of logical name */ &tabdesc, /* tabnam - name of logical name table */ &logdesc, /* lognam - name of logical name */ 0, /* acmode - access mode 0 means use the */ /* access mode of the caller=user mode */ &item_lst); /* itm_lst - item list */ if((status & 1) != 1) LIB$SIGNAL(status); } |
In the preceding example, logical name ABC was created and represents a search list with two equivalence strings, XYZ and DEF. Each time the LNM$_STRING item code of the itmlst argument is invoked, an index value is assigned to the next equivalence string. The newly created logical name and its equivalence string are contained in the process logical name table LNM$PROCESS_TABLE.
The following example illustrates the creation of a logical name in supervisor mode through DCL:
$ DEFINE/SUPERVISOR_MODE/TABLE=LNM$PROCESS ABC XYZ,DEF |
In the preceeding example, supervisor mode and /TABLE=LNM$PROCESS are
the defaults (default mode and default table) for the DEFINE command.
34.10.2 Using SYS$CRELNT to Create Logical Name Tables
The Create Logical Name Table (SYS$CRELNT) system service creates logical name tables. Logical name tables can be created in any access mode depending on the privileges of the calling process. A user-specified logical name that identifies a process-private created logical name table is stored in the process directory table LNM$PROCESS_DIRECTORY. The name of a shareable table is stored in the system directory table LNM$SYSTEM_DIRECTORY.
The following example illustrates a call to the SYS$CRELNT system service:
#include <stdio.h> #include <ssdef.h> #include <lnmdef.h> #include <descrip.h> main() { unsigned int status, tab_attr=LNM$M_CONFINE, tab_quota=5000; $DESCRIPTOR(tabdesc,"LOG_TABLE"); $DESCRIPTOR(pardesc,"LNM$PROCESS_TABLE"); /* Create the logical name table */ status = SYS$CRELNT(&tab_attr, /* attr - table attributes */ 0, /* resnam - logical table name */ 0, /* reslen - length of table name */ &tab_quota, /* quota - max no. of bytes allocated */ /* for names in this table */ 0, /* promsk - protection mask */ &tabdesc, /* tabnam - name of new table */ &pardesc, /* partab - name of parent table */ 0); /* acmode - access mode */ if((status & 1) != 1) { LIB$SIGNAL(status); } |
In this example, a user-defined table LOG_TABLE is created with an
explicit quota of 5000 bytes. The name of the newly created table is an
entry in the process-private directory LNM$PROCESS_DIRECTORY. The quota
of 5000 bytes is deducted from the parent table LNM$PROCESS_TABLE.
Because the CONFINE attribute is associated with the logical name
table, the table cannot be copied from the process to its spawned
processes.
34.10.3 Using SYS$DELLNM to Delete Logical Names
The Delete Logical Name (SYS$DELLNM) system service deletes entries from a logical name table. When you write a call to the SYS$DELLNM system service, you can specify a single logical name to delete, or you can specify that you want to delete all logical names from a particular table. For example, the following call deletes the process logical name TERMINAL from the job logical name table:
#include <stdio.h> #include <lnmdef.h> #include <ssdef.h> #include <descrip.h> main() { unsigned int status; $DESCRIPTOR(logdesc,"DISK"); $DESCRIPTOR(tabdesc,"LNM$JOB"); /* Delete the logical name */ status = SYS$DELLNM(&tabdesc, /* tabnam - logical table name */ &logdesc, /* lognam - logical name */ 0); /* acmode - access mode */ if ((status & 1) != 1) LIB$SIGNAL(status); } |
For information about access modes and the deletion of logical names,
see Chapter 20 and Appendix E.
34.10.4 Using SYS$TRNLNM to Translate Logical Names
The Translate Logical Name (SYS$TRNLNM) system service translates a logical name to its equivalence string. In addition, SYS$TRNLNM returns information about the logical name and equivalence string.
The system service call to SYS$TRNLNM specifies the tables to search for the logical name. The tabnam argument can be either the name of a logical name table or a logical name that translates to a list of one or more logical name tables.
Because logical names can have many equivalence strings, you can specify which equivalence string you want to receive.
A number of system services that require a device name accept a logical name and translate the logical name iteratively until a physical device name is found (or until the system default number of logical name translations has been performed, typically 10). These services implicitly use the logical name table name LNM$FILE_DEV. For more information about LNM$FILE_DEV, refer to Section 34.1.4.
The following system services perform iterative logical name translation automatically:
In many cases, however, a program must perform the logical name translation to obtain the equivalence name for a logical name outside the context of a device name or file specification. In that case, you must supply the name of the table or tables to be searched. The SYS$TRNLNM system service searches the user-specified logical name tables for a specified logical name and returns the equivalence name. In addition, SYS$TRNLNM returns attributes that are specified optionally for the logical name and equivalence string.
The following example shows a call to the SYS$TRNLNM system service to translate the logical name ABC:
#include <stdio.h> #include <lnmdef.h> #include <descrip.h> #include <ssdef.h> /* Define an item descriptor */ struct itm { unsigned short buflen, item_code; void *bufaddr; void *retlenaddr; }; /* Declare an item list */ struct { struct itm items[2]; unsigned int terminator; }trnlst; main() { char eqvbuf1[LNM$C_NAMLENGTH], eqvbuf2[LNM$C_NAMLENGTH]; unsigned int status, trnattr=LNM$M_CASE_BLIND; unsigned int eqvdesc1, eqvdesc2; $DESCRIPTOR(logdesc,"ABC"); $DESCRIPTOR(tabdesc,"LNM$FILE_DEV"); /* Assign values to the item list */ trnlst.items[0].buflen = LNM$C_NAMLENGTH; trnlst.items[0].item_code = LNM$_STRING; trnlst.items[0].bufaddr = eqvbuf1; trnlst.items[0].retlenaddr = &eqvdesc1; trnlst.items[1].buflen = LNM$C_NAMLENGTH; trnlst.items[1].item_code = LNM$_STRING; trnlst.items[1].bufaddr = eqvbuf2; trnlst.items[1].retlenaddr = &eqvdesc2; trnlst.terminator = 0; /* Translate the logical name */ status = SYS$TRNLNM(&trnattr, /* attr - attributes */ &tabdesc, /* tabnam - table name */ &logdesc, /* lognam - logical name */ 0, /* acmode - access mode */ &trnlst); /* itmlst - item list */ if((status & 1) != 1) LIB$SIGNAL(status); } |
This call to the SYS$TRNLNM system service results in the translation of the logical name ABC. In addition, LNM$FILE_DEV is specified in the tabnam argument as the search list that SYS$TRNLNM is to use to find the logical name ABC. The logical name ABC was assigned two equivalence strings. The LNM$_STRING item code in the itmlst argument directs SYS$TRNLNM to look for an equivalence string at the current index value. Note that the LNM$_STRING item code is invoked twice. The equivalence strings are placed in the two output buffers, EQVBUF1 and EQVBUF2, described by TRNLIST.
The attribute LNM$M_CASE_BLIND governs the translation process. The SYS$TRNLNM system service searches for the equivalence strings without regard to uppercase or lowercase letters. The SYS$TRNLNM system service matches any of the following character strings: ABC, aBC, AbC, abc, and so forth.
The output equivalence name string length is written into the first
word of the character string descriptor. This descriptor can then be
used as input to another system service.
34.10.5 Using SYS$CRELNM, SYS$TRNLNM, and SYS$DELLNM in a Program Example
In the following example, the Fortran program CALC.FOR creates a spawned subprocess to perform an iterative calculation. The logical name REP_NUMBER specifies the number of times that REPEAT should perform the calculation. Because the two processes are part of the same job, REP_NUMBER is placed in the job logical name table LNM$JOB. (Note that logical name table names are case sensitive. Specifically, LNM$JOB is a system-defined logical name that refers to the job logical name table; lnm$job is not.)
PROGRAM CALC ! Status variable and system routines INCLUDE '($LNMDEF)' INCLUDE '($SYSSRVNAM)' INTEGER*4 STATUS INTEGER*2 NAME_LEN, 2 NAME_CODE INTEGER*4 NAME_ADDR, 2 RET_ADDR /0/, 2 END_LIST /0/ COMMON /LIST/ NAME_LEN, 2 NAME_CODE, 2 NAME_ADDR, 2 RET_ADDR, 2 END_LIST CHARACTER*3 REPETITIONS_STR INTEGER REPETITIONS EXTERNAL CLI$M_NOLOGNAM, 2 CLI$M_NOCLISYM, 2 CLI$M_NOKEYPAD, 2 CLI$M_NOWAIT NAME_LEN = 3 NAME_CODE = (LNM$_STRING) NAME_ADDR = %LOC(REPETITIONS_STR) STATUS = SYS$CRELNM (,'LNM$JOB','REP_NUMBER',,NAME_LEN) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) MASK = %LOC (CLI$M_NOLOGNAM) .OR. 2 %LOC (CLI$M_NOCLISYM) .OR. 2 %LOC (CLI$M_NOKEYPAD) .OR. 2 %LOC (CLI$M_NOWAIT) STATUS = LIB$GET_EF (FLAG) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) STATUS = LIB$SPAWN ('RUN REPEAT',,,MASK,,,,FLAG) IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END PROGRAM REPEAT INTEGER STATUS, 2 SYS$TRNLNM,SYS$DELLNM INTEGER*4 REITERATE, 2 REPEAT_STR_LEN CHARACTER*3 REPEAT_STR ! Item list for SYS$TRNLNM INTEGER*2 NAME_LEN, 2 NAME_CODE INTEGER*4 NAME_ADDR, 2 RET_ADDR, 2 END_LIST /0/ COMMON /LIST/ NAME_LEN, 2 NAME_CODE, 2 NAME_ADDR, 2 RET_ADDR, 2 END_LIST NAME_LEN = 3 NAME_CODE = (LNM$_STRING) NAME_ADDR = %LOC(REPEAT_STR) RET_ADDR = %LOC(REPEAT_STR_LEN) STATUS = SYS$TRNLNM (, 2 'LNM$JOB', ! Logical name table 2 'REP_NUMBER',, ! Logical name 2 NAME_LEN) ! List requesting equivalence string IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) READ (UNIT = REPEAT_STR, 2 FMT = '(I3)') REITERATE DO I = 1, REITERATE END DO STATUS = SYS$DELLNM ('LNM$JOB', ! Logical name table 2 'REP_NUMBER',) ! Logical name IF (.NOT. STATUS) CALL LIB$SIGNAL (%VAL(STATUS)) END |
Previous | Next | Contents | Index |