Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!tut.cis.ohio-state.edu!ucbvax!YKTVMH.BITNET!PERSHNG From: PERSHNG@YKTVMH.BITNET ("John A. Pershing Jr.") Newsgroups: comp.lang.asm370 Subject: (none) Message-ID: <8906302128.AA14519@jade.berkeley.edu> Date: 29 Jun 89 13:49:25 GMT Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: IBM 370 Assembly Programming Discussion List Distribution: inet Organization: The Internet Lines: 74 I don't know of any books or manuals that describe how to write modules that are reentrant, refreshable, and/or reusable. I believe that this is the sort of stuff that you have to pick up "on your own". A common misconception is that a module that does not modify itself is reentrant, and vice versa. This is simply wrong -- I can write a fully reentrant module that modifies itself, and can similary write a non-reentrant module that does not modify itself. [An aside for VM bigots: modules that are placed into a DCSS need to be read-only; however, they do not need to be reentrant unless they expect to be runnable under VM/XA on a virtual MP.] The best way to deal with reentrancy is to consider the operation of your module running on a multi-processor (e.g., a 3060 6-way) under a concurrent operating system (e.g., MVS with lots of TCBs and SRBs flying around) -- note that CMS does not qualify here, since it runs on a virtual uni-processor (even though CP itself needs to deal with MPs). Think of your module being entered "simultaneously" by more than one CPU. If you have "static" data areas stuck into your module -- e.g., in the form of DC and DS directives stuck into your main CSECT -- then the various CPUs will be fighting it out for control of these data areas, and confusion will prevail. E.g., CPU-1 will store something in one of the data areas, and CPU-2 will come along and clobber it. Similarly, if you make use of "static" storage at other fixed locations (e.g., in low storage or in common, shared control blocks such as the ASCB or the various CVTs in MVS or the SCB chain in CMS), similar "fights" will break out amongst the various CPUs if your module happens to get "reentered" by CPU-2 before CPU-1 has finished. Reentrancy, in this MP sense, is a "stronger" condition than being recursive -- although they are related. Reentrant modules will, by their very nature, also be recursive. So, how does one write a reentrant module? Well, the registers are safe to use, since each CPU has its own set. Unfortunately, you frequently need more than 16 words of temporary storage. So, you need to explicitly acquire all of the storage that you need by calling the appropriate system service -- e.g., DMSFREE, GETMAIN, GETPOOL, CMSSTOR, whatever. One typically puts all of one's DS directives into a DSECT, start off by issuing a GETMAIN/whatever to allocate enough storage for the size of the DSECT, and then use the USING directive to base the DSECT on the register that you use to point at the storage area that you have allocated. Of course, none of this storage will be initialized, so you have to explicitly clear it or whatever. This is typically referred to as "automatic" storage, from the PL/I lexicon. System macros that generate control blocks come with the MF=L and MF=E forms for use in reentrant programs. The MF=L form will spit out a template of the control block with as many fields initialized as are possible at assembly time. What you typically do is grab some "automatic" storage (either a hunk that you have reserved in your "automatic" DSECT, or a chunk of GETMAIN/whatever storage that you allocate on-the-fly), copy the MF=L template into this storage area, and then call the actual system service using the MF=E form of the macro. It is rather cumbersome, but you get used to it after a while. It also helps to look at the macro expansions, so you can see what is going on. [As an aside, the non-reentrant form of the macro, where you don't specify the MF= parameter, typically generates the control block right in-line with the code. It will "hop" over this control block using a BAL instruction, which conveniently leaves a register (typically R1) pointing at the control block, all ready for issuing the SVC instruction. This in itself doesn't preclude reentrancy; however, the macro invariably stores a couple of things into this control block at run time before issuing the SVC, blowing your chances for reentrancy.] I hope that this has shed *some* light on this rather obscure topic. John A. Pershing Jr. IBM Research, Yorktown Heights