| Exploit Dynamic Program-Storage Management in ILE RPG |
|
|
|
| Programming - RPG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Written by Junlei Li | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Wednesday, 03 February 2010 00:00 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Allocate and free up program storage at run time.
Many i5/OS APIs receive variable-length output parameters. Many i5/OS machine interface (MI) instructions expect variable-length output operands. Many algorithms implemented by user programs need to allocate program storage with unpredictable length until run time. All these facts lead to the need for allocating and freeing program storage at run time.
Here, I will discuss four dynamic program-storage management methods that you can use in ILE RPG.
Dynamically Allocating Automatic Storage by MI Instruction MODASAOn i5/OS, automatic storage supplied to a program is called the "automatic storage stack." Before threads were introduced to i5/OS, the automatic storage stack of a program was allocated based on the program's activation group. After threads were introduced to i5/OS, the automatic storage stack of a program became allocated based on the thread in which the programming is running. There are two automatic storage segments within a thread—one for system-state programs and the other for user-state programs—and the two segments reside, respectively, in the system domain and the user domain. A user program has space addressability to the user-domain automatic storage stack. An interesting example of addressing a program's automatic storage stack is provided in Appendix A, Changing a Caller's Automatic Variables.
Unlike common operating systems, where automatic storage allocation in a procedure is decided at compile time by reserving space on the stack, an i5/OS program can modify (extend or truncate) automatic storage allocation in a certain procedure invocation at run time.
So what's the benefit of using dynamically allocated automatic storage over other run-time storage allocation methods? First, automatic storage is local to a procedure: you can forget it once the control flow leaves the procedure; there's no need to release or re-initialize the allocated automatic storage. Second, automatic storage is a thread-local resource, which means that it needs no synchronization in multi-threaded environments.
The MI instruction Modify Automatic Storage Allocation (MODASA) is responsible for extending and truncating automatic storage in a specific invocation of a procedure. This instruction's bound program access interface (system built-in for HLLs), _MODASA, does not provide the functionality to truncate allocated automatic storage. Here is the prototype of system built-in _MODASA.
_MODASA returns a space pointer addressing the allocated automatic storage. Operand mod_size should be greater than 0 and less than or equal to 16,773,119. When the automatic storage is extended, the extension is aligned on a 16-byte boundary. The extension is not initialized.
Look at this example ILE RPG program, T032, that uses dynamically allocated automatic storage as the receiver operand to MI instruction Materialize Authorized Users (MATAUU). With option hex 32, instruction MATAUU returns privately authorized user profiles to the MI object identified by the object operand. Here's the prototype of system built-in _MATAUU for ILE RPG.
ILE RPG program T032 lists privately authorized user profiles to a given program object.
Notes in code: (1) Allocate 8 bytes for MATAUU's operand 1, and then call MATAUU to retrieve the necessary amount of bytes to allocate. (2) Allocate necessary amount of bytes for MATAUU's operand 1.
To test ILE RPG program T032, you might grant specific authority for a program object to a given user profile and then call T032 and pass the name of the program object. Here's an example:
Managing Heap Storage with ILE CEE APIs or Heap Management MI InstructionsSince heap storage is an activation group-level resource, it is also referred to as "activation group-based heap space storage" in MI documentation provided by IBM. The heap storage for an activation group is accessible by any thread with a program or procedure running in the activation group. A default heap space with heap identifier 0 is automatically available in each activation group. The default heap space is created when the first Allocate Activation Group-Based Heap Space (ALCHSS) instruction is issued against the default heap space. A program can create additional heap spaces in its activation group by issuing MI instruction Create Activation Group-Based Heap Space (CRTHS). The amount of heap space storage that can be allocated for a single heap space is
To illustrate heap space, the following table shows the attributes of an activation group's default heap space and the acceptable values of each heap space attribute.
* The term "page" is defined to mean one or more basic storage units used by the machine to manage memory and DASD. The number of bytes in a page can be determined with option hex 12 of the Materialize Resource Machine Data (MATRMD) instruction. The typical value of 1 page is 4KB (4096).
** If a heap space mark is allowed, marking a heap space allows a subsequent Free Activation Group-Based Heap Space Storage from Mark (FREHSSMK) instruction or ILE CEE API Release Heap (CEERLHP), using the mark identifier returned in operand 1, to free all outstanding allocations that were performed against the heap space since the heap space was marked with that mark identifier. This relieves the user from performing a Free Activation Group-Based Heap Space Storage (FREHSS) instruction or ILE CEE API Free Storage (CEEFRST) for every individual heap space allocation.
The ILE RPG language provides operation codes and built-in functions to operate the default heap space of an activation group.
To gain full control over heap spaces, use ILE CEE heap APIs or heap management MI instructions. The following table lists ILE CEE heap APIs or heap management MI instructions that achieve same functionalities.
For ILE RPG prototypes of heap management MI instructions, please refer to mih52.rpgleinc, ILE RPG header for MI instructions (system built-ins).
There are no real differences in functionality between ILE CEE heap APIs and heap management MI instructions. One can even mix them when working with heap storage.
Please note the following when creating a heap space that is allowed to mark:
Using Teraspace Storage in ILE RPGA teraspace is a large, contiguous, process-local address space of 1TB size. A teraspace is not a space object, which means it cannot be referred to by using a system pointer, but it can be addressed with a space pointer. High-level languages (HLLs)—including ILE RPG, ILE COBOL, and ILE CL—are teraspace-enabled by default.
The following teraspace APIs exported by service program QSYS/QC2UTIL3 can be used to manage teraspace storage in an ILE RPG program.
Here are the prototypes of teraspace APIs extracted from ts.rpgleinc.
The most notable benefit of using teraspace storage might be the large, contiguous address space. Limited by the single-level storage model, you cannot allocate a single contiguous piece of automatic storage or heap storage larger than 16MB. When you really need a contiguous space larger than
Using Thread-Level Global Dynamic Storage via Pthreads Thread-Specific Storage APIsSome i5/OS programmers believe that ILE RPG is not a multi-thread-capable language. It's not accurate to say a programming language is multi-thread-capable or not. Most general-purpose programming languages don't have thread-synchronization-intrinsic primitives. For example, there are no synchronization primitives in C language's or C++ language's keywords. It is the operating system, not a specific programming language, that provides thread capabilities. Microsoft Windows provides thread capabilities to HLLs with thread management APIs such as CreateThread(), and POSIX-confirmed UNIX-like operating systems provide thread capabilities to HLLs with the Pthread library. It is not the duty of a programming language to implement thread support for different target operating systems. A programming language with large and often cross-platform function library or class library support might be an exception. For example, Java provides thread support with a unified interface under different platforms and leaves the complexity of working with platform-specific thread functions to vendors who implement the Java Virtual Machine (JVM) on a specific platform.
In my opinion, it would be more accurate to say that ILE RPG is unaware of multi-threading than to say that ILE RPG is not a multi-thread-capable language. Historically, the RPG compiler leaves a large number of static variables in compiled RPG modules or RPG programs. This makes it more complex to design a procedure or program to be invoked in a multi-threaded environment in ILE RPG than in other programming languages, such as C or C++. But, as an i5/OS HLL, there's no essential difference between ILE RPG and other i5/OS HLLs in terms of managing threads or implementing procedures or programs to run in multi-threaded environments.
In V6R1, a new value, THREAD(*CONCURRENT) was introduced to the THREAD parameter of ILE RPG's control specification. If THREAD(*CONCURRENT) is specified, then multiple threads can run the procedures within the module at the same time and be completely independent of each other. By default, all the static storage in the module will be in thread-local storage, meaning that each thread will have its own copy of the static variables in the module, including compiler-internal variables. But what if we need thread-level dynamically allocated storage that is global to all procedures within an i5/OS thread? The answer is Pthreads thread-specific storage APIs. This set of APIs provides us a mechanism to safely allocate, consume, and free dynamic thread-private storage that is global to all procedures within a thread.
Pthreads Thread-Specific Storage APIs
The i5/OS exposes thread management functions by implementing the POSIX standard for threads (Pthreads). Thread-specific storage APIs are one group of APIs of Pthread APIs.
For ILE RPG prototypes of Pthread thread-specific storage APIs, please refer to pthread.rpgleinc.
Example ILE RPG Program Using Dynamically Allocated Thread-Specific Storage ILE RPG program T038 starts two child threads in its main procedure that use different types of storage in different threads.
Code notes: (1) Call pthread_key_create () to create a thread local storage (TLS) key, passing the procedure pointer to the TLS destructor procedure tls_destructor(). (2) Launch child threads, passing the returned TLS key. (3) Allocate TLS in a specific thread. During the storage allocation process, Pthread APIs pthread_lock_global_np() and pthread_unlock_global_np() are used to synchronize possible race conditions on job-level storage resources, such as activation group-based heap storage or a job's teraspace storage. (4) Call pthread_setspecific() to make the allocated TLS storage visible to all procedures within the current thread. (5) Consume allocated TLS storage in other procedures of the current thread. (6) Once a thread exits, the registered TLS storage destructor procedure will be called to release corresponding TLS storage used by the thread. This example uses MI instruction TESTPTR to test whether the allocated TLS is allocated from a job's teraspace storage or not. (7) Release allocated TLS storage in the TLS storage destructor. Methods of Dynamic Program Storage ManagementI have discussed different methods of dynamic program storage management. Which one you should choose depends on your particular case. For example, if a small piece of procedure-local dynamic storage is needed when implementing a utility service program that would be invoked in multi-threaded environments, dynamically allocated automatic storage would be preferred over other types of dynamic storage.
There are even more methods to make use of dynamic allocated storage on i5/OS—for example, using temporary or permanent space objects or using shared memory APIs declared in <sys/shm.h>. The reason I decided to introduce the above-mentioned methods is that these methods are more convenient and suitable for ILE HLLs such as ILE RPG. AppendicesAppendix A: Changing a Caller's Automatic Variables As mentioned, a user program can address the user-domain automatic storage stack of the current thread by a space pointer. So it is not surprising that one procedure can address its caller procedure's or caller program's automatic storage after obtaining a space pointer to the automatic storage stack of the current thread.
Here are two ILE RPG programs that have been written just for fun. Program T040A calls program T040 from one of its subprocedures, func(), which has automatic data structure tom_sawyer. T040 obtains a space pointer to the current thread's automatic storage by MI instruction Materialize Invocation Attributes (MATINVAT) and then searches for caller program T040A's automatic data structure tom_sawyer and changes its content.
Caller Program T040A
Program T040 Called by T040A
Appendix B: Links and References Fortress Rochester: The Inside Story of the IBM iSeries by Frank G. Soltis, ISBN-13: 978-1583040836
i5/OS V6R1 Programming Languages and programming toolkits
ILE RPG headers provided by the open-source project i5/OS Programmer's Toolkit
For the latest versions of these ILE RPG header files, refer to http://i5toolkit.svn.sourceforge.net/viewvc/i5toolkit/rpg/ or directly check them out by svn from https://i5toolkit.svn.sourceforge.net/svnroot/i5toolkit/rpg.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
View all articles by this author
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Last Updated on Wednesday, 03 February 2010 00:00 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||






You must be logged in to view or make comments on this article.