![]() |
![]() HP OpenVMS Systemsask the wizard |
![]() |
The Question is: I'm experimenting with ipc on an alpha (vms 6.2-1h3, decc v5.6-003) and a vax (vms 6.2, decc v5.6-003). I've written a very simple program (see below) that should work, but doesn't and dies in different places depending on whether I run it on the alpha or the vax. Here's the program: #include <stdio.h> #include <processes.h> #include <unistd.h> #include <limits.h> #define PARENT_INPUT fd[0] #define PARENT_OUTPUT fd[1] #define CHILD_INPUT fd[0] #define CHILD_OUTPUT fd[1] int main (int argc, char *argv[]) int fd[2]; pid_t pid; int n = 0; char line[1024]; if (pipe(fd) < 0) perror ("pipe"); if ((pid = vfork()) < 0) { perror("vfork"); } else if (pid > 0) { /* parent */ fprintf(stderr,"entering parent\n"); if (close (PARENT_OUTPUT) == -1) { perror("parent's close"); } else { fprintf(stderr,"parent's close successful\n"); } if ((n = read (PARENT_INPUT, line, PIPE_BUF)) <= 0) { perror ("parent's read"); } else { fprintf(stderr, "parent's read successful, n = %d\n",n); } if (write(STDOUT_FILENO, line, n) == -1) { perror ("write to stdout\n"); } else { fprintf (stderr, "parent write to stdout successful\n"); } } else if (pid == 0) { /* child */ fprintf(stderr,"entering child\n"); if (close (CHILD_INPUT) == -1) { perror ("child close"); } else { fprintf(stderr,"child's close successful\n"); } if (write (CHILD_OUTPUT, "I'm working!\n",1) == -1) { perror ("child's write into pipe"); } else { fprintf (stderr, "child's write into pipe, successful\n"); } } else { fprintf(stderr, "weirdness from vfork(), pid = %d\n", (int) pid); perror("pid"); } return 1; On the ALPHA, the output is: entering child child's close successful child's write into pipe, successful %SYSTEM-W-UNWIND, unwind currently in progress %TRACE-W-TRACEBACK, symbolic stack dump follows %SYSTEM-W-UNWIND, unwind currently in progress On the VAX the output is: entering child child's close successful child's write into pipe, successful entering parent parent's close successful parent's read: bad file number %SYSTEM-F-ROPRAND, reserved operand fault at PC=00002122, PSL=03C00001 %TRACE-F-TRACEBACK, symbolic stack dump follows module name routine name line rel PC abs PC 00002122 00002122 00073787 00073787 00073F66 00073F66 000749F3 000749F3 0009FEBD 0009FEBD TEST main 1951 00000105 00000465 If I comment out the "close" sections in both the parent and the child, it works (!) on the VAX but continues to die on the ALPHA (output is the same as above). On the VAX: entering child child's write into pipe, successful entering parent parent's read successful, n = 1 parent write to stdout successful What am I doing wrong? Help! Thanks, -Steve Harris The Answer is : The "else if (pid == 0) /* child */ { /* ... */ }" branch of the code needs to call one of the exec* family of functions, preferably before doing anything else. On UNIX systems, the fork function causes a new process to be created, but the C run-time library vfork function on OpenVMS does not. Instead, it acts more like setjmp -- when you call vfork it returns zero the first time (in the one and only process usually called parent), then the code must call one of the exec* family of functions, after which vfork returns a second time with a nonzero value in the parent (negative means error, positive is the pid of the newly created child process, which doesn't exist if an exec* function was not called). In OpenVMS V7.2, there is a new CRTL function: decc$set_child_standard_streams() which makes it a somewhat easier to port Unix applications using a real fork() function to VMS. Attached is the description of this function from DEC C Run-Time Library Reference Manual Order Number: AA-PUNEF-TK which is shipped with the DEC C V6.0 compiler. There is an example of parent/child communication in this description. decc$set_child_standard_streams() was ECOed to V7.1 and is available in the CRTL backport object library. This type of parent/child communication works not only for pipes, but for sockets also and, as the example shows, for both .C and .COM child. decc$set_child_standard_streams For a child spawned by a function from the exec family of functions, associates specified file descriptors with a child's standard streams: stdin, stdout, and stderr. ---------------------------------------------------------------------------- Format #include <unistd.h> int decc$set_child_standard_streams (int fd1, int fd2, int fd3); ---------------------------------------------------------------------------- Arguments fd1 The file associated with this file descriptor in the parent process is associated with file descriptor number 0 (stdin) in the child process. If -1 is specified, the file associated with the parent's file descriptor number 0 is used (the default). fd2 The file associated with this file descriptor in the parent process is associated with file descriptor number 1 (stdout) in the child process. If -1 is specified, the file associated with the parent's file descriptor number 1 is used (the default). fd3 The file associated with this file descriptor in the parent process is associated with file descriptor number 2 (stderr) in the child process. If -1 is specified, the file associated with the parent's file descriptor number 2 is used (the default). ---------------------------------------------------------------------------- Description This function allows mapping of specified file descriptors to the child's stdin/out/err streams, thereby compensating, to a certain degree, the lack of a real fork function on OpenVMS systems. On UNIX systems, the code between fork and exec is executed in the context of the child process: parent: create pipes p1, p2 and p3 fork child: map stdin to p1 like dup2(stdin, p1); map stdout to p2 like dup2(stdout, p2); map stderr to p3 like dup2(stderr, p3); exec (child reads from stdin and writes to stdout and stderr) exit parent: communicates with the child using pipes On OpenVMS systems, the same task could be achieved as follows: parent: create pipes p1, p2 and p3 decc$set_child_standard_streams(p1, p2, p3); vfork exec (child reads from stdin and writes to stdout and stderr) parent: communicates with the child using pipes Once established through the call to decc$set_child_standard_streams , the mapping of the child's standard streams remains in effect until explicitly disabled by one of the following calls: decc$set_child_standard_streams(-1, -1, -1); OR decc$set_child_standard_streams(0, 1, 2); Usually, the child process inherits all its parent's open file descriptors. However, if file descriptor number n was specified in the call to decc$set_child_standard_streams , it is not inherited by the child process as file descriptor number n; instead, it becomes one of the child's standard streams. ---------------------------------------------------------------------------- Return Value x The number of file descriptors set for the child. This number does not include file descriptors specified as --1 in the call. --1 indicates that an invalid file descriptor was specified; errno is set to EBADF. ---------------------------------------------------------------------------- Example parent.c ======== #include <stdio.h> #include <string.h> #include <unistd.h> int decc$set_child_standard_streams(int, int, int); main() { int fdin[2], fdout[2], fderr[2]; char msg[] = "parent writing to child's stdin"; char buf[80]; int nbytes; pipe(fdin); pipe(fdout); pipe(fderr); if ( vfork() == 0 ) { decc$set_child_standard_streams(fdin[0], fdout[1], fderr[1]); execl( "child", "child" ); } else { write(fdin[1], msg, sizeof(msg)); nbytes = read(fdout[0], buf, sizeof(buf)); buf[nbytes] = '\0'; puts(buf); nbytes = read(fderr[0], buf, sizeof(buf)); buf[nbytes] = '\0'; puts(buf); } } child.c ======= #include <stdio.h> #include <unistd.h> main() { char msg[] = "child writing to stderr"; char buf[80]; int nbytes; nbytes = read(0, buf, sizeof(buf)); write(1, buf, nbytes); write(2, msg, sizeof(msg)); } child.com ========= $ read sys$command s $ write sys$output s $ write sys$error "child writing to stderr" This example program returns the following for both child.c and child.com: $ run parent parent writing to child's stdin child writing to stderr Note that in order to activate child.com , you must explicitly specify execl("child.com", ...) in the parent.c program.
|