.NONUMBER .LM 0 ^PY^- .PAGE SIZE 58,85 .LM 10 .RM 75 .NO FILL .NO JUSTIFY # .SKIP 5 ^IC0000^IS328^GThe RSX Multi-Tasker^IS204^IC1000^G .SKIP ^IC0000^IS328^GAugust, 1987^IS204^IC1000^G .SKIP .CENTER ##^IS144^G"It's Because They're the Same People"^IS204^G .SKIP .CENTER Fine Realtime Commentary Since 1975 .SKIP 6 .CENTER ^&Table of Contents\& .SKIP 2 .TAB STOPS 65 Food for Thought RSX-1 The Editor's Corner RSX-1 Contributions to the MT RSX-2 Answer to Last Month's Quiz RSX-3 Submitting Articles to the Multi-Tasker RSX-3 And That's The Way Things Are RSX-4 A Cheap Way To Monitor Task Status RSX-4 Erratum: Security of the RSX-11 Operating Systems RSX-12 The Hitchhiker's Guide to RSX, Part II RSX-13 .JUSTIFY .FILL .SKIP 15 .LM +5 .RM -5 Opinions expressed in the editorial section of the Multi-Tasker are those of the Editor. They do not represent the official position of the RSX SIG or that of DECUS leadership in general. .LM -5 .RM +5 .PAGE .COMMENT .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT Food for Thought .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT # .SKIP 7 .AUTOPARAGRAPH #######################^IC0000^IS328^GFood for Thought^IS204^IC1000^G .SKIP "DECtape II, TU58, is a low cost mass memory device offering random access on block-formatted, pocket-size cartridge media. DECtape II is ideal for small system mass storage, diagnostic loading, and software update distribution." .SKIP ^IS144^G(Any 11/44 or VAX 750 owner will tell you so ...)^IS204^G .SKIP 2 .INDENT 30 ^IS144^G- Digital Equipment Corporation^IS204^G .INDENT 30 ^IS144^G##PDP11 Peripherals Handbook^IS204^G .COMMENT .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT The Editor's Corner .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT .SKIP 9 ######################^IC0000^IS328^GThe Editor's Corner^IS204^IC1000^G .SKIP .CENTER Bruce R. Mitchell .SKIP Oh, my word, it's hot out here in Minnesota. It's so hot that the gophers aren't coming out until midnight, and then only for short sprints to the nearest corncrib. The carp have all packed up and left for parts south of here. Even the mosquitoes - the venerated Minnesota State Bird - are loath to leave their nice cool ponds. It's so hot out here ... but perhaps we'd better let sleeping dogs lie. We have more good information for you this month. For those of you who program in commercial control environments, check out the article on monitoring task status in multitask systems. And, of course, the serialization of the "Hitchhiker's Guide to RSX" continues. That pretty well fills up the 40 page quota for this issue. Which reminds me ... Haul out your fire extinguishers and check the Halon, my dear readership, because this month's editorial dragonflame is aimed at YOU. .TEST PAGE 5 .SKIP 2 .CENTER ----- Contributions to the MT ----- Your editor is pleased as can be that more contributions are arriving at the plush MT offices. I have a 40 page allocation each month, and few things please me more than filling those 40 pages - few, that is, other than asking for a bigger allocation. I do note, however, there are still some of you - yes, I must say it - some of you who haven't yet written an article for the Multi-Tasker. So maybe it's time again to blast away what appear to be common misconceptions about writing for this publication: .LM +3 .SKIP .INDENT -3 o##You do not have to be a genius or wizard to write an article. .SKIP .INDENT -3 o##Nobody laughs at articles submitted to this newsletter. .SKIP .INDENT -3 o##No article submitted is ever too elementary to publish. .SKIP .INDENT -3 o##No article submitted is ever too short to publish. .LM -3 .SKIP If you send me something for the Multi-Tasker, it will be printed in the first available issue, or I will see that it gets to the editor of the appropriate newsletter. Some of my correspondents complain that there aren't enough introductory, how-to, non-technical and general interest articles. There's a simple explanation: The people who submit now are interested in the technical side of RSX. They know the basics, so they don't want to write about them. They're solving today's problems so that you don't have to when you come to that point. If you want to see general interest articles, you have to submit them to me. That means you with the newsletter in your hands! If you have problems with Indirect or TKB, if you just discovered system-wide login command files, if you just found out how to bypass Files-11 protection by building a task /PR:0 - come on, ^IS144^Gwrite it up^IS204^G and ^IS144^Gsend it to me!^IS204^G## Great Ghu, what I wouldn't give to have an article on A-to-Z! I don't care how rough your writing is. I do my best to see that misspellings are corrected, dangling participles are cut off, and that code and text is vetted for correctness. But without an article to start with, I can't provide these services. Come on, you RSX rookies, write! I just love it when there's a name I don't know in a byline! Now, here's a challenge for you: I'm no longer going to ghostwrite articles. Over the past year, I've ghostwritten at least ten articles to fill space. No more. This is your newsletter, and from this point out, all articles will be ^IS144^Gyour^IS204^G articles. ^IS144^GYou^IS204^G now have 36 pages a month to fill. I'm just going to write editorials and glue things together. If nobody submits articles, all you will see is the editorial. ^IS144^GSo write, dammit!^IS204^G Now, smite the keyboards of your terminals! Don't put it off! Show them slimy VAX LUsers what real timers do! And be assured that our cause is righteous, our hearts are pure, and that if you send me something, future issues will have more than just ranting in this column. Thank you. .TEST PAGE 5 .SKIP 2 .CENTER ----- Answer to Last Month's Quiz ----- Embedded in the Editor's Corner. Congratulations from the Multi-Tasker staff, and the entire SIG's best wishes as well, Linda! .TEST PAGE 5 .SKIP 2 .CENTER ----- Submitting Articles to the Multi-Tasker ----- Please submit machine readable media. RK05, RK07, RL01/2, RM03, RX01/2, RX50, TK25, TK50, 9 channel 800/1600 BPI magtape or paper tape are OK. All RSX volume formats are acceptable. Anything I can't read I can get converted; don't let that stop you from submitting. The Editor can now Kermit articles in. The reverse is not true; the Multi-Tasker host is normally an isolate. If you want to submit via Kermit, call beforehand with phone number, login for the host machine and system uptimes. Submissions which aren't machine readable may take longer to get into print. The editor is lazy and types mass quantities only once a month when progress reports are due. If you preformat a submission in RUNOFF, please set page size 58,80; left margin 10; right margin 75; and, when changing margins, use incremental changes rather than absolute. The editor blesses you for the consideration. Send your articles and other submissions to the luxurious new Multi-Tasker offices c/o: .SKIP .NO FILL .NO JUSTIFY Bruce R. Mitchell 4-416 Alfred, St. Mary's Mayo Clinic Rochester, MN 55904 (507)#285-5753 .JUSTIFY .FILL .TEST PAGE 5 .SKIP 2 .CENTER ----- And That's The Way Things Are ----- _... this month in Pool Lowbegone, where the account file password encryption algorithm is strong, the FMS screens are good-looking, and the system manager's private TKB priority is above average. .COMMENT .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT A Cheap Way To Monitor Task Status .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT .TEST PAGE 15 .SKIP 6 ##########^IC0000^IS328^GA Cheap Way To Monitor Task Status^IS204^IC1000^G .SKIP .CENTER Vincent Moscaritolo .CENTER Datavox Corporation .CENTER 9 Pickering Way .CENTER Tancook Crescent, Suite 3A .CENTER Salem, MA###01970 .SKIP Ever hear a bank talk? RSX can be a very effective solution to the types of multi-tasking problems that occur in typical process control applications. I would like to describe one way in which I used some of the RSX parent-offspring tasking directives in an application called Banktalk. Banktalk is a voice response system which uses the DECtalk DTC03 voice terminals to provide home banking functions. A customer can access account data (eg. savings balance), rate information, and perform account transactions by calling from a Touch-Tone phone. A typical system can serve anywhere from one to 64 phone lines. Each line is managed by its own DECtalk and its own phone server task. Each server task runs under a unique terminal line. There is also a monitor task which tracks the status of each of the possible 64 server tasks. I needed a simple way for each server task to communicate its current status (i.e., is it speaking, waiting for a call, crashed, etc.) to the monitor task. .SKIP 2 .CENTER The Server Task Table I create a table in the monitor task that maintains information about each task. .SKIP 2 .NO FILL .NO JUSTIFY .TEST PAGE 7 ; Server Task Table Entry Format ; ; +------------------+ ; 00 | Status | 2 bytes ; +------------------+ ; 02 | Taskname in R50 | 4 bytes ; +------------------+ T$STAT = 0 ; Offset to task status T$ID = T$STAT + 2 ; Offset to task name T$LEN = T$ID + 4 ; Length of a table entry T$MAX = 64. ; Maximum entries in table TTABLE: .BLKB ; The Server Task table .JUSTIFY .FILL .SKIP 2 The table format is simple. Each server task maintains an entry in the table. The entry describes the task name and the current status. Given this information, what I need now is some way to fill in the status part of the corresponding task's entry. The problem is each task is in its own data space and can't access the server task table. .SKIP 2 .TEST PAGE 3 .CENTER Emitting Status RSX provides several ways to communicate between tasks; I wanted a cheap one. Fortunately, the CNCT$ and EMST$ directives provide us with one such way. The CNCT$ directive allows us to make a one way, one time connection between tasks. In fact, this connection is closed whenever the connected task either exits or emits status. The same mechanism that returns exit status can be invoked at any time. In the case of our server task, all it has to do is: .SKIP EMST$S####, _#status .SKIP If things are set up right, "status" can be picked up at the task that initiated the connection. Incidentally, "status" is preferably some number greater than 4, since 0 through 4 might be confused as one of RSX's reserved task exit status codes. .SKIP .NO FILL .NO JUSTIFY 0 EX$WAR Warning; task may have succeeded 1 EX$SUC Success 2 EX$ERR Error 4 EX$SEV Severe error; system may be compromised .JUSTIFY .FILL .SKIP I don't know what happened to status 3, but the above info should be in section 4.2 of the Exec reference. You might have noticed that in the above EMST$ example I did not specify any first parameter. This informs RSX to pass status to any task connected to this one. You can also pick a specific task to receive status by placing the task ID here. .SKIP 2 .TEST PAGE 3 .CENTER Connecting It Up So how does this status word get to the connector task? Let's walk through an example. Assume two tasks A and B. Task A executes a CNCT$ to task B. This causes RSX to create and queue an Offspring Control Block (OCB) to task B. Some time later, task B emits status. RSX fills the OCB with whatever task B specified via the EMST$, and returns the OCB to task A. Now the OCB is accessible to task A. Thus a simple method of intertask communications is completed. The connection between A and B, however, is lost. In order to do it again, task A must respecify the connection to task B (assuming that B is still hanging around, of course). One way of doing this is through the AST option in the CNCT$ directive. We can set up a piece of AST-driven code that reconnects to whatever task emits status to it. Enough talk, let's see some code. .SKIP 2 .NO FILL .NO JUSTIFY ; Test program NAME: .RAD50 / FIDO/ START: MOV _#TTABLE, R3 ; Point at table MOV NAME, T$ID(R3) ; Load taskname in MOV NAME+2, T$ID+2(R3) ; table entry CALL STASK ; Start task up ... code continues ... ; Start Task Subroutine ; ; Inputs: R3 - Points to task table entry ; ; Outputs: R0 - DSW status SNAME: .RAD50 /...SRV/ ; Server taskname STASK: RPOI$S _#SNAME,,,,,,,,,,, T$ID(R3) ; Start task up BCS 1$ ; Handle failure CNCT$S T$ID(R3),, _#UPAST, T$STAT(R3) ; Make connection 1$: MOV $DSW, R0 ; Get status RETURN ; Table Update AST Service Routine ; ; Inputs: R3 - Points to task table entry ; ; Outputs: Table updated UPAST: MOV R3, -(SP) ; Save R3 MOV 2(SP), R3 ; Point at entry CNCT$S T$ID(R3),, _#UPAST, T$STAT(R3) ; Reconnect task MOV (SP)+, R3 ; Restore R3 TST (SP)+ ; Clear stack ASTX$S ; Exit from AST .JUSTIFY .FILL .SKIP 2 "START" sets up a task name of "FIDO" in the first record of the Task Table. It also sets up R3 to point to that record. Now we can call STASK. At STASK the RPOI$ directive requests that a task be created from the prototype task at SNAME. In this case I call it "...SRV". It should be installed prior to the call, otherwise the directive punts and STASK returns IE.INS status in R0. I have elected to specify what task name "...SRV" clone will be called. (Note that this option exists only on M-Plus and Micro/RSX. If this option is omitted, the created task's name is based on which terminal it runs on; e.g. if on TT10:, the task is called SRVT10.) If all goes well with the RPOI$, we proceed to connect to task FIDO. Note how we do the CNCT$. We specify that an AST be queued when the connection is completed. We also set up T$STAT(R3) to have FIDO's status written into. If all goes well, we should return to START with R0 set to IE.SUC. We can now go on our merry way, confident that T$STAT(R3) contains the emitted status from FIDO. Whenever FIDO emits status, UPAST is called. It should find a pointer to the OCB at (SP). Because ASTs can occur at almost any point in the program, I save R3 for later use, and loaded it with the top of stack. R3 now points to the appropriate task table entry, in this case FIDO's. Then I execute a CNCT$ back to FIDO and set up the OCB at FIDO's record address. Next, I restore the state of things so I can exit from the AST. Notice that it doesn't matter which task emits status, because I can tell which task it is by looking at the OCB address. (Which happens to also be the address of the appropriate server task table entry.) .SKIP 2 .TEST PAGE 3 .CENTER When Connecting is Not Enough Now that we have created what amounts to a reusable link with the EMST$ / CNCT$ pair, how can we improve on it? Let's try a few ideas I have used in my application. .SKIP 2 .TEST PAGE 3 .CENTER Running on Other Terminals In the above example, the prototype task "...SRV" is set up to be cloned a number of times. However, they are all running on the same terminal line. It would be nice if there were some way to also specify to the created task which terminal it should attach to. We can solve this problem by using one of those many parameters in the RPOI$ that we previously ignored. The RPOI$ directive allows us to specify which terminal the created task runs under. This is done with the "dname" and "unit" parameters, where "dname" is the ASCII device name of the terminal (typicaly "TT") and "unit" is the unit number. By using this parameter, the "...SRV" task can be written as if it were doing I/O to its standard TI:. There are three caveats, however. Note that in order to run a task on terminal other than one's own, the task executing the RPOI$ has to be Taskbuilt or, at the very least, installed privileged. In this case I specify a /PR:0 option in my TKB command. A task can be created only on a physical device. For instance, you can use "TT" for a device name, but it doesn't really work for a pseudo device. If the task is running on a terminal that isn't logged in (most of the time in my application), there is no User Block for the task. This causes all sorts of problems if you use named directories since RSX tries to use your UIC as a default directory name. Just remember if you open any files to specify the full filename. .SKIP 2 .CENTER Passing a Command Line With RPOI$ we can also pass a command line on startup to the cloned task. We use the "bufadr" and "buflen" option, where "bufadr" is the address of a string to be passed to the task and "buflen" is the length in bytes. This command line can be picked up by the target task by executing a GCML$ directive. This is useful for passing filenames and options to the server tasks. .SKIP 2 .CENTER Timestamping Status It is sometimes useful to know when was the last time a task emitted status. We can get this information by doing a GTIM$ in the AST. A logical place to put it would be in the appropriate task table entry. Then, the next time we check a task's status, we can also find out how old this information is. .SKIP 2 .TEST PAGE 3 .CENTER Display Update Flag If the task table is used to provide information for a real time display, it is very helpful for the redisplay algorithm to have a quick way of knowing if something has "recently" changed in an entry. A good way to do this is by having the AST set something in the task table entry whenever it runs. The display routine can then update the corresponding screen field and clear the table entry. .SKIP 2 .CENTER Use Your Imagination I have talked enough about what I have done. The best way to find out about what RSX can do for you is to sit down, code it up and try it out for yourself. I include here some code which improves on the previous example and includes some of the ideas just mentioned. Happy Hacking. .SKIP 2 .NO FILL .NO JUSTIFY ; Server Task Table Entry Format ; ; +------------------+ ; 00 | Status 2 | T$Stat ; |------------------| ; 02 | TaskId (r50) 4 | T$Id ; |------------------| ; 06 | TTn 2 | T$TTn ; |------------------| ; 10 | Command line 2 | T$Cmd (Null Terminated) ; |------------------| ; 12 | Update Flag 1 | T$Updat ; |------------------| ; 13 | Time HMS 3 | T$HTime, T$MTime, T$STime ; +------------------+ T$STAT = 0 ; Task status T$ID = T$STAT + 2 ; Task name in R50 T$TTN = T$ID+ 4 ; Terminal Number T$CMD = T$TTN + 2 ; Command line arg T$UPDAT = T$CMD + 2 ; Update byte T$TIME = T$UPDAT + 1 ; Timestamp field T$HTIME = T$TIME ; Hours byte T$MTIME = T$HTIME + 1 ; Minutes byte T$STIME = T$MTIME + 1 ; Seconds byte T$LEN = T$STIME + 1 ; Length of entry T$MAX = 64. ; Maximum entries TTABLE: .BLKB ; Server task table SNAME: .RAD50 /...SRV/ ; Server taskname ; Start task ; ; Inputs: R3 - Points to task table entry ; ; Outputs: R0 - DSW status STASK: MOV R3, R0 ; ADD _#T$CMD, R0 ; Get cmd line arg CLR R1 ; Zero line length ; Find length of string by looking for terminating null 1$: TSTB (R0)+ ; Is this a null? BEQ 2$ ; If so, exit loop INC R1 ; Bump string lngth BR 1$ ; And go look again ; Request offspring task, pass OCB, and connect to offspring 2$: RPOI$ _#SNAME,,,,,,T$CMD(R3),R1,,_#"TT,T$TTN(R3),T$ID(R3) MOV $DSW, R0 ; Get status BCS 3$ ; On failure go die CNCT$S T$ID(R3),, _#UPAST, T$STAT(R3) ; Connect to task MOV $DSW, R0 ; Get status BCS 3$ ; On failure go die ; Task started OK. Save status about it in the task table. MOV _#5, T$STAT(R3) ; Set status of 5 GTIM$S _#TIMBUF ; Get system time MOVB SEC, T$STIME(R3) ; Set up start time MOVB MIN, T$MTIME(R3) ; in table entry MOVB HOUR, T$HTIME(R3) ; CLRB T$UPDAT(R3) ; Clear update flag 3$: RETURN ; Return to caller ; Table Update AST Service Routine ; ; Inputs: R3 - Points to task table entry ; ; Outputs: None UPAST: MOV R3, -(SP) ; Save R3 on stack MOV 2(SP), R3 ; Task entry pntr CNCT$S T$ID(R3),, _#UPAST, T$STAT(R3) ; Reconnect to task GTIM$S _#TIMBUF ; Get system time MOVB SEC, T$STIME(R3) ; Set up start time MOVB MIN, T$MTIME(R3) ; in task entry MOVB HOUR, T$HTIME(R3) ; CLRB T$UPDAT(R3) ; Clear update flag MOV (SP)+, R3 ; Restore R3 TST (SP)+ ; Clean off stack ASTX$S ; Exit AST state .JUSTIFY .FILL .COMMENT .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT Erratum: Security of the RSX-11 Operating Systems .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT .TEST PAGE 15 .SKIP 6 ###^IC0000^IS328^GErratum: Security of the RSX-11 Operating Systems^IS204^IC1000^G .SKIP .CENTER Thomas R. Wyant III .CENTER E. I. DuPont de Nemours _& Co., Inc. .CENTER Textile Fibers Department .CENTER Richmond, VA###23261 .SKIP In my article on RSX security (see "Security of the RSX-11 Operating Systems") in the June 1987 issue of ^&The Multi-Tasker\&, the section on protecting the system console terminal recommended that the console be slaved at SYSVMR time via the following VMR command: .SKIP VMR>SET /SLAVE=TT0: .SKIP to ensure that the system comes up with the console terminal slaved and therefore unresponsive to attempted startup command file aborts. This technique sounds good but, as it turns out, is a bum steer. It is defeated - deliberately! - by the SAV task. As part of its system startup processing, SAV selects a console terminal and explicitly marks it logged on, unslaved, and privileged. This negates the effects of the recommended VMR command. I know of no particular reason why the console terminal must be unslaved on startup. The code in SAV that unslaves the terminal is the statement: .SKIP BIC#####_#U2.LOG!U2.SLV, U.CW2(R3) .SKIP at label FINDCO: in [12,10]SAVE.MAC on the SYSGEN kit. The obvious modification is to remove U2.SLV from the bit clear, producing the modified statement: .SKIP BIC#####_#U2.LOG, U.CW2(R3) .SKIP then reassemble SAVE.MAC, library the new module, rebuild SAV, and re-VMR the system. I have NOT tried this; it may leave your system brain dead for some obscure reason. But if you're desperate to close that little window between the time the system comes alive and the time that STARTUP.CMD cranks up, here's a starting place. .COMMENT .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT The Hitchhiker's Guide to RSX, Part II .COMMENT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .COMMENT .TEST PAGE 15 .SKIP 6 ############^IC0000^IS328^GThe Hitchhiker's Guide to RSX, Part II^IS204^IC1000^G .SKIP .CENTER A-to-Z Base Product Marketing .CENTER Digital Equipment Corporation .CENTER Continental Boulevard, MKO1-2/E25 .CENTER Merrimack, NH##03054 .SKIP Through the kind intervention of a Digital employee, the Multi-Tasker is pleased to present "The Hitchhiker's Guide to RSX". This is probably the best overall coverage of the current RSX environment available. It is also a valuable reference for all application programmers, not just business application developers. This document is being serialized due to its length. This is the second of three parts, covering chapters 5 through 8. .PAGE # .SKIP 6 .CENTER HITCHHIKER'S GUIDE TO RSX .SKIP 2 .CENTER An Introduction to RSX for Business-Application Developers .SKIP 6 .CENTER Revision 0.0 .SKIP 4 .CENTER Disclaimer .SKIP This is a preliminary version and is not quite one-hundred percent complete. Please send comments, questions, and recommendations -- on this document -- to A-to-Z Base Product Marketing, MKO1-2/E25, Digital Equipment Corporation, Continental Boulevard, Merrimack, New Hampshire 03054. .SKIP The information in this document is subject to change without notice and should not be construed as a commitment by Digital Equipment Corporation. Digital Equipment Corporation assumes no responsibility for any errors that may appear in this document. .SKIP The software described in this document is furnished under a license and may only be used or copied in accordance with the terms of such license. .SKIP No responsibility is assumed for the use or reliability of software on equipment that is not supplied by Digital Equipment Corporation or its affiliated companies. .SKIP 3 .CENTER Copyright (C) 1986 by Digital Equipment Corporation .CENTER All Rights Reserved. .CENTER Printed in U.S.A. .SKIP 2 .CENTER September, 1986 .PAGE .CENTER Table of Contents .SKIP 2 .NO FILL .NO JUSTIFY Chapter 5 Record Management Services (RMS) 5.1 Introduction to RMS 5.2 File Organizations 5.2.1 Sequential 5.2.2 Relative 5.2.3 Indexed 5.2.3.1 Structure 5.2.3.2 Population 5.2.3.3 Index Activity 5.2.3.4 Storage Overhead 5.2.3.5 Interlocks 5.3 File Design 5.3.1 Which Files to Design 5.3.2 Selecting an Organization 5.3.3 Common Design Factors 5.3.3.1 Allocation 5.3.3.2 Extend Quantity 5.3.3.3 Contiguity 5.3.3.4 Carriage Control 5.3.4 Designing Sequential Files 5.3.5 Designing Relative Files 5.3.6 Designing Indexed Files 5.3.6.1 Specifying Key Fields 5.3.6.2 Sizing Buckets 5.3.6.3 Areas 5.4 Tuning RMS Files 5.4.1 Avoid File Opens 5.4.2 Use the Simplest Possible File Structure 5.4.3 Beware of Overloading Directories 5.4.4 Pre-Allocate the File 5.4.5 Make Critical Files Contiguous 5.4.6 Substitute Code for Mechanical Movement 5.4.7 Distribute the Load 5.4.8 Avoid Going Overboard Chapter 6 RMS Utilities 6.1 RMSDES File Design Utility 6.2 RMSIFL Indexed File Load Utility 6.3 RMSCNV File Conversion Utility Chapter 7 RMS for CTS-300 Users 7.1 Record Locks 7.2 Access Modes 7.3 Interchanging Sequential and Relative Files 7.4 Extending Files 7.5 Print Files Chapter 8 Flow Control 8.1 Concept of a Task 8.1.1 Installing a Task 8.1.2 Task Names 8.2 Requesting an Installed Task 8.2.1 RUN a Task 8.2.1.1 Running an Installed Task 8.2.1.2 Running a Task from a File 8.2.1.3 Running a System Utility 8.2.1.4 RUN as a Scheduling Command 8.2.2 Chaining between Tasks 8.2.2.1 Indirect Chaining 8.2.2.2 Direct Chaining 8.2.2.3 Chaining to a Command File 8.2.3 Spawning an Offspring Task 8.2.3.1 Indirect Spawn 8.2.3.2 Direct Spawn 8.3 Parent-Offspring 8.3.1 Command Line 8.3.2 Status Code 8.4 Intertask Communication 8.4.1 Send/Receive 8.4.2 Global Event Flags .JUSTIFY .FILL .PAGE .CENTER Hitchhiker's Guide to RSX .SKIP .CENTER D O N ' T P A N I C .SKIP 3 .CENTER Chapter 5 .SKIP .CENTER Record Management Services (RMS) .SKIP 2 In the early days of RSX there was little in the way of facilities for file or record management. File Control Services (FCS) offered routines to open and close files, and a Macro program could issue QIO requests directly to the disk driver. There was provision for sequential access to records and random access to disk blocks - but otherwise application developers were left pretty much to themselves. The need for something more was apparent and eventually RMS-11 was developed. .SKIP 2 5.1##Introduction to RMS Record Management Services (RMS) is a language-independent set of file and record management routines which may be linked into a user program to perform a variety of file and record related functions. Since the in-file format is determined by RMS and not by the host language processor, records within the files are also language independent, thereby providing a ready mechanism for exchange of data between applications. RMS has undergone several revisions since its inception, primarily to take advantage of more advanced hardware and operating system features. The first versions of RMS were a collection of object modules that had to be linked into, and carried about with, the task image. Modern versions take advantage of memory management hardware and CPU operating modes for improved speed and reduced disk space requirements and activity. The current version of RMS may be linked as a shared library which reduces disk requirements for task images and eliminates the overhead of disk overlays for the RMS routines. Another option is clustering the RMS library with the language OTS; this increases the amount of virtual address space available to the application. Lastly, it may be linked as a supervisor mode library on processors which support supervisor mode operation; this does all of the above and reduces the time required for context switching between libraries. For further details, see the chapter on linking. Full access to all RMS features is really only available through Macro. Each higher level language makes trade-offs in mapping traditional semantics of the language statements to facilities provided by RMS. Some languages allow the developer to specify the characteristics of a file being created with great precision; others do not. Some permit update of files opened for input; some do not. Some language statements may cause the run-time library to execute hidden RMS operations. The DIBOL WRITE statement, for instance, stores a record into both occupied and un-occupied cells, executing either an RMS PUT or UPDATE operation, as required. Utility programs are provided with RMS which provide for creating, converting, and re-organizing RMS files. These utilities can be used interactively or can be spawned from an application to perform their various functions. .SKIP 2 5.2##File Organizations RMS provides support for three major and two minor file organizations. The major types are sequential, relative and indexed. The minor types are "stream" and "undefined"; these are not discussed further here. Types of access allowed to a file depend on its organization. .SKIP 2 5.2.1##Sequential Sequential files are the simplest format and, in some circumstances, offer the highest performance. A sequential file consists of a header and a number of data records. The file is loaded by writing a series of data records. Later, the records may be retrieved in the order in which they were written. When you create a sequential file you may specify that the file contains fixed or variable length records. Fixed length format offer the most efficient packing. Variable length format offers the greatest flexibility and is by far the more common format. Sequential files are appropriate for serial writing or reading of records. Very high performance may be attained with languages which support the multiple buffering and deferred write features of RMS. There is no provision for deleting, replacing or updating records once a sequential file is created. Some languages permit opening a sequential file to append data to existing records. Sequential files with fixed length records do allow limited facilities for random access, but record interlocks are limited and this use is not encouraged. .SKIP 2 5.2.2##Relative Relative files consist of a file header, a prologue and data records. The header and prologue contain information about the file and the records. Data records are stored in groups known as "buckets". The size of the bucket is declared when the file is created, and each bucket is divided into as many record cells as will fit. Cells are all the same size and can hold the largest record. Maximum record size must be declared when the file is created. Data records within the cells may be fixed or variable length, but unused space in a cell containing a short record cannot be put to other uses. Once the file is created, the records may be loaded serially or randomly. There is a flag byte in each record cell which indicates whether a record is present, has never been stored or has been stored and then deleted. Records may be stored, retrieved, updated and deleted, randomly or sequentially. RMS automatically maintains a current record context which determines which record is selected for the next sequential operation. If a record is written to a cell beyond the end of the existing data, the file is automatically extended. New buckets are created and initialized by RMS, as required. Relative files represent a good compromise between convenience and efficiency. As long as buckets are densely populated data is stored with comparatively little overhead and access to any record in the file requires only a single I/O operation (not counting window turns). Interlocks are provided for files which have been opened for write access by one or more programs. Interlocks are maintained on a bucket basis. .SKIP 2 5.2.3##Indexed Indexed files offer the most flexibility to the programmer. You may access records directly or sequentially, by a primary key and any of up to 254 secondary keys. The keys may be located anywhere within the record, may be contiguous or segmented, and may be one of several data types. The index structure is dynamic, increasing in size and number of levels to accommodate new records as they are added to the file. Access time for all records is uniform whether the file is loaded in sequence by primary key, randomly across the file or in clusters. The number of I/O operations required to reach any record in the file is a minimum and is approximately equal to the number of levels in the index. In effect, RMS exchanges CPU time required to manage the (comparatively complex) index for more costly mechanical movements of the disk head. For small files there is little benefit to using this organization, but for files which contain tens of thousands of records the savings are substantial. There is a substantial amount of overhead carried with indexed files, both in terms of disk space and the code required to manage the file. Indexed files require the most attention to their design. There are a large number of design parameters associated with indexed files and unless values for these parameters are selected carefully, the file performance may prove disappointing. Due to the complexity of indexed files and the great variety of usage patterns it is impossible to provide defaults which are universally suitable and the burden of design is left to the developer. .SKIP 2 5.2.3.1##Structure An indexed file consists of a header, a prologue and two or more index levels for each key. The header describes the location of the file extents, and the prologue describes the structure of the records and the index levels. The lowest level of the primary index contains the data records themselves which are grouped together into buckets. Higher levels of the primary index contain copies of data record keys and pointers to the appropriate buckets at the next lower level. The highest level of the index is called the root, and consists of a single bucket. Each alternate key defined for the file has its own index structure. The structure of an alternate key index is the same as the primary key index except that, in place of user data, the lowest level contains Secondary Index Data Records (SIDRs). SIDRs contain alternate key values and pointers to data records in the primary index. There is only one copy of a data record in a file, but there may be several copies of the key field. Data records are collated in the buckets by primary key and the buckets are linked together so that sequential access can take place without any references to the index. .SKIP 2 5.2.3.2##Population A newly created file may be populated by writing records sequentially or randomly throughout the file. The index is dynamic, expanding both horizontally and vertically as required. When the initial allocation is exhausted RMS expands the file automatically by allocating buckets as required. As buckets fill up they are split to make room for new records. Populating a file with an application program is not necessarily the best way to proceed, however. There are certain features of RMS pertaining to indexed files, such as Bucket Fill size, which are only available to Macro. In addition, secondary key indexes are often convoluted since even if the records are added to the file in order of ascending values for primary key, the values for the secondary key are unlikely to be in an optimal order. Both these problems can be overcome with the Indexed File Load (RMSIFL) utility. .SKIP 2 5.2.3.3##Index Activity When a new record is added to the file, the primary index is scanned to find the proper bucket and the record is inserted according to its primary key value. If there is insufficient room to store the record, the bucket is split and half the records are moved to a newly created extension bucket. The next higher level index is updated to indicate the existence of the new bucket and the record is inserted. If the index bucket is filled, it too is split; and if the bucket being split is the root, a new index level is formed. If the file contains alternate keys, then each alternate key index must be searched until the lowest level is reached, a SIDR record added or updated, splitting the SIDR bucket if necessary, and so on. The amount of I/O required to store a new record or update an old one is a direct function of the number of keys. .SKIP 2 5.2.3.4##Storage Overhead The storage overhead in a bucket is a significant factor in indexed files and, unlike relative files, may increase over the life of a file. One of the features of RMS is that each data record in a file has a unique address, and, if the record is deleted, the address is never re-used. Because of this, deleted records leave behind residue which can be as little as two bytes (fixed length records, no duplicates for the primary key) or as much as the entire record (fixed length records, duplicates allowed for primary key). Similarly, if a record moves from its original location in a file when a bucket is split, a Record Reference Vector (RRV) is left in the original location. If you expect to be splitting buckets or deleting records frequently you must carefully consider the record type and key locations and the implications for bucket overhead. .SKIP 2 5.2.3.5##Interlocks RMS provides full interlock support on a bucket-wide basis. Each program which opens a file declares the operations that it wishes to perform and also the operations that it allows other programs. These declarations are often supplied by the language runtime system depending on the particular statement used and the default values may differ from one language to another. If the access declarations of all programs accessing a file are compatible, processing proceeds. Otherwise, the program opening the file with the incompatible access code receives a protection violation. .SKIP 2 5.3##File Design The design and tuning of RMS files is an area of study unto itself. The number of possible usage patterns for files is large and it is not possible for RMS to anticipate the manner in which a particular dataset is accessed. There is no obvious limit to the amount of effort you may put into improving your files, but there is usually a point beyond which additional effort might be better expended elsewhere. You must decide for yourself when you have reached the point of diminishing returns. This section is not intended to be a comprehensive tutorial on file design but rather to point the way to those areas where small changes may have major impact on the performance of an application as a whole. See the RMS User Guide for further details about file usage and design. .SKIP 2 5.3.1##Which Files to Design Although it may seem obvious, you should limit your design efforts to those files which are most critical to the performance of your application. If a particular file is used only occasionally there is little benefit to spending a great deal of effort on optimizing its performance. Concentrate efforts on large files, files which have many simultaneous users, or files which have high levels of insertion and deletion activity. .SKIP 2 5.3.2##Selecting an Organization In general, the amount of processing and overhead necessary to manage a file increases with the flexibility of the available access methods. Sequential and relative file organizations are very fast and carry little or no overhead, but they do not provide all the access paths of the indexed organization. You almost always attain the highest performance by choosing the simplest file organization which can be made to provide the access features you require. .SKIP 2 5.3.3##Common Design Factors The design parameters of a file are set when the file is created. The more complex the file organization, the more parameters there are to consider. There are some parameters, however, which are common to all file types. .SKIP 2 5.3.3.1##Allocation All files allow an initial allocation of disk blocks to be specified when the file is created. In the case of relative and indexed files, this allocation is mandatory since storage space must be provided for the file prolog. Allocating space for a file when it is created has two benefits. The allocation takes place all at one time and the disk blocks are likely to be located close together. The file can also be loaded without the interruption of extend operations. Unused space allocated to a file cannot be used for anything else. Once the file is fully populated, you may return any excess blocks to the operating system by truncating the file. If your language does not support the RMS truncate facility, you may spawn DCL with a SET FILE/TRUNCATE command. .SKIP 2 5.3.3.2##Extend Quantity If a file is created with less than the amount of space required for storage of the data, you may wish to specify an extend quantity. This is the amount by which the size of the file is increased when additional space is needed. The extend operation is carried out automatically by RMS so your application may not be aware that it is happening. The default extend quantity for all files on a disk is set when the volume is initialized; this value may not be appropriate for a given file. If the extend quantity is too big you may waste space. If it is too small the file must be extended frequently, which means frequent interruptions in file processing, scattered file fragments and reduced performance of subsequent file processing. A commonly used rule of thumb is to specify an extend quantity derived from some unit of processing such as a day's worth of records. .SKIP 2 5.3.3.3##Contiguity The best single action you can take to assure optimal file performance is to make the file contiguous. To make a file contiguous you must allocate all the required disk blocks when the file is created, which may result in some wasted space until the file is filled. It may also require that you re-organize the disk with Backup (BRU) to gather the unused fragments into a larger, contiguous space. .SKIP 2 5.3.3.4##Carriage Control If the file is ever to be printed or otherwise output to a record I/O device (printer or terminal) you may wish to specify a carriage control attribute for the file. Carriage control determines the way in which RMS separates the records as they are being output. Instead of carrying the formatting information with each data record, RMS stores a single format setting in the file header and this setting is interpreted by the system utilities when the file is printed. The default setting is Carriage_Return which means that as each record is output it is preceded by a line feed and followed by a carriage return. You may override this setting by specifying None. If you specify None you must store the formatting characters as data within your records, that is, you must explicitly include carriage return or line feed characters within your data records. Some languages have special file qualifiers which are used for this purpose. .SKIP 2 5.3.4##Designing Sequential Files Sequential file design is primarily a matter of allocation. Most such files are created with variable record lengths, and that's the end of it. You are allowed to specify that records may not span block boundaries but in most cases this practice is wasteful and not recommended. There is a special case situation involving fixed length records which you may wish to use. If you declare the records to be of fixed, defined length when you create the file you may use a limited form of random access to the file. You may store and retrieve records either sequentially or randomly. Access to this facility depends on which language you are using, and there is no record interlock protection. .SKIP 2 5.3.5##Designing Relative Files Designing relative files is also comparatively simple. Like sequential you choose an allocation and extend size. Records may be of fixed or variable length, but the record cells allocated are of uniform size and large enough to contain the longest record. RMS keeps track of the byte count of variable length records so the application never sees anything except real data. One additional design factor is determining the bucket size. A bucket is the logical structure within which records are grouped and the size you choose can affect the performance of the file. RMS reads and writes buckets in their entirety so that when you read a record from a file the entire bucket is loaded into a buffer in your program space. Bucket sizes are specified in blocks, 512 bytes. RMS fits as many record cells in a bucket as possible. Record cells are equal to the defined maximum record length plus one flag byte plus two length bytes if the records are variable length. Large buckets are good for access which is generally sequential or clustered. If your program reads a record and then reads an adjacent record which is in the same bucket, RMS fetches the record without re-reading the bucket, thus saving an I/O operation. Small buckets give better performance if the access patterns are random or if the file is shared between two or more programs. Interlocks are maintained by RMS on a bucketwide basis so that reading a record from a file with large buckets ties up more records than if smaller buckets are used. RMS also keeps a flag byte for each record cell in the bucket. This byte tells whether the cell has ever been used and whether it is presently occupied. RMS can therefore distinguish between records which have never been stored, have been stored, and have been deleted. .SKIP 2 5.3.6##Designing Indexed Files Designing indexed files can be a complex process. You must define key fields, decide on optimal bucket sizes, partition the file into areas and populate the file. Any or all of these decisions may affect the performance of the file. Here, more than anywhere else, you must consider each feature in light of its associated cost and use only those facilities which are really necessary. .SKIP 2 5.3.6.1##Specifying Key Fields When you create an indexed file you must specify how many keys you intend to use and a number of parameters for each key. You must indicate how many segments each key has and where they are located, whether the key may be duplicated, what type of data it is, and an optional null value. Key placement within the record is not critical for static files. If, on the other hand, records are to be deleted, the primary key should be located at or near the beginning of the record to reduce the amount of residual overhead in the bucket. The length of the key is also important. Index buckets contain key values and bucket pointers. The shorter the key, the more index entries fit in a bucket; the index is shallower as a whole. Shallow index structures mean fast access. Keys may be string, integer or packed decimal fields. Whether or not you allow duplicate values depends on the application but you should be aware that allowing duplicates can slow down writing of records and increases the amount of overhead due to deleted records. Null values can be specified for alternate key fields. If a record is stored and an alternate key field contains only the null character then no entry is made for that record in the alternate key index. If many such records are stored the overhead of the alternate key index processing can be kept to a minimum. If at some later time the record is updated and a real key value is supplied, the alternate key index is updated accordingly. .SKIP 2 5.3.6.2 Sizing Buckets The same general rules govern bucket sizes in Indexed files that pertain to Relative files. If access is expected to be primarily sequential or clustered around certain key values, make the buckets large. If access is expected to be random or the file is heavily shared, make the buckets small. The memory penalty for large buckets is greater for Indexed files since RMS allocates two bucket-sized buffers when an Indexed file is opened. Furthermore, you should consider the relationship of bucket size and the number of levels in the index. The time required to process an index bucket (computation) is negligible compared to the time required to move to the next index level (I/O). Therefore, the time to access a record is directly proportional to the number of levels in the index. Larger buckets mean a shallower index and faster operations. You should set the bucket size to the smallest size (program size considerations) that results in an index with three or four levels including the data. Very large files may require five levels total. You must anticipate the amount of activity overhead in the bucket due to splits and deleted records. If you expect the file to be static, that is, it is loaded once and then read many times, you need not allocate space for the overhead. If, on the other hand, you intend to insert and delete a lot of records you must allocate additional space. Finally, you may specify a Bucket Fill Size when you create the file. This factor is the percentage of each bucket that is used if the Mass Load bit is turned on during the initial load of the file. This is of most benefit when records are added uniformly across the file. Leaving the extra space in each bucket reduces (but not necessarily eliminates) the number of bucket splits which occur and therefore the RRV overhead. There is still probably unused space in some buckets, however. .SKIP 2 5.3.6.3 Areas RMS Indexed files may be partitioned into Areas as part of the initial allocation. An Area is a portion of the file which is set aside for a specific purpose. Each index may have up to three areas allocated to it. Each Area may have its own allocation, extension size and bucket size. The primary advantage of this partitioning scheme is that logically related buckets are grouped closely together in a file and head movement while traversing an index tree or scanning sequentially through data buckets is minimized. In the simplest case a file could be divided into an Index and a Data area. When bucket splits occur, the extension buckets are allocated from the appropriate area. Without Areas, index buckets are scattered throughout the file in such a way that moving from one index level to another may require moving the disk head a considerable distance. Areas also allow a certain amount of optimization. You may be able to improve performance by specifying a smaller index bucket if data records are very large and access is primarily random. Large index buckets should be used if records are small or access to the file is clustered. .SKIP 2 5.4 Tuning RMS Files File design is only one aspect of what makes an application mix go fast or slow. But it's a highly visible aspect, and is one with which developers feel most familiar and comfortable. It is often the case that poor file performance results from a lack of understanding that every feature of a system has an associated cost and, in some cases, the cost may not be obvious or may be described in such a way that its significance is not properly marked. This section points out some of the more common areas in which unneeded features can burden an application. See the RMS-11 User Guide for more details. .SKIP 2 5.4.1 Avoid File Opens One of the most expensive things you can do with a file is to open it. RSX supports lots and lots of files in any given directory and developers who are moving over from CTS-300 may not be making effective use of the directory structure. Once you have a file open you should avoid closing it since the close usually means another open at some later time. There is more program space available on RSX than any other PDP-11. You may be able to keep files open on RSX that memory constraints caused you to close on other systems. .SKIP 2 5.4.2 Use the Simplest Possible File Structure If you use a multi-key index structure the file is necessarily larger and slower than if you use a single key. A single key file is more complex than a relative file and access to a record with a known key is slower. Sometimes developers discover that they can live without ISAM after all and the performance difference is considerable. .SKIP 2 5.4.3 Beware of Overloading Directories Directory searches are no different from scanning any other sequential file and records at the end take the longest to find. Keep your directories small and balanced for fast access. You should also realize that when you create a new file the system has to search through the entire directory to see if a file of the same name already exists. Consider re-using an old file in place of creating a new one. .SKIP 2 5.4.4 Pre-Allocate the File If the file is to be static and the amount of data to be stored therein can be estimated then you may wish to allocate the entire file when it is created. This keeps fragmentation to a minimum and improve processing speed. Such allocations must be judged in light of total disk capacity and their affect on free space. .SKIP 2 5.4.5 Make Critical Files Contiguous The cost of locating the different parts of a file can represent up to 30% of the disk activity. Make your file contiguous. Failing that, make the extents of the file as large as possible. If a file which is contiguous is extended then it is no longer strictly contiguous, although some of the benefits of the initial contiguity still pertain in that the initial allocation is a single large extent. If the file is further extended over time you may wish to periodically restore it to a contiguous state. You can do this from your application by spawning a COPY/CONTIGUOUS command. .SKIP 2 5.4.6 Substitute Code for Mechanical Movement Disk activity almost always involves some mechanical movement, often requiring tens of milliseconds to complete. It is often possible to replace disk operations with program code. If you are suffering a performance problem, try to determine whether you can simplify the file by doing a little more work in your program. .SKIP 2 5.4.7 Distribute the Load Multiple disk spindles very often can provide more throughput than a single drive for a given total storage capacity. The disk head itself is subject to a number of demands in addition to data transfer such as directory manipulation and program overlays and consequently may become a significant bottleneck. Even though timesharing continues while the head is moved, all other disk I/O requests are delayed; and, since commercial systems depend heavily on I/O, this is a serious problem. RSX supports overlapped seeks if multiple disk drives are available so that a number of disk requests can be processed simultaneously. .SKIP 2 5.4.8 Avoid Going Overboard Multiple keys are costly if records are being stored or updated in a file. The number of disk operations required to store a record is proportional to the number of keys. Very long keys consume extra storage and can increase the number of levels in an index by reducing the number of key entries in an index bucket. Keep the keys near the beginning of the record. For certain types of files, deleted records leave behind a fragment which includes the record from the beginning through the end of the primary key. Load the file in order of ascending key value. Doing otherwise causes more frequent bucket splits and a more complex index. Avoid duplicate keys, if possible. Duplicate primary keys increase the overhead of deleted records. Duplicate alternate keys can result in long chains of pointers in the SIDR records. .PAGE .CENTER Chapter 6 .SKIP .CENTER RMS Utilities .SKIP 2 Most programming languages on RSX lack support for one or more RMS features. Moreover, there are a number of operations which should be carried out on a regular basis for creating and maintaining RMS files. Therefore, special utility programs have been provided which may be invoked interactively or may be spawned with a command file. What follows is a brief description of three of these utilities. For details about the operation and use of these programs see the RMS-11 Utilities Manual. .SKIP 2 6.1 RMSDES File Design Utility RMSDES is an interactive utility for designing and creating RMS files. You design a file by issuing commands to set, clear and display file attribute values in a file design buffer workspace. Attributes are arranged in functional groups which pertain to the target system, file, record, key and areas for the file. You may enter or change the attributes in order from beginning to end, by section, or individually. You may enter the attribute values directly, load them from a description file or copy them from an existing data file. You may create a file directly or save the workspace in a description file for use at another time. When the attributes are arranged to your satisfaction you may create an empty file. RMSDES checks to see that all required values are present and performs sanity checks on the values. .SKIP 2 6.2 RMSIFL Indexed File Load Utility RMSIFL reads records from any type of RMS file and loads them into an empty Indexed file. RMSIFL is superior to other loading methods in that it bypasses the standard RMS mechanism and exploits the underlying file structure to produce an output file quickly and with optimal packing of buckets. Use of RMSIFL is the most common way of honoring the Area Fill values specified for the indexed file when it is created. RMSIFL operates in a number of phases. It optionally sorts the input records by primary key value before loading them into the indexed file. During the load it extracts any alternate key values and stores them in a temporary file. When the data records are completely loaded, RMSIFL sorts the values for each alternate key and then build the alternate key indexes. The resulting file is optimized for the fastest possible access along all index paths. RMSIFL has some limits. The index structures are created without the assistance of RMS which means that the output file must be empty at the beginning of the load. RMSIFL can handle no more than 20 keys per record and may be limited to bucket sizes of five blocks or less depending on the format of the record and the keys. These restrictions aside, RMSIFL is absolutely the fastest way to load a high performance indexed file. .SKIP 2 6.3 RMSCNV File Conversion Utility RMSCNV can read data records from any RMS file organization and load them into any other, either locally or over a network. RMSCNV uses the standard RMS facilities to read the data and build the output file. It is not subject to the same limitations as RMSIFL. RMSCNV can be used to append records from one file to another, re-establish contiguity and convert data from one file format to another. If the output file is to be sequential, RMSCNV can create it. Otherwise the file must be created before RMSCNV can be used. A number of switches are available (and may be required) which determine such operations as record truncation and padding, recognition of bucket fill size and mass insertion mode, block mode operation and so on. When used with Indexed file structures RMSCNV is not subject to any of the restrictions of RMSIFL but does not provide the same level of performance. .PAGE .CENTER Chapter 7 .SKIP .CENTER RMS for CTS-300 Developers .SKIP 2 Since many commercial users are migrating their applications from CTS-300, this section is set aside to point out some of the more commonly encountered problems caused by the differences between DMS and RMS files. .SKIP 2 7.1 Record Locks The biggest single difference encountered by developers moving from CTS-300 to RSX is the way record interlocks are managed. CTS-300 (and VMS) were created with the record management facility tightly integrated with the operating system; therefore, it is possible to control access to shared files in such a fashion that potentially dangerous operations are avoided. The most common such case is allowing one program, which has opened a file for input, to read a record or bucket which has been locked by a second program which has the file open for update. This is permitted on both CTS-300 and VMS such that read operations issued to a file opened for Input never encounter a record lock. There may, in fact, be delays in the read operation if the request occurs at a difficult time but these delays are temporary and are invisible to the application. RMS on RSX is more of a layered application than an integral part of the operating system. It is possible, therefore, that a program which has a file open for input might try to traverse an index tree which is being updated by another program and if this happened, the program issuing the read might crash. To prevent such an occurrence, any access to a file which has been opened for update or write operations is subject to record locks. .SKIP 2 7.2 Access Modes As explained earlier, DIBOL makes certain assumptions in mapping the various language statements to RMS facilities. One commonly encountered example has to do with access modes declared when a file is opened. When a program calls upon RMS to open a file it must declare both the operations it intends to perform (Read, Write, Update, Delete) and also the operations it allows other programs to perform. RMS matches these access declarations with those of any other program which has the file open and only permits the latest program to proceed if the access codes are compatible. This has certain side effects. A common example is the complaint that DIBOL on RSX is much slower than DIBOL on RT-11 or RSTS since it takes longer to read sequentially through a file. For some reason that is not clearly understood the sample file chosen for such experiments is always a relative file which results in an unexpected condition. When DIBOL opens an existing file for input it tells RMS that it wishes Read only access and, because of the traditions of CTS-300, it allows other programs write access. RMS interprets this as a hint that the data in the file may change (even though no other programs have the file open at that moment) and consequently re-reads the entire bucket each time the DIBOL program tries for the next record. If the DIBOL program were to open the file in Update mode, the bucket would be locked when the first read occurs, and subsequent reads take place directly from the bucket in memory. There would only be I/O when moving from one bucket to the next. The difference in processing speeds between input and update mode is directly proportional to the number of records in each bucket. That the open mode should affect the speed with which a program may scan a file is just one example of how "poor performance" may be due to a simple misunderstanding. .SKIP 2 7.3 Interchanging Sequential and Relative Files It is a common practice on CTS-300 to create a file as sequential, fill it with records and then close the file and re-open it for random access. This is also possible with RMS except that the file must be created with a Relative structure. While RMS permits limited random access to a sequential file with fixed length records, the use of Relative files offers more capability and is the preferred method. There is one consideration in transporting such an application from CTS-300 to RSX or VMS. It is sometimes the case that such files begin with a header record which is a different length than the transaction records. Since RMS relative files are allocated in record cells, each large enough to contain the largest possible record, it is wasteful to write a very large record followed by a number of smaller ones. It is much more efficient to write the header data into a number of smaller records and adjust the transaction record numbers accordingly. .SKIP 2 7.4 Extending Files RSX permits files to be extended regardless of the internal structure while CTS-300 does not. This means that you need not allocate all the space required for a file initially. Performance suffers somewhat if the file is extended many times but you can overcome this by periodically using RMSCNV to restore the contiguity. .SKIP 2 7.5 Print Files It is common practice on CTS-300 to write records in fragments using mixtures of WRITES and DISPLAY statements. This is done partly for coding convenience and partly due to the increased flexibility of formatting. This practice is possible because DMS files are really an unstructured stream of characters whereas RMS files (on VMS as well as RSX) are a series of records. Formatting of reports on RMS is provided through the Print Mode files (O:P) which use the NONE declaration for Carriage Control when the file is created. Each subsequent output operation, whether a WRITES, DISPLAY or FORMS creates an individual record and the application program is responsible for adding all the carriage control characters. While these files are somewhat lacking in storage efficiency, the programmer has full control over the output format. A consideration when using such files is that attempts to re-read the file must be made with care. On CTS-300 it is possible to create a record in a file with a number of DISPLAY statements followed by a WRITES. On re-reading the file, all of the information is returned as though it had been written as a single record. With RMS this is not the case. Each field is stored as an individual record and is therefore returned as individual records in exactly the order with which they were written. .PAGE .CENTER Chapter 8 .SKIP .CENTER Flow Control .SKIP 2 Most small system commercial applications are broken down into a (possibly very large) number of program modules, each of which fits within the bounds of a limited hardware configuration and CPU architecture. Flow control is that aspect of application design which determines the manner in which these logic modules exchange information and control. One of the dimensions along which operating systems differ most widely is the variety and comparative efficiency of the flow control mechanisms. CTS-300 (RT-11) and RSTS are limited to program Chaining. VMS allows a primary program module to Chain to a secondary, spawn a secondary in a sub-process or, when the secondary module permits, call it as though it were a subroutine. RSX permits both chaining and spawning - each in a variety of flavors. Each of these mechanisms has its advantages and disadvantages. RSX originated in the scientific / industrial marketplace where realtime response is a top priority. The design point was to create a system in which a particular program module (Task) could be activated as quickly as possible upon the occurrence of some event. Consequently, the flow control architecture is more complex than the other systems, and it requires a bit of understanding before it can be used to greatest advantage. .SKIP 2 8.1 Concept of a Task The fundamental unit of execution on RSX is the TASK. System utilities are tasks. Compilers and editors are tasks. Application programs are tasks. Activation of a task is a two step process. .SKIP 2 8.1.1 Installing a Task Before RSX can do anything with a task it must be Installed. Installation is the process by which the location and characteristics of the executable module are made known to the system Executive. Once installed, a task is available for execution and remains so until it is removed. Each task on the system must be installed with a unique, six character name. During installation the Executive records the task's location on disk (by File ID for very fast access), priority, the name of the partition in which the task executes, and several other items which reduce to an absolute minimum the number of operations which remain before the task can actually begin to execute. Contrast this with other systems in which a RUN command causes the Executive to begin looking through disk directories just trying to find the program image. .SKIP 2 8.1.2 Task Names Installed tasks are identified by name and therefore the name must be unique on the system. Multiple programs may have the same task name but only one of them may be installed at any time. The name of the task may be established when it is linked, when it is installed, or when it is requested and run. A special case of task naming is the "Prototype" name which consists of three periods followed by three alphabetic characters such as "...PIP". This is the mechanism by which multiple terminals can be executing independent copies of the same program. When a particular terminal invokes a task installed with a prototype name, the Executive creates a private copy of the task for the requesting terminal and gives it a unique task name by combining the prototype name and the terminal name. Thus, a copy of PIP running at terminal 11 becomes "PIPT11". The prototype task name is an important facility for systems where multiple copies of job streams may be executing simultaneously. .SKIP 2 8.2 Requesting an Installed Task Once a task is installed and brought to the absolute brink of execution, all that remains is for some entity on the system to request its execution. Some tasks are requested as a result of a command typed at a keyboard. Others are requested via system directives issued by another program. There are a number of different mechanisms involved but the functionality of all of them falls into one of three categories. .SKIP 2 8.2.1 RUN a Task The simplest way to invoke a task is to RUN it. The RUN command has four forms. .SKIP 2 8.2.1.1 Running an Installed Task If a task is already installed you may invoke it with the RUN command and the task name: .SKIP RUN taskname .SKIP 2 8.2.1.2 Running a Task from a File If a task is not installed you may invoke it directly from the task image file: .SKIP RUN filespec .SKIP This form of the RUN command invokes a special facility known as Install-Run-Remove. Before the task actually runs it is installed with your terminal name (e.g. "TT11") as the taskname. The task is then run and when it exits, it is removed. You may pass a command to the task with the /COMMAND:"command string" qualifier. .SKIP 2 8.2.1.3 Running a System Utility You may invoke the system utilities by preceding the task image filespec with a dollar sign: .SKIP RUN $RMSDES .SKIP This tells RSX to look in the system library for the image file. You may pass a command to the utility with the /COMMAND:"command string" qualifier. .SKIP 2 8.2.1.4 RUN as a Scheduling Command The last form of RUN allows a privileged user to schedule the execution of an installed task for some future time: .SKIP RUN/SCHEDULE:hh:mm:ss taskname .SKIP 2 8.2.2 Chaining between Tasks The chain mechanism on RSX is the RPOI$ directive - Request and Pass Offspring Information. All the popular implementation languages provide support for this directive in one form or another. Check the User Guide for details. There are two options associated with the RPOI directive of which you should be aware. One option determines whether the program issuing the directive exits. The other determines whether RSX Parent-Offspring connections are passed to the target task. Unless there is a good reason to do otherwise, both these bits should be set. The directive itself may be used in two ways according to whether the offspring task has been installed. .SKIP 2 8.2.2.1 Indirect Chaining (to a non-installed task) You may chain to a non-installed task image file indirectly by forming the task image filespec into a pseudo RUN command and then RPOI to either MCR or DCL passing the string as a command. This is how DIBOL and BASIC implement the STOP 'filespec' and CHAIN 'filespec' statements. This form is the most familiar to developers used to working with CTS-300 and RSTS, but it is also the least efficient. This is really a special case of the RUN filespec command and because of the number of intermediate tasks which must become involved it is the slowest form of chain. .SKIP 2 8.2.2.2 Direct Chaining (to an installed task) You may chain directly to an installed task by using the installed task name as the object of the RPOI$ directive. DIBOL supports this form with the CHAINI subroutine. You may pass a command string to the offspring and the performance is much, much better than the indirect chain. .SKIP 2 8.2.2.3 Chaining to a Command File You may chain to a command file by issuing an RPOI$ to the Indirect Command File processor and passing the the name of the command file to be executed. The last action of the command file should be to invoke the next section of your application. .SKIP 2 8.2.3 Spawning an Offspring Task Developers who are moving from CTS-300 or RSTS may, at first, have difficulty understanding the significance of the Spawn facility but it is one of the principal reasons that RSX was chosen as the first operating system for A-to-Z. It is the foundation of the A-to-Z application integration architecture in which commonality of form and function is attained by spawning the appropriate module to perform an operation such as spawning Business Graphics to display some data. It also serves as the mechanism by which otherwise unrelated applications may be nested such that the operator may request an ongoing task to be suspended while another function is performed. That function may also be interrupted and so on. With or without A-to-Z, Spawn allows an application to invoke almost any facility on the system without losing any context other than, possibly, the contents of the screen. You can spawn a system utility with a command to create an ISAM file, for example, and wait for the exit status to determine the success or failure of the operation. You can spawn infrequently used sections of your own code as independent tasks to avoid having to build them into the mainline images. You can spawn the CLI tasks to execute commands as though they were being entered from the keyboard. The possibilities go on and on. Like Chain, Spawn has two forms depending on whether the offspring task is installed or not. .SKIP 2 8.2.3.1 Indirect Spawn (of a non-installed task) You can spawn a non-installed task indirectly by spawning your favorite command line interpreter with a 'RUN Taskname' command. You can include the /COMMAND:"command string" qualifier for the RUN command to pass a command string through to the task. You should also use the /STATUS:TASK qualifier as this assures that the exit status passed back to the parent task is that of the task and not the RUN command itself. Because it carries all the overhead of the RUN command entered from the keyboard, this is the slowest of the two forms of spawn. .SKIP 2 8.2.3.2 Direct Spawn (of an installed task) Direct Spawn of an installed task is the fastest way to invoke an external facility on RSX. You may pass the task a command string and you may wait for exit status. You can spawn more than one offspring task at a time if your implementation language interface to spawn permits. The designer of the parent task is responsible for deciding whether to wait for the offspring task to exit and for correctly interpreting any status which is returned. If task A spawns task B which in turns chains to task C passing all connections and task C exits, the status returned to A is that of C, not B. .SKIP 2 8.3 Parent-Offspring You may choose to create a library of spawnable tasks for your application. These tasks may perform infrequently used functions or they may serve to centralize certain functions as in the case of multiple front end tasks feeding transactions to a single (or multiple) background processor. The two most commonly used means of communication with the parent task are the command line buffer passed from the parent task to the offspring and the status code passed from the offspring back to the parent task. .SKIP 2 8.3.1 Command Line RSX provides for passing a 255 byte command line to any offspring task. The offspring must retrieve this buffer through use of the GMCR$ directive. Access to this directive is available in the more popular implementation languages. This buffer may contain function codes, filenames or any other data in a format agreed upon by the parent and offspring task designers. .SKIP 2 8.3.2 Status Code RSX provides for a task which is Exiting to pass back a 16-bit status code to the parent task. The directive is EXST$ and access to this directive is available in the more popular implementation languages. The low order three bits of this code are defined (by convention) to be the error code and severity level. The remaining bits may be used to communicate any other information in a format agreed upon by the designers of the parent and offspring tasks. A-to-Z has established a convention by which this 16 bit value is divided into fields, each with a particular meaning. You might consider adopting this convention. .SKIP 2 8.4 Intertask Communication RSX provides two principal mechanisms for communicating between tasks running on the system. .SKIP 2 8.4.1 Send/Receive Send and Receive can be used to pass blocks of information between cooperating tasks. The block can consist of up to 500 bytes of information. If more data is to be passed it can be done with multiple blocks or by storing the information in a file and passing the name of the file in a message. A second, more complex mechanism allows passing of a memory common between two tasks. This feature is more complex than most applications require and the memory mapping requirements make its use in commercial applications uncommon. Support for Send Data and Send By Reference varies from one language to another. Some languages provide support through library subroutines while others allow access to the requisite system services. .SKIP 2 8.4.2 Global Event Flags RSX supports a second intertask communication mechanism which is specifically intended for synchronization of task execution. It is possible for a program which has access to system services to define and manipulate event flags on a task, group or system wide basis. Event flags are one bit registers which can be set, cleared or interrogated via system services. Typically one application sets a flag whenever data is available for processing by another. The waiting application clears the flag when all available data has been processed. Support for event flags is limited or non-existent in some languages. It is mentioned here because it is the highest performance intertask signaling mechanism available on RSX.