#include <spawn.h> #include <qlg.h> pid_t QlgSpawn(const Qlg_Path_Name_T *path, const int fd_count, const int fd_map[], const struct inheritance *inherit, char * const argv[], char * const envp[]);
The QlgSpawn() function, like the spawn() function, creates a child process that inherits specific attributes from the parent. The difference is that for the path parameter, the QlgSpawn() function takes a pointer to a Qlg_Path_Name_T structure, while the spawn() function takes a pointer to a character string in the CCSID of the job.
Limited information on the path parameter is provided here. For more information on the path parameter and for a discussion of other parameters, authorities required, and return values, see spawn()--Spawn Process.
See spawn()--Spawn Process for a complete discussion of usage information for QlgSpawn(). In addition, the following should be noted specifically for QlgSpawn().
See Code disclaimer information for information pertaining to code examples.
Parent ProgramThe following ILE C for i5/OS program can be created in any library. This parent program assumes the corresponding child program will be created with the name CHILD in the library QGPL. Call this parent program with no parameters to run the example.
/*****************************************************************/ /*****************************************************************/ /* */ /* FUNCTION: This program acts as a parent to a child program. */ /* */ /* LANGUAGE: ILE C for i5/OS */ /* */ /* APIs USED: QlgSpawn(), waitpid(), */ /* QlgCreat(), QlgUnlink(), QlgOpen() */ /* */ /*****************************************************************/ /*****************************************************************/ #include <errno.h> #include <fcntl.h> #include <spawn.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <qlg.h> #include <Qp0lstdi.h> #define ARGV_NUM 6 #define ENVP_NUM 1 #define CHILD_PGM "QGPL/CHILD" #define spwpath "/QSYS.LIB/QGPL.LIB/CHILD.PGM" #define fpath "A_File" typedef struct pnstruct { Qlg_Path_Name_T qlg_struct; char pn[100]; /* This size must be >= the path */ /* name length or this must be a */ /* pointer to the path name. */ }; /* This is a parent program that will use QlgSpawn() to start a */ /* child. A file is created that is written to, both by the parent */ /* and the child. The end result of the file will look something */ /* like the following: */ /* Parent writes Child writes */ /* ------------- --------------------------------------- */ /* 1 argv[0] getppid() getpgrp() getpid() */ /* The parent uses waitpid() to wait for the child to return and to */ /* retrieve the resulting status of the child when it does return. */ int main(int argc, char *argv[]) { int rc; /* API return code */ int fd, fd_read; /* parent file descriptors */ char fd_str[4]; /* file descriptor string */ const char US_const[3]= "US"; const char Language_const[4]="ENU"; const char Path_Name_Del_const[2]= "/"; struct pnstruct f_path_name; /* file pathname */ int buf_int; /* write(), read() buffer */ char buf_pgm_name[22]; /* read() program name buffer */ struct pnstruct spw_path; /* QlgSpawn() *path */ int spw_fd_count = 0; /* QlgSpawn() fd_count */ struct inheritance spw_inherit; /* QlgSpawn() *inherit */ char *spw_argv[ARGV_NUM]; /* QlgSpawn() *argv[] */ char *spw_envp[ENVP_NUM]; /* QlgSpawn() *envp[] */ int seq_num; /* sequence number */ char seq_num_str[4]; /* sequence number string */ pid_t pid; /* parent pid */ char pid_str[11]; /* parent pid string */ pid_t pgrp; /* parent process group */ char pgrp_str[11]; /* parent process group string */ pid_t spw_child_pid; /* QlgSpawn() child pid */ pid_t wt_child_pid; /* waitpid() child pid */ int wt_stat_loc; /* waitpid() *stat_loc */ int wt_pid_opt = 0; /* waitpid() option */ /* Get the pid and pgrp for the parent. */ pid = getpid(); pgrp = getpgrp(); /* Format the pid and pgrp value into null-terminated strings. */ sprintf(pid_str, "%d", pid); sprintf(pgrp_str, "%d", pgrp); /* Initialize Qlg_Path_Name_T parameters */ memset(&f_path_name,0x00,sizeof(struct pnstruct)); f_path_name.qlg_struct.CCSID = 37; memcpy(f_path_name.qlg_struct.Country_ID,US_const,2); memcpy(f_path_name.qlg_struct.Language_ID,Language_const,3); f_path_name.qlg_struct.Path_Type = QLG_CHAR_SINGLE; f_path_name.qlg_struct.Path_Length = sizeof(fpath)-1; memcpy(f_path_name.qlg_struct.Path_Name_Delimiter, Path_Name_Del_const,1); memcpy(f_path_name.pn,fpath,sizeof(fpath)-1); /* Create a file and maintain the file descriptor. */ fd = QlgCreat((Qlg_Path_Name_T *)&f_path_name, S_IRWXU); if (fd == -1) { printf("FAILURE: QlgCreat() with errno = %d\n",errno); return -1; } /* Format the file descriptor into null-terminated string. */ sprintf(fd_str, "%d", fd); /* Initialize Qlg_Path_Name_T parameters */ memset(&spw_path,0x00,sizeof(struct pnstruct)); spw_path.qlg_struct.CCSID = 37; memcpy(spw_path.qlg_struct.Country_ID,US_const,2); memcpy(spw_path.qlg_struct.Language_ID,Language_const,3); spw_path.qlg_struct.Path_Type = QLG_CHAR_SINGLE; spw_path.qlg_struct.Path_Length = sizeof(spwpath)-1; memcpy(spw_path.qlg_struct.Path_Name_Delimiter, Path_Name_Del_const,1); memcpy(spw_path.pn,spwpath,sizeof(spwpath)-1); /* Write a '1' out to the file. */ seq_num = 1; sprintf(seq_num_str, "%d", seq_num); buf_int = seq_num; write(fd, &buf_int, sizeof(int)); /* Set the QlgSpawn() child arguments for the child. */ /* NOTE: The child will always get argv[0] in the */ /* LIBRARY/PROGRAM notation, but the QlgSpawn() argv[0] */ /* (spw_argv[0] in this case) must be non-NULL in order */ /* to allow additional arguments. For this example, the */ /* CHILD_PGM was chosen. */ /* NOTE: The parent pid and the parent process group are */ /* passed to the child for demonstration purposes only. */ spw_argv[0] = CHILD_PGM; spw_argv[1] = pid_str; spw_argv[2] = pgrp_str; spw_argv[3] = seq_num_str; spw_argv[4] = fd_str; spw_argv[5] = NULL; /* This QlgSpawn() will use simple inheritance for file */ /* descriptors (fd_map[] value is NULL). */ memset(&spw_inherit,0x00,sizeof(spw_inherit)); spw_envp[0] = NULL; spw_child_pid = QlgSpawn((Qlg_Path_Name_T *)&spw_path, spw_fd_count, NULL, &spw_inherit, spw_argv, spw_envp); if (spw_child_pid == -1) { printf("FAILURE: QlgSpawn() with errno = %d\n",errno); close(fd); QlgUnlink((Qlg_Path_Name_T *)&f_path_name); return -1; } /* The parent no longer needs to use the file descriptor, so */ /* it can close it, now that it has issued QlgSpawn(). */ rc = close(fd); if (rc != 0) printf("FAILURE: close(fd) with errno = %d\n",errno); /* NOTE: The parent can continue processing while the child is */ /* also processing. In this example, though, the parent will */ /* simply wait until the child finishes processing. */ /* Issue waitpid() in order to wait for the child to return. */ wt_child_pid = waitpid(spw_child_pid,&wt_stat_loc,wt_pid_opt); if (wt_child_pid == -1) { printf("FAILURE: waitpid() with errno = %d\n",errno); close(fd); QlgUnlink((Qlg_Path_Name_T *)&f_path_name); return -1; } /* Check to ensure the child did not encounter an error */ /* condition. */ if (WIFEXITED(wt_stat_loc)) { if (WEXITSTATUS(wt_stat_loc) != 1) printf("FAILURE: waitpid() exit status = %d\n", WEXITSTATUS(wt_stat_loc)); } else printf("FAILURE: unknown child status\n"); /* Open the file for read to verify what the child wrote. */ fd_read = QlgOpen((Qlg_Path_Name_T *)&f_path_name, O_RDONLY); if (fd_read == -1) { printf("FAILURE: open() for read with errno = %d\n",errno); QlgUnlink((Qlg_Path_Name_T *)&f_path_name); return -1; } /* Verify what child wrote. */ rc = read(fd_read, &buf_int, sizeof(int)); if ( (rc != sizeof(int)) || (buf_int != 1) ) printf("FAILURE: read()\n"); memset(buf_pgm_name,0x00,sizeof(buf_pgm_name)); rc = read(fd_read, buf_pgm_name, strlen(CHILD_PGM)); if ( (rc != strlen(CHILD_PGM)) || (strcmp(buf_pgm_name,CHILD_PGM) != 0) ) printf("FAILURE: read() child argv[0]\n"); rc = read(fd_read, &buf_int, sizeof(int)); if ( (rc != sizeof(int)) || (buf_int != pid) ) printf("FAILURE: read() child getppid()\n"); rc = read(fd_read, &buf_int, sizeof(int)); if ( (rc != sizeof(int)) || (buf_int != pgrp) ) printf("FAILURE: read() child getpgrp()\n"); rc = read(fd_read, &buf_int, sizeof(int)); if ( (rc != sizeof(int)) || (buf_int != spw_child_pid) || (buf_int != wt_child_pid) ) printf("FAILURE: read() child getpid()\n"); /* Attempt one more read() to ensure there is no more data. */ rc = read(fd_read, &buf_int, sizeof(int)); if (rc != 0) printf("FAILURE: read() past end of data\n"); /* The parent no longer needs to use the read() file descriptor, */ /* so it can close it. */ rc = close(fd_read); if (rc != 0) printf("FAILURE: close(fd_read) with errno = %d\n",errno); /* Clean up by performing unlink(). */ rc = QlgUnlink((Qlg_Path_Name_T *)&f_path_name); if (rc != 0) { printf("FAILURE: QlgUnlink() with errno = %d\n",errno); return -1; } printf("completed successfully\n"); return 0; }
The following ILE C for i5/OS program must be created with the name CHILD in the library QGPL in order to be found by the parent program. This program is not to be called directly, as it is run through the use of QlgSpawn() in the parent program.
/*******************************************************************/ /*******************************************************************/ /* */ /* FUNCTION: This program acts as a child to a parent program. */ /* */ /* LANGUAGE: ILE C for i5/OS */ /* */ /* APIs USED: getpid(), getppid(), getpgrp() */ /* */ /*******************************************************************/ /*******************************************************************/ #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> /* This is a child program that gets control from a parent program */ /* that issues QlgSpawn(). This particular child program expects */ /* the following 5 arguments (all are null-terminated strings): */ /* argv[0] - child program name */ /* argv[1] - parent pid (for demonstration only) */ /* argv[2] - parent process group (for demonstration only) */ /* argv[3] - sequence number */ /* argv[4] - parent file descriptor */ /* If the child program encounters an error, it returns with a */ /* value greater than 50. If the parent uses wait() or waitpid(), */ /* this return value can be interrogated using the WIFEXITED and */ /* WEXITSTATUS macros on the resulting wait() or waitpid() */ /* *stat_loc field. */ int main(int argc, char *argv[]) { pid_t p_pid; /* parent pid argv[1] */ pid_t p_pgrp; /* parent process group argv[2] */ int seq_num; /* parent sequence num argv[3] */ int fd; /* parent file desc argv[4] */ int rc; /* API return code */ pid_t pid; /* getpid() - child pid */ pid_t ppid; /* getppid() - parent pid */ pid_t pgrp; /* getpgrp() - process group */ /* Get the pid, ppid, and pgrp for the child. */ pid = getpid(); ppid = getppid(); pgrp = getpgrp(); /* Verify 5 parameters were passed to the child. */ if (argc != 5) return 60; /* Since the parameters passed to the child using QlgSpawn() are */ /* pointers to strings, convert the parent pid, parent process */ /* group, sequence number, and the file descriptor from strings */ /* to integers. */ p_pid = atoi(argv[1]); p_pgrp = atoi(argv[2]); seq_num = atoi(argv[3]); fd = atoi(argv[4]); /* Verify the getpid() value of the parent is the same as the */ /* getppid() value of the child. */ if (p_pid != ppid) return 61; /* If the sequence number is 1, simple inheritance was used in */ /* this case. First, verify the getpgrp() value of the parent */ /* is the same as the getpgrp() value of the child. Next, the */ /* child will use the file descriptor passed in to write the */ /* child's values for argv[0], getppid(), getpgrp(), */ /* and getpid(). Finally, the child returns, which will satisfy */ /* the parent's wait() or waitpid(). */ if (seq_num == 1) { if (p_pgrp != pgrp) return 70; rc = write(fd, argv[0], strlen(argv[0])); if (rc != strlen(argv[0])) return 71; rc = write(fd, &ppid, sizeof(pid_t)); if (rc != sizeof(pid_t)) return 72; rc = write(fd, &pgrp, sizeof(pid_t)); if (rc != sizeof(pid_t)) return 73; rc = write(fd, &pid, sizeof(pid_t)); if (rc != sizeof(pid_t)) return 74; return seq_num; } /* If the sequence number is an unexpected value, return */ /* indicating an error. */ else return 99; }
Top | Process-Related APIs | APIs by category |