Serially reusable programs

A sequence of code that is guaranteed to run to completion before being invoked to accept another input is called serially reusable code. In earlier versions of the z/TPF system, serially reusable code was used within reentrant programs to update shared data. This was reasonable because in a uniprocessing environment, a sequence of code that updates shared data is serially reusable within a single I-stream engine. However, if the code is to remain serially reusable in a multiple I-stream engine environment, then the code can be used by only one I-stream engine at a time. Serially reusable code is a critical region in disguise.

In early versions of the z/TPF system, the system programs were designed on the assumption that all application programs were serviced by a set of system programs that ran on a single I-stream engine (CPU), required very little processing per request, used no I/O, and ran to completion before servicing another application request. In other words, it was assumed that system programs were serially reusable.

Many application programs are reentrant, but not all. Some refer to a shared area of main storage called the global area. The interval of time in which an Entry modifies the global area is not critical in a uniprocessor environment; the attribute of being serially reusable during modifications to the global area is tacitly assumed. This critical region for applications causes problems in a multiprocessing environment. The use of the global area in a multiprocessing environment affects application program interfaces and is related to some rather complex structures for incorporating references to the global area into the application programs.

A serially reusable sequence of code may, in a uniprocessor environment, build data within a program area that is not private or indirectly referenced. However, this same code occasionally fails in a multiprocessing environment when the code is executed simultaneously on more than one I-stream engine. This is caused by updating values in a shared area that can be corrupted by the conflicting demands of separate processes in a multiple I-stream engine environment. In reality, within a multiple I-stream engine environment, a serially reusable program that is designed to run in a uniprocessor environment is no longer guaranteed to run to completion before being reused.

Several techniques apply to both system and application programs and are used within the z/TPF system to overcome the assumptions of serial reusability in the past:
  • Restructure code sequences to be reentrant instead of serially reusable
  • Allow the program to run on all I-stream engines within a z/Architecture configuration, but restrict execution of critical regions to one I-stream engine at a time

    This means that the critical regions of existing code must be identified and controlled by the mechanisms that restrict their execution to one I-stream engine at a time.

  • Restrict the use of serially reusable code to a single I-stream engine (within a z/Architecture configuration)

    This means that within a z/Architecture configuration of multiple I-stream engines, the program can only execute in one I-stream engine. The z/TPF system provides a load balancing mechanism to do this, or the user installation can design its own.

  • Allocate a copy of serially reusable programs to each I-stream engine within a z/Architecture configuration.

    This leads to various forms of interprocessor communication.

The best technique would be a completely new system design and implementation. However, this is an option constrained by the past: preserving application interfaces for loyal customers.