Process Control/Pipe Tutorial

From EDM2
Jump to: navigation, search

By Johann Oskarsson

This is a short tutorial on spawning a background process, and reading its standard output through a pipe.

The following is a simple program that spawn a subprocess, and reads its standard output, which it then writes out again. It does lack error checking and variable names could be better. It is also meant to be used with the classic "Hello, World" program that prints to STDOUT, not the VIO hello-world example. It does not matter what programming language is used to create it, only the executable has to be "HELLO.EXE". If you need to call the executable something else, you'll need to modify the DosExecPgm() call.

#define INCL_DOSQUEUES
#define INCL_DOSPROCESS
#define INCL_DOSFILEMGR
#include <os2.h>

// The reason I'm using my own constants, as opposed to the ones
// defined in os2.h, is that their definition seems to conflict
// with my use of the | operator.
const unsigned long int open_flags_dasd = 0x8000; // bit 15
const unsigned long int open_flags_write_through = 0x4000; //bit 14
const unsigned long int open_fail_on_error = 0x2000; // bit 13
const unsigned long int open_flags_no_cache = 0x1000; // bit 12

// ... irrelevant constants skipped ...

const unsigned long int open_flags_no_inherit = 0x0080; // bit 7

int main( int argc, char *argv[] )
{
       HFILE pipe1_in = 0, pipe1_out = 0;
       DosCreatePipe( &pipe1_in, &pipe1_out, 50 );


       // And to prevent the child process from inheriting
       // the read handle of the pipe.
       unsigned long int m;
       DosQueryFHState( pipe1_in, &m );
       // bits 0-6, 8-11, 15 must be 0
       // that is, only the following flags are legal
       // in DosSetFHState()
       unsigned long int mask = open_flags_write_through |
               open_fail_on_error |
               open_flags_no_cache |
               open_flags_no_inherit;
       m &= mask; 
       m |= open_flags_no_inherit;
       DosSetFHState( pipe1_in, m );
	

       // Duplicate standard output
       HFILE mystdout = -1;
       DosDupHandle( 1, &mystdout );
	
       // Close STDOUT since otherwise the subprocess will inherit it.
       // After this, using printf will not work, but writing to
       // mystdout will have the same effeccts.
       DosClose( 1 );

       // On second thought, the above DosClose() is probably redundant
       // since DosDupHandle will close it as well, but it doesn't hurt.

       // Set STDOUT of child process
       HFILE childout = 1;
       DosDupHandle( pipe1_out, &childout );

       // Spawn process
       char buffer[25];
       RESULTCODES res;
       DosExecPgm( buffer, 25, EXEC_ASYNCRESULT, 0, 0, &res, "hello.exe" );


       // Read output of subprocess
       char rbuffer[100];
       ULONG bread = 0;
       DosRead( pipe1_in, rbuffer, 100, &bread );
 
       // Print the output to STDOUT
       DosWrite( mystdout, rbuffer, bread, &bread );

       PID p;
       // Wait for child process to terminate
       DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &res, &p, res.codeTerminate );

       // and return the exit code of the child
       return res.codeResult;
}