The following section is intended to give a brief overview of Activation Groups.
Program activation is the process that is used to prepare a program to run. The system must activate ILE programs before they can be run. Program activation includes the allocation and initialization of static storage for the program in addition to completing the binding of programs to service programs. Named activation groups must be used when running persistent CGI.
Program activation is not a unique concept. All modern computer operating systems must perform program initialization and load. What is unique to CGI programs on the iSeries™ server is the concept of Activation Groups. All ILE programs and service programs are activated within an activation group. This substructure contains the resources necessary to run the program. The resources that are contained and are managed with an activation group include:
Run-time creation of ILE activation groups is controlled by specifying an activation group attribute when your program or service program is created. The attribute is specified by using the ACTGRP parameter on the CRTPGM or CRTSRVPGM command. The valid options for this attribute include user-named, *NEW, and *CALLER. The following is a brief description of these options:
For additional information about activation groups see the ILE Concepts ILE Concepts, SC41-5606 book.
There are advantages to running CGI programs in either a user-named or *CALLER activation group. The performance overhead associated with activating a CGI every time that is requested can be drastically reduced. It is important to understand that because the system does not delete user-named activation groups, normal high level language end verbs cannot provide complete end processing. For example, the system will not close open files, and the system will not return the static and heap storage that are allocated by a program. The program must manage these resources explicitly. This will be especially important when changing the activation group of CGI programs that rely on their end processing functions to run properly.
The following section shows examples which will work fine running in a *NEW activation group, however will cause problems if run in a user-named or *CALLER activation group.
In the following example a CGI program when run in a *NEW activation group, would write Hello World to the browser. What is important to understand is that this application is taking advantage of job end processing to delete the stdio buffers that are used to buffer the stdout data.
You could build the following CGI program to run in either a user-named or *CALLER activation group. In such an instance, the server will not process the information that was written to stdout. This will cause the web browser to display a ″Document Contains No Data″ error message. Another application could run again in the same activation group that properly erased stdout. In this instance, the data that has been buffered from previous calls would be sent.
#include <stdio.h> void main(void) { /***************************************************/ /* Write header information. */ /***************************************************/ printf("Content-type: text/html\n\n"); /***************************************************/ /* Write header information. */ /***************************************************/ printf("Hello World\n"); }
End processing may not erase stdio buffers so the application must erase the stdout with a fflush(stdout) call. The following example will work regardless of the activation group specification:
#include <stdio.h> void main(void) { /***************************************************/ /* Write header information. */ /***************************************************/ printf("Content-type: text/html\n\n"); /***************************************************/ /* Write header information. */ /***************************************************/ printf("Hello World\n"); /*-------------------------------------------------*/ /* FIX: Flush stdout. */ /*-------------------------------------------------*/ fflush(stdout); }
When run in a *NEW activation group, this example CGI would read CONTENT_LENGTH bytes of data from stdin and write this back out to stdout. The system has allocated the buffer that is used to hold the data with a malloc. Like the example that is previously shown, this application is relying on several aspects of job end processing to function properly.
If this CGI program were built to run in either a user-named or *CALLER activation group, the following problems would occur:
/*************************************************************************/ /* */ /* CGI Example program. */ /* */ /*************************************************************************/ #include void main(void) { char* stdinBuffer; char* contentLength; int numBytes; int bytesRead; FILE* pStdin; /**********************************************************************/ /* Write the header. */ /**********************************************************************/ printf("Content-type: text/html\n\n"); /**********************************************************************/ /* Get the length of data on stdin. */ /**********************************************************************/ contentLength = getenv("CONTENT_LENGTH"); if (contentLength != NULL) { /*******************************************************************/ /* Allocate storage and clear the storage to hold the data. */ /*******************************************************************/ numBytes = atoi(contentLength); stdinBuffer = (char*)malloc(numBytes+1); if ( stdinBuffer ) memset(stdinBuffer, 0x00, numBytes+1); /*******************************************************************/ /* Read the data from stdin and write back to stdout. */ /*******************************************************************/ bytesRead = fread(stdinBuffer, 1, numBytes, pStdin); stdinBuffer[bytesRead+1] = ’\0’; printf("%s", stdinBuffer); } else printf("Error getting content length\n"); return; }
The following example shows the changes that would be required to this application to allow it to run in a user-named or *CALLER activation group:
/*************************************************************************/ /* */ /* CGI Example program with changes to support user-named */ /* and *CALLER ACTGRP. */ /* */ /*************************************************************************/ #include void main(void) { char* stdinBuffer; char* contentLength; int numBytes; int bytesRead; FILE* pStdin; /**********************************************************************/ /* Write the header. */ /**********************************************************************/ printf("Content-type: text/html\n\n"); /**********************************************************************/ /* Get the length of data on stdin. */ /**********************************************************************/ contentLength = getenv("CONTENT_LENGTH"); if (contentLength != NULL) { /*******************************************************************/ /* Allocate storage and clear the storage to hold the data. */ /*******************************************************************/ numBytes = atoi(contentLength); stdinBuffer = (char*)malloc(numBytes+1); if ( stdinBuffer ) memset(stdinBuffer, 0x00, numBytes+1); /*-----------------------------------------------------------------*/ /* FIX 2: Reset stdin buffers. */ /*-----------------------------------------------------------------*/ pStdin = freopen("", "r", stdin); /*******************************************************************/ /* Read the data from stdin and write back to stdout. */ /*******************************************************************/ bytesRead = fread(stdinBuffer, 1, numBytes, pStdin); stdinBufferþbytesRead+1þ = ’\0’; printf("%s", stdinBuffer); /*-----------------------------------------------------------------*/ /* FIX 3: Free allocated memory. */ /*-----------------------------------------------------------------*/ free(stdinBuffer); } else printf("Error getting content length\n"); /*-------------------------------------------------------------------*/ /* FIX 1: Flush stdout. */ /*-------------------------------------------------------------------*/ fflush(stdout); return; }