Welcome to the June, 1994 Issue of the C/370 Newsletter

                  370 370 370 370 370 370 370 370 370 370
              370 370 370 370 370 370 370 370 370 370 370 370
              370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370
         370 370 370
         370 370 370
         370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
         370 370 370 370 370 370 370 370 370 370 370 370 370 370
             370 370 370 370 370 370 370 370 370 370 370 370 370
             370 370 370 370 370 370 370 370 370 370 370 370
                  370 370 370 370 370 370 370 370 370 370


Table of Contents

Welcome to the June, 1994 Issue of the C/370 Newsletter

  • In This Issue
  • Talk to us Electronically
    PERFORMANCE UPDATE
  • Performance Comparison of C/370 V2R2 Library and C/370 V2R1 Library
  • Migrating from C/370 V2R1 Compiler/Library to C/370 Compiler V1.2/Library V2.2
  • AD/C C/370 V1R2 with LE/370 V1R3 vs its predecessor
  • Comparison of the newly released C compiler products
  • Memory Management
    You ask, we answer
    Missed our Previous Editions?
    A word from your editor
    Coming Soon
  • Reader's Comment Form

  • Welcome to the June, 1994 Issue of the C/370 Newsletter

    In This Issue

    ( )

    Talk to us Electronically

    As many of you have requested, we have now instituted an electronic way to talk to the C/370 developers. You can send comments, ask technical questions, and get answers directly from the people who build C/370. Simply send a message to INETC370 @ VNET.IBM.COM for technical support on INTERNET or for those of you on IBMMAIL you can use IBMMAIL(CAIBMRXZ). Don't forget to use the normal IBM ® support channels for defect support. If you want to subscribe to this FREE newsletter, send your name, full mailing address and phone number, in case we have to contact you, to either of these addresses.


    PERFORMANCE UPDATE

    Performance Comparison of C/370 V2R2 Library and C/370 V2R1 Library

    Performance benchmarking of C/370 V2R2 Library showed significant Input/Output performance improvement, when compared to its predecessor, C/370 V2R1 Library. In this case, we relinked all the programs to take advantage of the new library.

    We tested C/370 programs which contained I/O functions exclusively, such as fopen, fclose, fseek, fsetpos, fgetpos, fputc, fread, fwrite, rewind, fputs, and memory file I/O functions running under MVS/ESA (TM). The results showed an average of 20% reduction in CPU time.

    For all tests, CPU time on the same CPU was used as the basis for the benchmarking. Response time was not measured, since response time varies considerably depending on the system workload.

    Migrating from C/370 V2R1 Compiler/Library to C/370 Compiler V1.2/Library V2.2

    The new release of the C compiler, AD/C C/370 V1R2 Compiler, also delivered some performance improvement. Execution of C benchmarks compiled with AD/C C/370 V1R2 Compiler and C/370 V2R2 Library showed a 10% performance improvement when compared to execution of the same applications compiled with C/370 V2R1 Compiler and C/370 V2R1 Library. The benchmark suite that was run included Whetstone, Dhrystone, Towers of Hanoi and the Sieve benchmark.

    AD/C C/370 V1R2 with LE/370 V1R3 vs its predecessor

    Similar I/O performance improvements resulted in running the C I/O performance benchmarks (described above) with AD/C C/370 V1R2 using LE/370 V1R3, instead of AD/C C/370 V1R1 using LE/370 V1R2. The programs were recompiled and relinked.

    Comparison of the newly released C compiler products

    Execution time performance of C applications compiled using AD/C C/370 V1R2 and LE/370 V1R3 is comparable to the execution time performance of the same C applications compiled using AD/C C/370 V1R2 Compiler and C/370 V2R2 Library.

    Please keep in mind that these performance improvements were measured using our own programs and programs from various performance standards organizations. Your programs' performance improvement may vary from our results. We encourage you to do your own benchmarking.


    Memory Management

    If you have ever had an error with overwriting malloc'ed storage, the following may be of interest. Read on to see how to use debuggable versions of malloc/calloc/realloc and free. If you would like an "as-is" softcopy version of this code send a note to IBMMAIL(CAIBMRXZ) or INETC370 @ VNET.IBM.COM.

    Here are some macros you can tailor.


    #ifndef __STORAGE__
      #define __STORAGE__
    
      #define PADDING_SIZE         4    /* amount of padding around   */
                                        /* allocated storage          */
      #define PADDING_BYTE      0xFE    /* special value to initialize*/
                                        /* padding to                 */
      #define HEAP_INIT_SIZE    4096    /* get 4K to start with       */
      #define HEAP_INCR_SIZE    4096    /* get 4K increments          */
      #define HEAP_OPTS           72    /* HEAP(,,ANYWHERE,FREE)      */
    
      extern int heapVerbose;           /* If 0, heap allocation and  */
                                        /* free messages will be      */
                                        /* suppressed, otherwise, they*/
                                        /* will be displayed          */
    #endif
    


    /*
     * STORAGE:
     *
     * EXTERNALS:
     *
     *  This file contains code for the following functions:
     *   -malloc......allocate storage from an LE/370 heap
     *   -calloc......allocate storage from an LE/370 heap and initialize
     *                it to 0.
     *   -free........free storage previously allocated by malloc in this
     *                file.
     *   -realloc.....re-allocate storage previously allocated by malloc in
     *                this file. If a NULL pointer is passed instead of a
     *                previously allocated pointer, malloc will be called
     *                directly.
     *
     * USAGE:
     *
     *  To use this code, compile with no special options (although the
     *  TEST option is useful so that the trace back will give
     *  additional information - line number information and the type and
     *  values of variables will be dumped in a trace back for all
     *  files compiled with TEST).
     *  Prelink (or link) this text deck with your text decks (make sure
     *  you explicitly link this text deck - avoid using autocall since
     *  you might get the C/370 version of malloc/free/realloc).
     *
     * INTERNALS:
     *
     *  General Algorithm:
     *
     *  When storage is allocated, extra 'padding' is allocated at the
     *  start and end of the actual storage allocated for the user.
     *  This padding is then initialized to a special pad value. If the
     *  user's code is functioning correctly, the padding should not
     *  have been changed when it comes time to free the storage. If the
     *  free() routine finds that the padding does not have the correct
     *  value, the storage about to be freed is dumped and a trace back
     *  is issued, and then the storage is dumped, as usual.
     *  The padding size and padding byte value can be modified to suit
     *  your needs. Update the include file "storage.h" if you want
     *  to modify these values.
     *  Here is a diagram of how storage is allocated (assume that the
     *  pad value is xFE, the padding size is 4 bytes and 8 bytes of
     *  storage were requested):
    
     *
     *  Length of      Padding        Allocated storage          Padding
     *   storage          |            returned to user             |
     *      |             |                     |                   |
     * +----+------+ +----+------+ +------------+------------+ +----+-----+
     * |           | |           | |                         | |          |
     *+--------------------------------------------------------------------+
     *| 00 00 00 10 | FE FE FE FE | xx xx xx xx | xx xx xx xx | FE FE FE FE|
     *+--------------------------------------------------------------------+
     *
    
     *  (Values above shown in hexadecimal)
     *
     *  This method is fairly effective in tracking down storage
     *  allocation problems. Also, code does not have
     *  to be recompiled to use these routines - it just has to be
     *  relinked. Note that it is not guaranteed to find all storage
     *  allocation errors - if you overwrite the padding with the
     *  same value it had before, or you overwrite more storage than
     *  you had padding for, you will still have problems.
     *
     *  This code uses the LE/370 heap services to allocate, re-allocate
     *  and free storage. A User Heap is used instead of the library
     *  heap so that if the heap gets corrupted, the standard library
     *  services that themselves use the heap won't be affected (i.e.
     *  if the user heap is damaged, a call to a library function
     *  such as printf should still succeed).
     *
     *  Notes of interest:
     *   o The runtime option STORAGE is very useful for tracking down
     *     random pointer problems - it initializes heap and/or stack frame
     *     storage to a particular value.
     *   o The runtime option RPTSTG(ON) is useful for improving heap and
     *     stack frame allocation - it generates a report indicating how
     *     stack and heap storage was managed for a given program.
     */
    #include "storage.h"
    #include <leawi.h>
    #include <stdio.h>
    
    /*
     * heapVerbose: external variable that controls whether heap
     *              allocation and free messages are displayed.
     */
    int heapVerbose=1;
    
    /*
     * mallocHeapID: static variable that is the Heap ID used for allocating
     *               storage via malloc(). On the first call to malloc(),
     *               a Heap will be created and this Heap ID will be set.
     *               All subsequent calls to malloc will use this Heap ID.
     */
    static _INT4 mallocHeapID=0;
    
    /*
     * CHARS_PER_LINE/BYTES_PER_LINE: Used by dump() and DumpLine()
     *                                to control the width of a storage dump.
     */
    #define CHARS_PER_LINE           40
    #define BYTES_PER_LINE           16
    
    /*
     * align: Given a value and the alignment desired (in bits), round
     *        the value to the next largest alignment, unless it is
     *        already aligned, in which case, just return the value passed.
     */
    #pragma inline(align)
    static int align(int value, int shift) {
      int alignment = (0x1 << shift);
    
      if (value % alignment) {
        return(((value >> shift) << shift) + alignment);
      }
      else {
        return(value);
      }
    }
    
    /*
     * padding: given a buffer (address and length), return 1 if the
     *          entire buffer consists of the pad character specified,
     *          otherwise return 0.
     */
    #pragma inline(padding)
    static int padding(const char* buffer, long size, int pad) {
      int i;
      for (i=0;i<size;++i) {
        if (buffer[i] != pad) return(0);
      }
      return(1);
    }
    
    /*
     * CEECmp: Given two feedback codes, return 0 if they have the same
     *         message number and facility id, otherwise return 1.
     */
    #pragma inline(CEECmp)
    static int CEECmp(_FEEDBACK* fc1, _FEEDBACK* fc2) {
    
      if (fc1->tok_msgno == fc2->tok_msgno &&
          !memcmp(fc1->tok_facid, fc2->tok_facid,
                  sizeof(fc1->tok_facid))) {
        return(0);
      }
      else {
        return(1);
      }
    }
    
    /*
     * CEEOk: Given a feedback code, return 1 if it compares the same to
     *        condition code CEE000.
     */
    #pragma inline(CEEOk)
    static int CEEOk(_FEEDBACK* fc) {
      _FEEDBACK CEE000 = { 0, 0, 0, 0, 0, {0,0,0}, 0 };
    
      return(CEECmp(fc, &CEE000) == 0);
    }
    
    /*
     * CEEErr: Given a title string and a feedback code, print the
     *         title to stderr, then print the message associated
     *         with the feedback code. If the feedback code message can't
     *         be printed out, print out the message number and severity.
     */
    static void CEEErr(const char* title, _FEEDBACK* fc) {
      _FEEDBACK msgFC;
      _INT4 dest = 2;
    
      fprintf(stderr, "\n%s\n", title);
      CEEMSG(fc, &dest, &msgFC);
      if (!CEEOk(&msgFC)) {
        fprintf(stderr, "Message number:%d with severity %d occurred\n",
                fc->tok_msgno, fc->tok_sev);
      }
    }
    
    /*
     * DumpLine: Dump out a buffer (address and length) to stderr.
     */
    static void DumpLine(char* address, int length) {
      int i, c, charCount=0;
    
      if (length % 4) length += 4;
    
      fprintf(stderr, "%8.8p: ", address);
      for (i=0; i < length/4; ++i) {
        fprintf(stderr, "%8.8X ", ((int*)address)[i]);
        charCount += 9;
      }
      for (i=charCount; i < CHARS_PER_LINE; ++i) {
        putc(' ', stderr);
      }
      fprintf(stderr, "| ");
      for (i=0; i < length; ++i) {
        c = address[i];
        c = (isprint(c) ? c : '.');
        fprintf(stderr, "%c", c);
      }
      fprintf(stderr, "\n");
    }
    
    /*
     * dump: dump out a buffer (address and length) to stderr by dumping out
     *       a line at a time (DumpLine), until the buffer is written out.
     */
    static void dump(void* generalAddress, int length) {
      int curr = 0;
      char* address = (char*) generalAddress;
    
      while (&address[curr] < &address length-BYTES_PER_LINE ) {
        DumpLine(&address[curr], BYTES_PER_LINE);
        curr += BYTES_PER_LINE;
      }
      if (curr < length) {
        DumpLine(&address[curr], length-curr);
      }
    }
    
    /*
     * malloc: Create a heap if necessary by calling CEECRHP. This only
     *         needs to be done on the first call to malloc(). Verify
     *         that the heap creation was ok. If it wasn't, issue an
     *         error message and return a NULL pointer.
     *         Write a message to stderr indicating how many bytes
     *         are about to be allocated.
     *         Call CEEGTST to allocate the storage requested plus
     *         additional padding to be placed at the start and end
     *         of the allocated storage. Verify that the storage allocation
     *         was successful. If it wasn't, issue an error message and
     *         return a NULL pointer.
     *         Write a message to stderr indicating the address of the
     *         allocated storage.
     *         Initialize the padding to the value of PADDING_BYTE, so that
     *         free() will be able to test that the padding was not changed.
     *         Return the address of the allocated storage (starting after
     *         the padding bytes).
     */
    void* malloc(long initSize) {
      _FEEDBACK fc;
      _POINTER address=0;
      long totSize;
      long* lenPtr;
      char* msg;
      char* start;
      char* end;
    
      if (!mallocHeapID) {
        _INT4 heapSize = HEAP_INIT_SIZE;
        _INT4 heapInc  = HEAP_INCR_SIZE;
        _INT4 opts     = HEAP_OPTS;
    
        CEECRHP(&mallocHeapID, &heapSize, &heapInc, &opts, &fc);
        if (!CEEOk(&fc)) {
          CEEErr("Heap creation failed", &fc);
          return(0);
        }
      }
      if (heapVerbose) {
        fprintf(stderr, "Allocate %d bytes", initSize);
      }
      /*
       * Add the padding size to the total size, then round up to the
       * nearest double word
       */
      totSize  = initSize + (PADDING_SIZE*2) + sizeof(long);
      totSize  = align(totSize, 3);
    
      CEEGTST(&mallocHeapID, &totSize, &address, &fc);
      if (!CEEOk(&fc)) {
        msg = "Storage request failed";
        CEEErr(msg, &fc);
        __ctrace(msg);
    
        return(0);
      }
    
      lenPtr = (long*) address;
      *lenPtr= initSize;
      start  = ((char*) address) + sizeof(long);
      end    = start + initSize + PADDING_SIZE;
    
      memset(start, PADDING_BYTE, PADDING_SIZE);
      memset(end,   PADDING_BYTE, PADDING_SIZE);
    
      if (heapVerbose) {
        fprintf(stderr, " starting at address %p\n", address);
      }
    
      return(start + PADDING_SIZE);
    }
    
    /*
     * calloc: Call malloc() to allocate the requested amount of storage.
     *         If the allocation was successful, initialize the allocated
     *         storage to 0.
     *         Return the address of the allocated storage (or a NULL
     *         pointer if malloc returned a NULL pointer).
     */
    void* calloc(long initSize) {
      void* ptr;
    
      ptr = malloc(initSize);
      if (ptr) {
        memset(ptr, 0, initSize);
      }
      return(ptr);
    }
    /*
     * realloc: If a NULL pointer is passed, call malloc() directly.
     *          Call CEECZST to re-allocate the storage requested plus
     *          additional padding to be placed at the start and end
     *          of the allocated storage.
     *          Verify that the storage re-allocation was ok. If it wasn't,
     *          issue an error message, dump the storage, and return a NULL
     *          pointer.
     *          Write a message to stderr indicating the address of the
     *          re-allocated storage.
     *          Initialize the padding to the value of PADDING_BYTE, so
     *          that free() will be able to test that the padding was not
     *          changed. Note that the padding at the start of the storage
     *          does not need to be allocated, since it was already
     *          initialized by an earlier call to malloc().
     *          Return the address of the re-allocated storage (starting
     *          after the padding bytes).
     */
    void* realloc(char* ptr, long initSize) {
      _FEEDBACK fc;
      _POINTER address = (ptr - sizeof(long) - PADDING_SIZE);
      long oldSize;
      long* lenPtr;
      char* start;
      char* end;
      char* msg;
      long newSize = initSize;
    
      if (ptr == 0) {
        return(malloc(newSize));
      }
    
      oldSize = *((long*) address);
    
      if (heapVerbose) {
        fprintf(stderr, "Re-allocate %d bytes from address %p to ",
                newSize, address);
      }
    
      /*
       * Add the padding size to the total size, then round up to the
       * nearest double word
       */
      newSize += (PADDING_SIZE*2) + sizeof(long);
      newSize  = align(newSize, 3);
      CEECZST(&address, &newSize, &fc);
      if (!CEEOk(&fc)) {
        msg = "Storage re-allocation failed";
    
        CEEErr(msg, &fc);
        dump(address, oldSize + (PADDING_SIZE*2) + sizeof(long));
        __ctrace(msg);
        return(0);
      }
    
      lenPtr = (long*) address;
      *lenPtr= initSize;
      start  = ((char*) address) + sizeof(long);
      end    = start + initSize + PADDING_SIZE;
    
      memset(end, PADDING_BYTE, PADDING_SIZE);
    
      if (heapVerbose) {
        fprintf(stderr, "address %p\n", address);
      }
    
      return(start + PADDING_SIZE);
    }
    /*
     * free: Calculate where the start and end of the originally
     *       allocated storage was. The start will be different than the
     *       address passed in because the address passed in points after
     *       the padding bytes added by malloc() or realloc().
     *       Write a message to stderr indicating what address is about
     *       to be freed.
     *       Verify that the start and end padding bytes have the original
     *       padding value. If they don't, dump out the originally
     *       allocated storage and issue a trace.
     *       Free the storage by calling CEEFRST. If the storage free
     *       fails, dump out the storage and issue a trace.
     */
    void free(char* ptr) {
      _FEEDBACK fc;
      _POINTER address=(void*) (ptr - sizeof(long) - PADDING_SIZE);
      char* start;
      char* end;
      long size;
      long* lenPtr;
      char* msg;
    
      lenPtr = (long*) address;
      size   = *lenPtr;
      start  = ((char*) address) + sizeof(long);
      end    = start + size + PADDING_SIZE;
    
      if (heapVerbose) {
        fprintf(stderr, "Free address %p\n", address);
      }
      if (!padding(start, PADDING_SIZE, PADDING_BYTE) ||
          !padding(end, PADDING_SIZE, PADDING_BYTE)) {
    
        dump(address, size + (PADDING_SIZE*2) + sizeof(long));
        msg = "Padding overwritten";
        __ctrace(msg);
      }
      else {
        CEEFRST(&address, &fc);
        if (!CEEOk(&fc)) {
          msg = "Storage free failed";
    
          CEEErr(msg, &fc);
          dump(address, size + (PADDING_SIZE*2) + sizeof(long));
          __ctrace(msg);
        }
      }
    }
    


    You ask, we answer

    These questions are culled from a variety of sources: from various question and answer databases, from customer calls, and from our own experiences. If you have a question you'd like answered, please send it to IBMMAIL(CAIBMRXZ) or INETC370 @ VNET.IBM.COM.

    Question- C.Runtime Library Abends

    A question has come up about why we sometimes get a U4012 abend from the C/370 V2 runtime library and other times will get S80A or S878... Can you clarify when/why we get different abends and the exact circumstances that would cause each one to be generated?

    Answer

    The error codes mentioned in your question all deal with insufficient memory. When the memory is requested by the C/370 library code, the insufficient memory condition is handled by the library which issues U4012 return code. If the memory is requested by a system routine for its own use, the system does not return to the invoker, but issues a return code S80A or S878 and abends.

    Question- Carriage Return escape sequence

    Are the escape sequences, ie \r, defined in a header file? If so which file?

    Answer

    '\r' (carriage return) is a special escape sequence character. It is interpreted as "moves the active position to the initial position of the current line". It is NOT defined in header file. It is understood by both the C compiler and the C library.

    Question- System Function

    I am attempting to use a SYSTEM function within a C/370 environment to call another C/370 program. The called program executes successfully. However, the calling program does not continue execution until the called program has completed execution. I have not experienced this with other C implementations (ie. C++ on OS/2 ® or UNIX). The question is this working as designed? Does a calling program have to wait until a called program completes execution before it can continue? If this is the case, how can it be avoided? It is desired that the calling program continue processing, ie. does not wait, while the called program is executing. Appreciate the help in getting these questions answered.

    Answer

    The C/370 implementation of the system() function is similar to a call in that the issuing program waits for the function to complete before it can proceed. I would suggest using the C/370 Multitasking Facility which is described in the C/370 Programming Guide SC09-1384 page 421-452.

    Question- Execution Time Analyzers

    Both the C/370 V2R1 and the AD/Cycle ® R1.1 programming guides have a footnote about using "available execution time analyzers" in their discussions concerning Inlining functions.

    Can you give us some more information/pointers to such programs and their availability?

    Answer

    OMEGAMON ® from Candle can monitor CICS (TM)/DB2 (TM) /IMS/DBCTl. For a C transaction, OMEGAMON can help find bugs, bottlenecks, etc. CODE/370 can measure how many times a statement or verb has been processed. Batch Terminal Simulator from IBM has a trace facility for IMS calls. DB2PM does the same thing for DB2/SQL trace. PPE from Boole and Babbage can also be used, but it is only available for MVS.

    Question- Inlining

    We have a load module that is built from 6 object modules. If we have a subroutine (transl()) that we wish to INLINE in all 6 object modules, what do we do?

    From the manual, it appears the we need to add either #pragma inline(transl) or #pragma inline(transl()) in the source module containing transl() and compile all sources with the compile option INLINE(NOAUTO).

    Does the pre-linker/linker then substitute the actual code of the transl() function for all the invocations of it?

    Answer

    Inlining is a compiler feature, not a link-edit feature. A function to be inlined must appear in the source file being compiled. To ensure this, the function can be coded in a header file that is then included in each source file that invokes the function. Inline pragma should be also coded in the header file. The correct syntax is: #pragma inline(transl). The compile time option INLINE(NOAUTO) should also be specified.

    Question- MVS/ESA V5.1

    Is my understanding correct in that MVS/ESA V5.1 INCLUDES AD/Cycle LE/370?

    Answer

    MVS/ESA 5.1 has a no charge feature, OpenEdition (TM) AD/Cycle Support Feature, which are shipped as 3 FMIDs on MVS/ESA 5.1. These FMIDs provide the AD/Cycle C/370 Run-time Library component, the CEL (Common Execution Language interface) from AD/Cycle LE/370 V1.3 and the National Language Resources (locale and codepage data) and provides the run-time library support needed by the OpenEdition functions available in MVS/ESA 5.1. If you only need AD/Cycle LE/370 for the C/370 environment, then you don't need a separate license for the AD/Cycle LE/370 program product. This applies to all LE/370-enabled C applications on MVS OpenEdition or otherwise. If you require AD/Cycle LE/370 to support COBOL and PL/I then you will need a AD/Cycle LE/370 license. ( )

    Question- New C/370 Compiler Questions

    I have the following questions concerning the recent AD/Cycle C/370 Compiler V1.2 announcement when being used with the C/370 V2.2 Library:

    1. Have the subpools for STACK and HEAP changed from the previous subpool 1 non-shared for STACK and subpool 4 non-shared for HEAP?

    2. Has storage management changed? Still in EDCXV and use the same scheme? Internal control block changed?

    3. Do you still use a TCA for each task?

    Answer

    1. We have not changed the subpools for STACK and HEAP.

    2. The common library is still used in V2.2, so the storage management is the same, but some internal control blocks have changed.

    3. There is no change in the use of TCA.

    Question- C Set++ (TM) V2.1

    I am running C Set++ V2.1. I was told that there is a level of C/370 for MVS that is compatible with C Set++ V2.1. What MVS version of C/370 is compatible with C Set++ V2.1?

    Answer

    Either the C/370 V2R1, AD/Cycle C/370 R1 or the recently announced R2 levels of the C/370 compiler support the same ANSI C language definition. There are OS/2 unique and MVS unique features and functions in each of C Set++ and C/370. The programmer can code to the ANSI standard. It is also advisable to isolate your platform unique functions into separate modules to reduce the porting efforts.

    Question- COBOL TO C/370 DYNAMIC CALL

    I need to incorporate existing C functions into my COBOL environment. I also have a requirement that the C functions must be invoked dynamically.

    I have read and understand the interlanguage issues documented on page 330 of the C/370 Programming Guide (SC09-1384-00).

    I want to avoid using the method of dynamically calling a COBOL stub which in turn invokes the statically linked c functions. They have performance concerns with using this method since the c environment will repeatedly be established and terminated when the COBOL stub returns (is this true ????).

    The way I implemented a dynamic call interface is to have a COBOL main statically calls a c stub and the c stub issues a fetch() for the "real" c function and then calls the function.

    This seems to satisfy the requirement that the C environment must be invoked statically from COBOL and provides the dynamic interface they want without the extra COBOL stub layer. Are there any potential problems in using this method ????

    Answer

    The C environment will be repeatedly established and terminated only if no C function is called directly from the COBOL mainline. If on the other hand, a dummy C routine is called from the COBOL mainline the C environment will be preserved until the mainline terminates, and will not be repeatedly established and terminated for each invocation of C functions called from dynamically called COBOL stubs. The method used is fine, but it appears to be somewhat restrictive in that it only allows fetching C routines from the COBOL mainline routine. Once the COBOL statically calls a C stub, any COBOL subroutine can statically call C stubs that fetch and execute "real" C functions.

    Question- C/370 and AD/CYCLE C/370 RESTRICTIONS FOR CICS

    In the description for C/370 there are some restrictions listed for executing in a CICS environment. - interlanguage call - multitasking - INSPECT - dynamic loading of modules - native language interface to CICS

    These restrictions are not mentioned in the description for SAA AD/CYCLE C/370 or LE/370. I assume that some of them still exist, but am not sure. Can you tell me they are still restrictions?

    Answer

    Some restrictions have been lifted in AD/Cycle versions of C/370, but most restrictions still exist. In particular interlanguage call (COBOL) is now supported, as is the case with dynamic loading of modules using fetch function. Instead of INSPECT, CODE/370 is provided for AD/Cycle versions of C/370, and it is supported under CICS. Functions cdump, csnap, ctest, and ctrace are also supported. All other restrictions still apply, and are described in the C/370 Programming Guide SC09-1356 on page 192.

    Question- Redirection Message

    I have an Assembler routine which uses ATTACH for a PLI and a C/370 program. There is a common work area in the assembler routine, which is used by both the PLI and C/370 programs.

    The PLI program has AMODE=24, RMODE=24. The C/370 program has AMODE=31, RMODE=ANY. Due to the common workarea, the Assembler program has AMODE=31, RMODE=24.

    When the program starts to run, the SYSPRINT listing contains the message: "Program not run due to redirection error." No error message id is provided. This error is being issued for the C/370 program.

    We suspect that this error may have something to do with the C/370 being in 31 bit mode and using a common workarea below the 16 MB line. We would appreciate assistance in understanding what the redirection error message is really trying to tell us.

    Answer

    The redirection message is issued when an error is encountered while trying to parse the arguments from the command line. Try running the C/370 program by itself, passing the same arguments as when it is attached. There is a possibility that the arguments being passed are incorrect, or that the argument list is not properly packaged for the attach macro.

    Question- Proper use of SETLOCALE

    Could someone help me with the proper use of the SETLOCALE parameter? My program was calculating the correct local time. After a PTF was installed, the local time that was calculated came out as GMT time(local time +7 hours). I have since discovered that the program needed the SETLOCALE parameter but we're having trouble coding it correctly since it still calculates local time. Any recommendation will be greatly appreciated. Here's the source that we're using:

    #include <stdio.h>
    #include <stdefs.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <locale.h>
    int    main(int, char**);
    
    int    main(argc, argv)
    int    argc;
    char  *argv [ ];
    {
        char         *tstring;
        time_t        lt;
    
        time(<);
        printf("time is: %s\n", ctime(<) );
    
        tstring = setlocale(LC_ALL, LC_C_USA);
        if (tstring != NULL)
          printf(" %s \n", tstring);
    
        time(<);
        printf("time is: %s\n", ctime(<) );
    
        tstring = setlocale(LC_ALL, LC_C_FRANCE);
        if (tstring != NULL)
          printf(" %s \n", tstring);
    
        time(<);
        printf("time is: %s\n", ctime(<) );
    
        exit(0);
    }
    

    Answer

    There is nothing wrong with the way you are coding your setlocale(). The problem is in the locale objects that are in the SEDCLINK library (e.g. EDC$USA, EDC$FRAN). If you don't customize the locales, you will by default be getting UTC (aka GMT) time. This is due to the change in behavior necessitated by the APAR fix in PTF UN55807. Included below is the EDC$USA locale source customized for the Eastern time zone. You can refer to this example or to the C/370 Programming Guide to learn how to customize a locale. The source of the locales delivered as part of the C/370 run-time library are located in the SEDCLOCL library. Once you customize a locale, you should compile and link-edit, and concatenate it to the STEPLIB, or install it in the LPA, or if you are on VM, put it in the DCSS.

             PRINT ON,GEN
    EDC$USA  EDCLOC  CHARTYP=2,CTYPE=,CTYPE1=,UPPER=,LOWER=,COLLTAB=,      *
                   COLLSTR=,DEC='.',SEP=,GROUP=(0,0),ICURR=,CURR=,         *
                   MDEC=,MSEP=,MPLUS=,MMINUS=,                             *
                   MIFDIGITS=CHAR_MAX,                                     *
                   MFDIGITS=CHAR_MAX,MGROUP=(0,0),MPCSP=CHAR_MAX,          *
                   MPSBYS=CHAR_MAX,MNCSP=CHAR_MAX,MNSBS=CHAR_MAX,          *
                   MPLUSPOS=CHAR_MAX,MMINUSPOS=CHAR_MAX,                   *
                   SDAYS=(Sun,Mon,Tue,Wed,Thu,Fri,Sat),                    *
                   LDAYS=(Sunday,Monday,Tuesday,Wednesday,Thursday,        *
                   Friday,Saturday),                                       *
                   SMONS=(Jan,Feb,Mar,Apr,May,Jun,                         *
                   Jul,Aug,Sep,Oct,Nov,Dec),                               *
                   LMONS=(January,February,March,April,May,June,           *
                   July,August,September,October,November,December),       *
                   DATFMT='%m/%d/%y',TIMFMT='%I:%M:%S',AM='AM',PM='PM',    *
                   DATTIM='%y/%m/%d %X',                                   *
                   TZDIFF=300,TNAME='EST',                                 *
                   DSTSTM=4,DSTSTW=1,DSTSTD=0,STARTTM=0,SHIFT=3600,        *
                   DSTENM=10,DSTENW=-1,DSTEND=0,ENDTM=0,DSTNAME='DST',     *
                   VERSION=1
             END
    

    Question- Reading PL/1 DECIMAL FIXED from C/370

    I have to write some C/370 code that will read a PL/1 DECIMAL FIXED(n,m) data type. This seems to have no obvious analogue in C but from its description looks to be stored as something very close to BCD (binary coded decimal) with a rightmost sign nybble. Before I sit down and do this from scratch, can anyone point me to some C code that reads/writes FIXED DECIMAL data? If it gives you any further clues, this is data stored in a DB2 table. Any help would be appreciated. Thanks in advance.

    Answer

    As of release 1.3 of LE/370 (GA'ed April of this year) you can manipulate packed decimal data directly from C/370 code. You need the NEW switchable AD/Cycle C/370 compiler in order to compile your C code.

    Question- Memory Allocatons

    I'm trying to understand what buffer allocations (either above or below the 16MB line) that may be taking place when I execute my applications.

    I am running V2R1M00 of the IBM C/370 compiler. I have several MVS tasks which use the EDCXHOTL macro to set up persistent C environments. On this macro I specify that a 4096 byte stack be obtained and I specify a '1' (indicating that the stack be allocated above the line). Also, since I don't specify any HEAP options, I believe I am running with the default (4k,4k,ANY,FREE) parameters. Is that right? If I issue a malloc for an 8k buffer will this obtain the buffer above the line??

    We ran into a case where we received a U2100 ABEND (out of storage). We know at the time of the abend, we were out of space BELOW the 16 MB line. I'm trying to understand if the U2100 ABEND was due to one of my mallocs (shouldn't it try and get space above the line?) or due to some other unknown buffer request. Any suggestions as to how I might be able to determine which call caused the U2100??

    Based on the programmer's guide, I believe I can not run the REPORT runtime option. Did I interpret the document correctly? Is there an alternative way to obtain the REPORT information.

    Answer

    Your assumptions about the HEAP parameter are correct, you will by default get HEAP(4K,4K,ANY,FREE). However, if you are running below the 16M line, the heap will be allocated below the line even though you have ANY in the option. Even if you are running above the line, the heap will be allocated below the line if there is not enough memory above the line.

    You are also correct about the REPORT option not being available in SPC environment. I would suggest that you verify in your program that malloc() returns a valid pointer, and print the value of the pointer. You can tell by the value of the pointer if it points below or above the line. If the pointer returned by malloc() is NULL then you know that the memory allocation was not successful.

    Question- STACK Runtime Option

    In the C/370 Users Guide SC09-1264 it states that the STACK runtime option on PRAGMA only has an effect in CICS runtime environment. I am running batch. Is there an effect for batch? What is the default for stack in the batch environment?

    Answer

    Under C/370 1.2, STACK has effect in CICS only. Under C/370 2.1, 2.2, or LE/370, STACK has effect everywhere. Instead you can use: (default outside CICS, ie. also apply in Batch)

      ISASIZE - default is 0, get as much storage as poss < 16M
                and return half
      ISAINC  - default is 0, so it will use the requested size
                For 1.2, the stack is always below the line.
    

    Question- MTF feature of C/370

    The main program below issues the TINIT, TSCHED, TSYNCRO, and TTERM but the MTF subtask Ftpproc never executes. Why?

    /* #pragma runopts(NOSPIE, NOSTAE)   */
    /* pragma linkage(TEST04, OS)   */
    #define MVS
    #include <stdlib.h>
    #include <errno.h>
    #include <mtf.h>
    #include <ctest.h>
    #include <dynit.h>
    #include <stdio.h>.../* System screen and I/O definitions.*/
    int main(void) {
      int s, namelen, client_address_size;
      int ns, ls, trc, trs, try;
        for(;;) {
          namelen = sizeof(client);
          if ((ns = accept(s, &client,&namelen)) == 1) {
           tcperror("Accept()");
           exit(-1);
          }
          trc=tinit("UUFTP", 2);
          if(trc != 0) {
               printf("tinit  error %d\n", trc);
          }
          trs=tsched(MTF_ANY,"UUFTP");
          if(trs != 0) {
               printf("tsched error %d\n", trs);
          }
          tsyncro(MTF_ALL);
          if(try != 0) {
               printf("tinit  error %d\n", try);
          }
          tterm();
        }
     }
    
    #define MVS
    #include <stdlib.h>
    #include <stdio.h>
      FILE *fp;
    void Ftpproc() {
      char buf[80] ="HELLO WORLD HAVE A GOOD ONE ";
      printf("Hello world \n");
      fflush(NULL);
      fp = fopen("dd:STDOUT02", "wb,type=record");   fwrite(&buf, 1, 80, fp);   close(fp);   } 

    Answer

    During testing we found that the function "tsched" has called the module name (UUFTP) instead of the function name (FTpproc) which caused the problem. We have attached the two modified programs as reference. If you still have problems, it's probably because of the linking. Make sure you have included the following linkage editor control statements and linked correctly:

            INCLUDE SYSLIB(EDMTFS)
            ENTRY CEESTART
    
    /* #pragma runopts(NOSPIE, NOSTAE)   */
    /* pragma linkage(TEST04, OS)   */
    #define MVS
    #include <stdlib.h>
    #include <errno.h>
    #include <mtf.h>
    #include <ctest.h>
    #include <dynit.h>
    #include <stdio.h>    /* System screen and I/O definitions.*/
    int main(void) {
      int s, namelen, client_address_size;
      int ns, ls, trc, trs, try;
        for(;;) {
          trc=tinit("UUFTP", 2);/*UUFTP is the name of the load
                                  module containing function
                                  that is going to be scheduled*/
          if(trc != 0) {
               printf("tinit  error %d\n", trc);
             }
          trs=tsched(MTF_ANY,"Ftpproc");/*Ftpproc is the name of
                                        the function in UUFTP
                                        that is being scheduled*/
          if(trs != 0) {
               printf("tsched error %d\n", trs);
             }
          tsyncro(MTF_ALL);
          if(try != 0) {
               printf("tsynchro error %d\n", try);
             }
          tterm();
        }
     }
    
    #define MVS
    #include <stdlib.h>
    #include <stdio.h>
      FILE *fp;
    void Ftpproc() {
      char buf[80] ="HELLO WORLD HAVE A GOOD ONE ";
      printf("Hello world \n");
      fflush(NULL);
      fp = fopen("dd:STDOUT02", "wb,type=record");   fwrite(&buf, 1, 80, fp);   } 

    Question- Memory Allocation on MVS

    I am running MVS/ESA 4.3, using DB2, and writing my application in C/370 Version 2. I need to understand how the memory allocation for C programs on MVS works. I reviewed the C/370 programming Guide, and Users guide to review the HEAP, ISASIZE, and STACK parameter's.

    1. Are there any other manuals that give more detail on how to use these memory management parameters? Guidelines ...

    2. Is there an IBM C/370 recommendation on ISASIZE ? (64K), or do you have to use the REPORT option to determine.

    3. Is there any run time way to determine actual module requirements without having to recompile everything with RUNOPTS (REPORT) ?

    4. Is there a way to identify memory leaks in my C programs? Does anything exist on the MVS side ?

    5. Since I am having memory fragmentation problems, is there a way to detect memory fragmentation. How do they manage protecting fragmentation ? Do they have to use HEAP for this ?

    I understand the methodology of allocating and freeing memory has to be done carefully and in the correct order to prevent memory fragmentation. I am not sure how to detect if I am doing it wrong.

    Answer

    1. No. Have you read both the descriptions of the Run-Time Options and the Run-time Storage Chapter (Ch.17 V2R1 Programming Guide and Ch. 6 AD/Cycle C/370 V1R2 Users Guide).

    2. There an no IBM C/370 recommendation on ISASIZE. We recommend that you run your program with the REPORT option and set the ISASIZE to the value in "Amount of Stack Storage Required ". Do not count on the ISA being zeroed.

    3. Since you have a large amount of large modules we recommend you compile with #pragma runopts(EXECOPS) in the code and run the module with go parms of "REPORT /". The EXECOPS option allows you to specify the run time option on the command line at execution time - this will allow you to try different combinations of HEAP and STACK without recompiling your code. Do not move the code into production with #pragma runopts(EXECOPS) - it will slow you down. For C/370 V2 and above the first parameter of the STACK option is equivalent to the ISASIZE run time option. If your program is AMODE 31 you should specify ANYWHERE as the third STACK parameter so that the STACK could be placed above the line. This may alleviate some storage constraints.

    4. We are not not aware of any IBM product that does this.

    5. STACK and HEAP can both be used to help you eliminate fragmentation. If the initial stack is too small then additional small stacks may be allocated and cause storage fragmentation. Ideally the ISASIZE should be the recommended stack size from the report. The use of HEAP is a bit more tricky. If you have a lot of system storage, or your programs do not use much heap you could make the initial heap size the total size as listed in the report. Otherwise, one must look at the storage report and the design of the program and try to optimize. Your knowledge of the program design may tell you the best base heap and increment size. Changing the KEEP/FREE parameter of the HEAP option may also provide some benefit.


    Missed our Previous Editions?

    If you did not get a copy of any of our previous editions, just let us know and we will be more than happy to send them to you.


    A word from your editor

    If you haven't already sent for your free subscription to this newsletter, now is the time to mail it in. So far, we have been able to keep to our plan of 4 issues a year. If you prefer, mail or fax your business card to the address/phone number on the Reader's Comment Form. You can also subscribe to this newsletter on INTERNET. Just send a message containing your name, full mailing address and phone number, in case we have to talk to you to INETC370 @ VNET.IBM.COM or IBMMAIL(CAIBMRXZ).

    For the many of you sending in the reply forms with your comments, we may need to call you to discuss your comments further. Please keep those cards, letters, faxes and messages coming in to us so that we can continue to provide this service. We really thank the many of you who have already sent your comments and subscriptions in. It's a great help if you include your phone number. Thanks!


    Coming Soon

    In future issues, we'll bring have some performance tips and answer some more of your questions. Thanks for reading; please let us know what you think of this newsletter.

    +-------------------------------------------------------------               --+
    

    This newsletter was produced by the IBM Software Solutions Toronto | Laboratory. For further information on any of the products mentioned, please contact your local IBM office, or an authorized IBM Business Partner.

    Numerous product references in this publication are registered | trademarks or trademarks of International Business Machines Corporation, unless otherwise indicated. IBM Canada Ltd., a related company is a licensee.

    This newsletter was created and marked for processing using IBM | BookMaster ® (Program Number 5688-015) and IBM Document Composition | Facility (DCF)(Program Number 5748-XX9). The final copy was printed on an IBM 3825 Page Printer, an Advanced Function Printer.

    This newsletter is © Copyright IBM Corporation 1994. | In Canada - © Copyright IBM Canada Ltd. 1994. | +------------------------------------------------------------ ---------+


    C/370 Compiler News Volume 2 Number 2 June/94 Issue

    Reader's Comment Form

    1. Did you find this newsletter useful?

    2. Is there any way you think we could improve this newsletter?

    3. Is there any C/370 compiler-related subject you would like to see addressed in this newsletter?

    Please note:

    Thank you for your cooperation and help. You can either mail this form to us, hand it into an IBM office for forwarding or send a message containing your full mailing address and phone number to IBMMAIL(CAIBMRXZ) or INETC370 @ VNET.IBM.COM.

    You can also fax the form to us. Our fax number is 416-448-6057. Please mark your fax for the attention of Gord Sinclair. Thanks.

    C/370 Compiler News Volume 2 Number 2 June/94 Issue

    Reader's Comment Form

    Fold here and tape.........fold here and tape.........fold here


        Gordon Sinclair
        Software Solutions Toronto Laboratory
        IBM Canada Ltd
        23/148/844/TOR
        844 Don Mills Road
        North York
        Ontario, Canada
        M3C 1V7
    


    Fold here and tape.........fold here and tape.........fold here
    Footnotes:

    ( ) Products marked (TM) or ® are trademarks or registered trademarks of the International Business Machines Corporation, unless otherwise indicated.

    ( ) Omegamon is a Registered Trademark of Candle Corporation.