[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference rdgeng::cics_technical

Title:Discussion of CICS technical issues
Moderator:IOSG::SMITHF
Created:Mon Mar 13 1995
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:192
Total number of notes:680

166.0. "problem with cics EPI examples" by NETRIX::"ricardo.lopez@sqo.mts.dec.com" (Ricardo Lopez Cencerrado) Mon Feb 03 1997 20:49

I have a problem testing the performance of a simple EPI sample code. I have
modified "cicsepi2a.c" to execute a transaction in my region. The transaction
"JCM3" simply returns a message as an answer and ends. The program executes 
the echo transaction 550 times, waiting 1 second between two transactions.

The modified test program shows an ouput like:

>>> Executed 545 transactions
The following message was received from CICS:
"2000                    FIN"
>>> Executed 546 transactions
The following message was received from CICS:
"2000                    FIN"
>>> Executed 547 transactions
The following message was received from CICS:
"2000                    FIN"
>>> Executed 548 transactions
The following message was received from CICS:
"2000                    FIN"
>>> Executed 549 transactions
The following message was received from CICS:
"2000                    FIN"
The following message was received from CICS:
"2000                    FIN"

When I have six or seven example processes running concurrently the console 
begins to fill up with messages like:

Feb  3 17:41:50 ib003 vmunix: fork/procdup: thread_create failed. Code: 0x11
Feb  3 17:41:52 ib003 vmunix: fork/procdup: thread_create failed. Code: 0x11

on a dec 3000/500 with 192MB, 1.2GB of VM and running OSF 3.2C with
CICS 2.1A. 

The same test repeated on a 3000/500 with 64MB RAM, 256MB of VM and running
OSF
3.2G, but launching the transactions againts the host defined in the previous
paragraph produces messages like:

Feb  3 16:38:39 dc227 vmunix: fork/procdup: thread_create failed. Code: 0x6
Feb  3 17:00:39 dc227 vmunix: fork/procdup: thread_create failed. Code: 0x6

when running only 5 example processes. 

This problem seems to affect the whole system, not the kernel or sysconfigtab
limits for a user process. 

I would like to know which kernel parameter is being reached. I would say 5-7 
processes are too few to generate this type of problem. I use an approach 
similar to this example's to implement a server program to connect tcp clients
to a cics host and so I am very interested in this issue.


Thanks in advance


Ricardo Lopez Cencerrado


PS.- following the compilation line and source code:


make command:

cc -c -taso -std1 -threads -I/usr/opt/cics/include cicsepi2a.c
ld /usr/ccs/lib/crt0.o -taso -call_shared  -L/usr/opt/cics/lib -o cicsepi
cicsep
i2a.o -lcicsepico -L/usr/opt/dce/usr/shlib/dce -lpthreads -lmach -lc_r -lc

modified source code:

/*
 * NAME:        EPI Sample 1 - cicsepi2a.c
 *
 * VERSION:     1.1
 *
 * COPYRIGHT:
 *
 *   (C) COPYRIGHT International Business Machines Corp. 1993, 1995
 *   All Rights Reserved
 *   Licensed Materials - Property of IBM
 *
 *   US Government Users Restricted Rights - Use, duplication or
 *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 *
 *
 * DESCRIPTION:
 *
 *      This is a sample EPI application program for CICS.  It takes
 *      one parameter, the name of a CICS region, and adds a single
 *      EPI terminal to that region.  It then runs the transaction EPI2
 *      against the terminal displays the data sent by the transaction and
 *      replies when the transaction asks for data back.
*
 *      The EPI2 transaction simply does an EXEC CICS CONVERSE asking the
 *      user to enter their name and then does an EXEC CICS SEND with a
 *      "Hello" message to the user.
 *
 *      This sample demonstrates simple use of the following EPI functions:
 *
 *      - CICS_EpiInitialize()
 *      - CICS_EpiTerminate()
 *      - CICS_EpiAddTerminal()
 *      - CICS_EpiDelTerminal()
 *      - CICS_EpiStartTran()
 *      - CICS_EpiGetEvent()
 *      - CICS_EpiGetSysError()
 *
 *      It also illustrates processing of the following EPI events:
 *
 *      - CICS_EPI_EVENT_SEND
 *      - CICS_EPI_EVENT_CONVERSE
 *      - CICS_EPI_EVENT_END_TRAN
 *      - CICS_EPI_EVENT_END_TERM
 *
 *      For simplicity a secondary thread is started to handle all EPI
 *      event processing and condition variables are used to coordinate
 *      with the main thread.
 */

#include <cicstype.h>
#include <stdio.h>
#include <pthread.h>
#include <dfhaid.h>             /* CICS 3270 AID values */
#include <locale.h>

#include <cics_epi.h>           /* Include the EPI header file */
#include <cics_samples.h>

/*
 * This is a piece of dummy 3270 data (an ENTER AID key followed by a
 * cursor position of (0,0)).  It is used when starting transactions.
 */

#define DUMMY_DATA ((cics_ubyte_t *)"'  JCM31122")

/*
 * Declare the functions used in this program.
 */

#define BUFFER_SIZE 200

void ErrorExit(cics_char_t *Function, cics_sshort_t Rc, cics_ushort_t
TermIndex)
;
void *EventThread(void *Parm);
void DisplayData(cics_ubyte_t *Data, cics_ushort_t Size);
void SendResponse(cics_ushort_t TermIndex);


/*********************************************************************/
/* Condition Variables and Mutexes used for thread coordination      */
/*********************************************************************/

pthread_cond_t   TranEnded;
pthread_cond_t   TermEnded;
pthread_mutex_t  Mutex;
cics_bool_t      TranEnd_Flag = FALSE;
cics_bool_t      TermEnd_Flag = FALSE;


/*********************************************************************/
/* ErrorExit() - Report errors and exit                              */
/*********************************************************************/
/* This function is called to report serious and unexpected EPI      */
/* errors.  It will then terminate the program.                      */

void ErrorExit(cics_char_t *Function, cics_sshort_t Rc, cics_ushort_t
TermIndex)
{
  CICS_EpiSysError_t SysErr;            /* Receives EPI error info.  */

   fprintf(stderr, "%s() call failed ", Function);
   if (Rc != CICS_EPI_ERR_FAILED)
   {
      fprintf(stderr, "with return code: %d\n", Rc);
   }
   else
   {
      CICS_EpiGetSysError(TermIndex, &SysErr);

      fprintf(stderr, "with a system error.\n");
      fprintf(stderr, "Cause: %u, Error: %u, Message: %s\n",
                      SysErr.Cause, SysErr.Value,
                      (SysErr.Msg != NULL) ? SysErr.Msg : "<none>");
   }

  exit(1);
}


/*********************************************************************/
/* EventThread() - Event processing thread                           */
/*********************************************************************/
/* This function is run in a secondary thread and handles all the    */
/* EPI event processing for the program.  It calls CICS_EpiGetEvent()*/
/* in blocking mode to wait for the arrival of EPI events.           */

void *EventThread(void *Parm)
{
  cics_sshort_t Rc;
  cics_ushort_t TermIndex;                  /* Installed TermIndex        */
  CICS_EpiEventData_t EventData;        /* Receives EPI event details */
  cics_ubyte_t Data[BUFFER_SIZE];           /* Receives event data        */

  char nothing2[8192];

  TermIndex = *((cics_ushort_t *)Parm);

 /*
 * This thread runs in a loop receiving and processing events until
   * the final CICS_EPI_EVENT_END_TERM is received.
   */

   do
   {
      /*
       * Wait for next event.
       */

       EventData.Data = Data;           /* Point to space for any    */
       EventData.Size = sizeof(Data);   /* incoming datastream.      */

       Rc = CICS_EpiGetEvent(TermIndex,
                             CICS_EPI_WAIT,   /* Wait for next event */
                             &EventData);

      /*
       * Return codes of CICS_EPI_NORMAL and CICS_EPI_ERR_MORE_EVENTS both
mean
       * the function completed successfully and obtained an EPI event.
       */

       if (Rc == CICS_EPI_NORMAL || Rc == CICS_EPI_ERR_MORE_EVENTS)
 {
          switch (EventData.Event)
          {
            /*
             * ENDTERMINAL: Nothing needs to be done here.  The event
             *              processing loop will end.
             */

             case CICS_EPI_EVENT_END_TERM:
                break;

            /*
             * SEND: Display the data received from a transaction.
             */

             case CICS_EPI_EVENT_SEND:
                DisplayData(EventData.Data, EventData.Size);
                break;

            /*
             * CONVERSE: Display the data received and send a reply.
             */
 case CICS_EPI_EVENT_CONVERSE:
                DisplayData(EventData.Data, EventData.Size);
                SendResponse(EventData.TermIndex);
                break;

            /*
             * ENDTRAN: Signal the "TranEnded" condition variable to tell
             *          the main thread to proceed.
             */

             case CICS_EPI_EVENT_END_TRAN:
                pthread_mutex_lock(&Mutex);
                TranEnd_Flag = TRUE;
                pthread_cond_signal(&TranEnded);
                pthread_mutex_unlock(&Mutex);
                break;

            /*
             * Display a warning for unexpected events.
             */

             default:
                printf("Unexpected event received (%d)\n", EventData.Event);
       break;
          }
       }
       else
       {
          ErrorExit("CICS_EpiGetEvent", Rc, TermIndex);
       }

   } while (EventData.Event != CICS_EPI_EVENT_END_TERM);

  /*
   * Drop through to here when the terminal has ended.  Display a message
   * if the terminal ended for an unexpected reason and signal the
   * "TermEnded" condition variable to tell the main thread to exit.
   */

   switch (EventData.EndReason)
   {
      case CICS_EPI_END_SIGNOFF:
         break;                         /* This is what we expect    */

      case CICS_EPI_END_FAILED:
         printf("Terminal Delete ABENDed (\"%s\")\n", EventData.AbendCode);
        break;

      default:
         printf("Unexpected terminal end (%d)\n", EventData.EndReason);
         break;
   }

   pthread_mutex_lock(&Mutex);
   TermEnd_Flag = TRUE;
   pthread_cond_signal(&TermEnded);
   pthread_mutex_unlock(&Mutex);

  return;
}


/*********************************************************************/
/* DisplayData() - Show data sent from a transaction                 */
/*********************************************************************/
/* This function will display the data sent to the EPI from a CICS   */
/* transaction.  The first two bytes of the data are a 3270 command  */
/* byte and the 3270 WCC, these are ignored.                         */
                                                              
void DisplayData(cics_ubyte_t *Data, cics_ushort_t Size)
{
  cics_ushort_t Index;                      /* Loop counter              */

   if (Size > 0)
   {
      printf("The following message was received from CICS:\n");
      printf("\"");
      for (Index = 2; Index < Size; Index++)
         printf("%c", Data[Index]);
      printf("\"\n");
   }

  return;
}


/*********************************************************************/
/* RespondData() - Show data sent from a transaction and reply       */
/*********************************************************************/
/* This function will obtain a line of input from the user and send  */
/* it as a response to a CONVERSE request.                           */
                                      
void SendResponse(cics_ushort_t TermIndex)
{
  cics_sshort_t Rc;
  cics_ubyte_t Response[BUFFER_SIZE];

  /*
   * The EPI2 transaction expects 3270 datastream back, so we must fake
   * the first 3 bytes of the response data to be an AID key (ENTER) and
   * a cursor position (0,0).
   */

   Response[0] = DFHENTER;              /* ENTER AID key value       */
   Response[1] = 0x20;                  /* Code for cursor row=0     */
   Response[2] = 0x20;                  /* Code for cursor column=0  */

  /*
   * Now get the user's input line.
   */

   scanf("%s", Response + 3);

  /*
   * Send the reply.
  */

   Rc = CICS_EpiReply(TermIndex, Response, strlen(Response));
   if (Rc != CICS_EPI_NORMAL)
   {
      ErrorExit("CICS_EpiReply", Rc, TermIndex);
   }

  return;
}


/*********************************************************************/
/* main() - Sample Entry Point                                       */
/*********************************************************************/
/* This program should be called with the name of a CICS region.  If */
/* none is supplied it will exit with an error, otherwise it will    */
/* install and EPI terminal and run the EPI2 transaction.  When the  */
/* transaction ends the terminal is deleted.                         */

main(int argc, cics_char_t *argv[])
{
  cics_sshort_t Rc;                             /* EPI function return codes
*/
 cics_ushort_t TermIndex;                  /* EPI Terminal Index        */
  pthread_t Thread;                     /* Secondary thread id       */

  char nothing[8192];

  int i=0, maximum=551;

  /*
   * Check the caller supplied the name of a CICS region to be used.
   * Give up if we haven't got one.
   */

   if (argc < 2)
   {
      fprintf(stderr, "A CICS region name must be specified.\n");
      exit(1);
   }

  /*
   * Pick up the locale from the environment
   */
   (void)setlocale(LC_ALL,"");
                              
 /*
   * Initialize the condition variables and mutexes used for thread
   * coordination.
   */

   pthread_mutex_init(&Mutex, pthread_mutexattr_default);
   pthread_cond_init(&TermEnded, pthread_condattr_default);
   pthread_cond_init(&TranEnded, pthread_condattr_default);

  /*
   * Initialize the EPI.
   */

   Rc = CICS_EpiInitialize(CICS_EPI_VERSION_101);
   if (Rc != CICS_EPI_NORMAL)
   {
      ErrorExit("CICS_EpiInitialize", Rc, CICS_EPI_TERM_INDEX_NONE);
   }

  /*
   * Install a terminal against the specified region.
   * Specify the terminal model to avoid an unsuitable default.
   */

   Rc = CICS_EpiAddTerminal(NULL,       /* No Namespace needed       */
                            argv[1],    /* Use region specified      */
                            NULL,       /* Autoinstall the terminal  */
                            "hft",      /* High function terminal    */
                            NULL,       /* No event notification     */
                            NULL,       /* TermDetails not needed    */
                            &TermIndex); /* Receives new TermIndex   */
   if (Rc != CICS_EPI_NORMAL)
   {
      ErrorExit("CICS_EpiAddTerminal", Rc, CICS_EPI_TERM_INDEX_NONE);
   }

  /*
   * Once the terminal is installed start up the secondary event
   * processing thread.  If this fails just terminate the EPI and exit.
   */

   if (pthread_create(&Thread, pthread_attr_default,
                      EventThread, &TermIndex) == -1)
   {
      fprintf(stderr, "Cannot start event processing thread.\n");
      Rc = CICS_EpiTerminate();
     exit(1);
   }

  /*
   * Submit the EPI2 transaction and wait for it to complete.  This is
   * done by waiting on the "TranEnded" condition variable, signalled
   * by the event thread.  Some initial 3270 data must be provided so
   * use the DUMMY_DATA.
   */

  for (i=0;i<maximum;i++)
    {
      Rc = CICS_EpiStartTran(TermIndex,
                             NULL,
                             DUMMY_DATA,
                             sizeof(DUMMY_DATA) );
      if (Rc != CICS_EPI_NORMAL)
        {
          ErrorExit("CICS_EpiStartTran", Rc, TermIndex);
        }

      pthread_mutex_lock(&Mutex);
      while (!TranEnd_Flag)
  {
          pthread_cond_wait(&TranEnded, &Mutex);
        }
      pthread_mutex_unlock(&Mutex);

      if ( (i%10) && i )
        {
          fprintf( stderr, ">>> Executed %d transactions\n", i );
          fflush( stderr );
        }
      sleep(1);
    }
      /*
       * The transaction has finished.  The terminal is now deleted and the
       * "TermEnded" condition variable used to wait for deletion to complete.
       */

   Rc = CICS_EpiDelTerminal(TermIndex);
   if (Rc != CICS_EPI_NORMAL)
   {
      ErrorExit("CICS_EpiDelTerminal", Rc, TermIndex);
   }
                                                      
  pthread_mutex_lock(&Mutex);
   while (!TermEnd_Flag)
   {
       pthread_cond_wait(&TermEnded, &Mutex);
   }
   pthread_mutex_unlock(&Mutex);

  /*
   * Finally terminate the EPI and the application.
   * Clean up mutexes and condition variables
   */

   Rc = CICS_EpiTerminate();
   if (Rc != CICS_EPI_NORMAL)
   {
      ErrorExit("CICS_EpiTerminate", Rc, CICS_EPI_TERM_INDEX_NONE);
   }

   pthread_mutex_destroy(&Mutex);
   pthread_cond_destroy(&TranEnded);
   pthread_cond_destroy(&TermEnded);

   exit(0);
  }

/* EOF */

[Posted by WWW Notes gateway]
T.RTitleUserPersonal
Name
DateLines
166.1Check system resource limitsMUFFIT::gerryGerry ReillyTue Feb 04 1997 16:4918
Looks to me that you are out of the threads.  Please can you post your

/etc/sysconfigtab 

file.  You should have a minimum setting of

max-proc-per-user = 267
max-threads-per-user = 1024

Please can you also do a

grep -i maxusers /sys/conf/<SYSTEM NAME>

to check the maxusers setting.  This needs to be at least 256.

-gerry


166.2Thanks, but repeats with 10 examplesNETRIX::&quot;ricardo.lopez@sqo.mts.dec.com&quot;Ricardo Lopez CencerradoThu Feb 06 1997 17:1940
Hello and thanks for your quick and clear reply. 

I had only a sysconfigtab file with the entries:

proc:
 max-proc-per-user=267
 max-threads-per-user=1024
vm:
 vm-vpagemax = 32767

But I did not have enough maxusers defined for /sys/conf/DC227( only 64 ). I
recompiled Kernel and got a new one for maxusers 256. On it I get errors again

when launching the ninth example. The message is:

kern.log:Feb  4 17:45:26 dc227 vmunix: fork/procdup: thread_create failed.
Code: 0x11
kern.log:Feb  4 18:11:00 dc227 vmunix: fork/procdup: thread_create failed.
Code: 0x11

After this point, they reach again a maximum for some kernel parameter. No
more
processes can be created by any user. Are processes which use EPI this
resource
intensive on the kernel?

I would like to know which parameters would be appropiate for a configuration 
running 25-30 processes which call EPIinitilize and also if there is a limit
for the maximum number of processes which use EPI. As far as I understand, 
any process which has to use EPI must initizalize and terminate EPI with the
appropiate call, in the way the example cicsepi2a.c does.

I am looking for a configuration (sysconfigtab and kernel parameters) which
allows simultaneous operation of CICS 2.1A,Oracle 7.1.6, DCE full (non-lite)
and about 30 EPI processes.

Thanks very much again,

Ricardo Lopez Cencerrado.
[Posted by WWW Notes gateway]
166.3MUFFIT::gerryGerry ReillyFri Feb 07 1997 14:1632
Hi,

Your almost certainly not running out of processes.  However, I suspect
that you may be running out of threads.  You might want to increase the
number of threads available to both the user and system.  The users number
is controlled through /etc/sysconfigtab, the system wide limited is
controlled through the kernel configuration file.

Please can do the following-

ps alx | wc -l              / This will get the number of processes running
ps alxm | wc -l             / to get the number of threads -approx

then

dbx -k /vmunix /dev/mem
(dbx) p thread_max          / Maximum number of system wide threads and tasks
(dbx) p task_max

CICS uses a lot of threads but not necessarily a lot of processes.  With 10
epi client programs running you will have 10 processes but a minimum of
1,000 threads.  EPI clients are expected to be multithreaded and not for a 
single client sessions.  There is an undocumented EPI call that will reduce the
number of threads,

TerEP_SetMaxLimits(max_terminals,max_terminals);

If you are using an EPI client for each connection you can safely reduce
max_terminals to, say, 2. The TerEP_SetMaxLimits must be called before
initialising the EPI.

-gerry