/*---------------------------------------------------------------------+
| Copyright (c) 1995, SAS Institute Inc. |
| Unpublished - All Rights Reserved |
| S A S / C S A M P L E |
| |
| NAME: ECBMAIN |
| LANGUAGE: C |
| PURPOSE: Demonstrate the use of various SAS/C MVS Multi-tasking |
| functions, including: ECB processing, the ATTACH() |
| function, selectecb(), ecbpause() and the WAIT1 macro. |
| ECBMAIN attaches a sub-task, ECBTASK (a C MAIN), |
| passing a standard C parameter list. |
| Refer to the "sub_attach()" function for concerns |
| within a multi-tasking environment. |
| Additional details on the functions may be found in |
| SAS/C Library Reference, Third Edition, Release 6.00. |
| MVS - |
| COMPILE, LINK, EXECUTE: SUBMIT prefix.SAMPLE.AUX(ECBMAINJ) |
| where "prefix" is the installation defined high-level- |
| qualifier for the SAS/C product. |
| TSO - |
| COMPILE: LC370 CLIST - options EXTNAME |
| LINK: CLK370 CLIST |
| EXECUTE: CALL 'your.local.load(ECBMAIN)' |
| NOTES: ECBTASK should be compiled and linked prior to |
| executing ECBMAIN. |
| NOTES: Issue a: ALLOC F(SYSOTASK) DS(your.stdout.dataset) MOD |
| prior to calling ECBMAIN, where "your.stdout.dataset" |
| DCB values are: RECFM=VBA LRECL=133 BLOCKSIZE=23476 |
| CMS - N/A - multi-tasking is not supported in a CMS environment |
| |
| MISC NOTES: Systems without a TCP/IP stack should comment out the |
| "#define TCPIP_SYSTEM" statement below. |
| MISC NOTES: The ATTACHed load module ECBTASK is itself a C main |
| program, therefore a new C environment will be created |
| for the subtask. SAS/C requires that a multitasking |
| application be structured such that each task uses a |
| separate C environment. For this reason, address |
| space contention for: stdin, stdout, and stderr |
| may occur. Refer to the SAS/C Library Reference, |
| I/O Functions chapter, and the SAS/C Compiler Library |
| and User's Guide, Run-Time Argument Processing chapter,|
| for how to manage and/or redirect stdin, stdout and |
| stderr. |
| |
+---------------------------------------------------------------------*/
#define TCPIP_SYSTEM /* comment the #define if a TCPIP stack is */
/* not available on this system. */
#if defined(TCPIP_SYSTEM)
/*----------------------------------------------------------------+
| Includes for socket calls. |
+----------------------------------------------------------------*/
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#if __SASC__ == 550
#include <fcntl.h>
#else
#include <unistd.h>
#endif
int setupSocket(void); /* initializes a socket descriptor */
#endif /* TCPIP_SYSTEM */
/*-------------------------------------------------------------------+
| Include for ATTACH. |
+-------------------------------------------------------------------*/
#include <ostask.h>
/*-------------------------------------------------------------------+
| Miscellaneous includes. |
+-------------------------------------------------------------------*/
#include <ctype.h>
#include <lclib.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <lcstring.h>
#include <lcsignal.h>
/*-------------------------------------------------------------------+
| sub_attach() is used to attach a sub-task. Parmlist is: |
| int - used to determine the parameter list passed to attached task |
| unsigned * - ecb address to be posted when the sub-task terminates |
| void ** - address of the tcb for the sub-task, used in DETACH() |
+-------------------------------------------------------------------*/
int sub_attach(int, unsigned *, void **);
main()
{
int attach_rc;
void *subtcb = 0; /* sub-task tcb, used for DETACH */
time_t cur_time; /* time_t stucture for current time function*/
#if defined(TCPIP_SYSTEM)
int listensock; /* socket on which we listen for requests */
int select_posted = 0; /* set when selectecb() has been posted */
int ns = 0; /* number of sockets with action */
fd_set incoming; /* bound socket description for selectecb() */
struct timeval timeout; /* timeeval stucture for selectecb() */
#endif
/*-------------------------------------------------------------------+
| set up mainECB to contain a single ECB to be posted when the |
| attached sub-task terminates. |
+-------------------------------------------------------------------*/
unsigned ECB = 0;
struct _ecblist mainECB = { 1 , 0 };
mainECB.ecbarr = &ECB;
#if defined(TCPIP_SYSTEM)
/*----------------------------------------------------------------+
| Set up a socket, to prepare for sub_attach() and selectecb() |
+----------------------------------------------------------------*/
listensock = setupSocket();
if (listensock == -1)
exit(EXIT_FAILURE);
/*----------------------------------------------------------------+
| attach the sub-task and call selectecb() |
+----------------------------------------------------------------*/
time(&cur_time);
printf("calling sub_attach(): %s", ctime(&cur_time));
attach_rc = sub_attach(0, &ECB, &subtcb);
if (attach_rc == -1)
{
printf("sub_attach failed\n");
close(listensock);
exit(EXIT_FAILURE);
}
/*----------------------------------------------------------------+
| set timeout values, file descriptor array |
+----------------------------------------------------------------*/
timeout.tv_sec = 3; /* set timeout value to 3 seconds */
timeout.tv_usec = 0;
FD_ZERO(&incoming);
FD_SET(listensock,&incoming); /* set socket descriptor for */
/* demonstration purposes only */
/*----------------------------------------------------------------+
| selectecb() may return after a time-out, or when posted by an |
| event. In this case, time-out is 3 seconds. When selectecb() |
| returns test the ecb, and take the appropirate action. Either |
| set "select_posted" or re-enter selectecb() |
+----------------------------------------------------------------*/
while ( select_posted != 1 )
{
time(&cur_time);
printf("calling selectecb(): %s",ctime(&cur_time));
ns = selectecb(1, &incoming, NULL, NULL, &timeout, &mainECB, 1);
if (ns == -1)
{
perror("selectecb() call failed");
close(listensock);
exit(EXIT_FAILURE);
}
time(&cur_time);
printf("returned from selectecb(): %s",ctime(&cur_time));
if ( ECB & 0x40000000)
{
select_posted = 1;
printf("selectecb() was posted by sub-task termination\n\n");
}
else
printf("selectecb() returned because of a timeout\n\n");
}
/*----------------------------------------------------------------+
| cleanup: detach sub-task, close socket, and reset ecb. |
+----------------------------------------------------------------*/
DETACH(&subtcb,NOSTAE);
close(listensock);
ECB = 0;
#endif /* defined TCPIP_SYSTEM */
/*----------------------------------------------------------------+
| attach the sub-task and call ecbpause() |
+----------------------------------------------------------------*/
time(&cur_time);
printf("calling sub_attach(): %s", ctime(&cur_time));
attach_rc = sub_attach(1, &ECB, &subtcb);
if (attach_rc == -1)
{
printf("sub_attach failed\n");
exit(EXIT_FAILURE);
}
/*----------------------------------------------------------------+
| call ecbpause() |
+----------------------------------------------------------------*/
time(&cur_time);
printf("calling ecbpause(): %s",ctime(&cur_time));
/*----------------------------------------------------------------+
| NOTE: ecbpause() is a replacement for sigpause(). The ecbpause()|
| function allows an application to wait for either a POST |
| of an OS ECB or a C signal. Refer to the SAS/C Library |
| Reference for a complete description of the sigpause() |
| and ecbpause() functions. |
+----------------------------------------------------------------*/
ecbpause( 0, 1, &mainECB);
time(&cur_time);
printf("returned from ecbpause(): %s\n",ctime(&cur_time));
/*----------------------------------------------------------------+
| cleanup: detach sub-task, and reset ecb. |
+----------------------------------------------------------------*/
DETACH(&subtcb,NOSTAE);
ECB = 0;
/*----------------------------------------------------------------+
| attach the sub-task and call WAIT1() macro |
+----------------------------------------------------------------*/
time(&cur_time);
printf("calling sub_attach(): %s",ctime(&cur_time));
attach_rc = sub_attach(2, &ECB, &subtcb);
if (attach_rc == -1)
{
printf("sub_attach failed\n");
exit(EXIT_FAILURE);
}
/*----------------------------------------------------------------+
| invoke WAIT1() macro |
+----------------------------------------------------------------*/
time(&cur_time);
printf("calling WAIT1(): %s",ctime(&cur_time));
/*----------------------------------------------------------------+
| NOTE: WAIT1() allows and application to wait for only a POST |
| of an OS ECB. |
+----------------------------------------------------------------*/
WAIT1(&ECB);
time(&cur_time);
printf("returned from WAIT1(): %s\n",ctime(&cur_time));
/*----------------------------------------------------------------+
| cleanup: detach sub-task, and reset ecb. |
+----------------------------------------------------------------*/
DETACH(&subtcb,NOSTAE);
ECB = 0;
return (EXIT_SUCCESS);
}
#if defined(TCPIP_SYSTEM)
/*-------------------------------------------------------------------+
| Open a socket and set it up to accept requests. Return -1 if error.|
+-------------------------------------------------------------------*/
int setupSocket()
{
int listensock;
struct sockaddr_in sa_serv;
/*----------------------------------------------------------------+
| Get a socket of the proper type. |
+----------------------------------------------------------------*/
listensock = socket(AF_INET, SOCK_STREAM, 0);
if (listensock == -1)
{
perror("socket() call failed in setupSocket()");
return -1;
}
/*----------------------------------------------------------------+
| Bind our socket to the desired address so clients may reach us. |
+----------------------------------------------------------------*/
memset(&sa_serv,'\0',sizeof(struct sockaddr_in));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = htonl(INADDR_ANY);
sa_serv.sin_port = 0;
if (bind(listensock, &sa_serv, sizeof(sa_serv)) == -1)
{
perror("bind() call failed in setupSocket()");
close(listensock);
return -1;
}
/*----------------------------------------------------------------+
| Set up a queue for incoming requests. SOMAXCONN is maximum |
| size of queue. |
+----------------------------------------------------------------*/
if (listen(listensock, SOMAXCONN) == -1)
{
perror("listen() call failed in setupSocket()");
close(listensock);
return -1;
}
return listensock;
}
#endif /* TCPIP_SYSTEM */
/*----------------------------------------------------------------+
| sub_attach() attaches a sub-task which will post the sub_ecb |
| passed by the main() function. sub_ecb will be posted at |
| sub-task termination. |
+----------------------------------------------------------------*/
int sub_attach(int sub_int, unsigned *sub_ecb, void **subtcb)
{
int rc;
/*----------------------------------------------------------------+
| care must be taken when passing automatic variables to an |
| ATTACHed task. When sub_attach() returns, the storage |
| associated with an automatic variable is freed. If the attached |
| task addresses these variables, unpredictable results may occur.|
| For this reason, plist[] and argument are defined as "static". |
+----------------------------------------------------------------*/
static void *plist[1];
struct argument_s
{
short len;
char parms[100];
};
static struct argument_s argument;
/*----------------------------------------------------------------+
| argument.parms[] consists of a parameter list passed to C MAIN. |
| The parameter list is equivalent to: PARM='parms' in BATCH, or |
| within TSO, equivalent to "parms" in: CALL 'pgmname' 'parms' |
| In a multi-tasking environment, contention may occur for stdin, |
| stdout, and stderr. For this reason stdout for the subtask is |
| redirected to the DDname SYSOTASK using the standard C notation |
| ">filename" in the parameters. |
+----------------------------------------------------------------*/
switch(sub_int)
{
case 0: strcpy(argument.parms,">SYSOTASK selectecb() call "); break;
case 1: strcpy(argument.parms,">SYSOTASK ecbpause() call "); break;
case 2: strcpy(argument.parms,">SYSOTASK WAIT1() call"); break;
default:
printf("invalid sub_int value: %d passed to sub_attach, exiting\n",
sub_int);
return(-1);
}
argument.len = strlen(argument.parms);
plist[0] = (void *) (0x80000000 | (unsigned) &argument);
/*----------------------------------------------------------------+
| call ATTACH() |
+----------------------------------------------------------------*/
rc = ATTACH(subtcb, _Aep, "ECBTASK", _Aecb, sub_ecb, _Aparam,
plist, _Aend);
/*----------------------------------------------------------------+
| Check return code from ATTACH. |
+----------------------------------------------------------------*/
if (rc != 0)
{
printf("ATTACH for ECBTASK failed with rc = %d.\n",rc);
return -1;
}
return 0;
}
|