INF: Spawned Program Accessing Parent's Functions

ID Number: Q43318

5.10 6.00 6.00a 6.00ax 7.00 | 5.10 6.00 6.00a

MS-DOS | OS/2

Summary:

In Microsoft C versions 5.0, 5.1, 6.0, 6.0a, 6.0ax, and C/C++ version

7.0, a program spawned with the P_WAIT modeflag can successfully call

functions within its parent. The functions must be set up in such a

way, however, that CPU registers are preserved and the data segment

register is loaded as necessary. It is also very important that all

necessary startup code and C run time library routines are present

whenever the parent functions are called.

Warning: This procedure is neither recommended nor supported. This

article is for informational purposes only. Additionally, for C/C++

7.0, this procedure works only in the large memory model.

More Information:

The programs below, PARENT.C and CHILD.C, demonstrate this technique.

This method of sharing functions may be useful as a primitive form of

overlaying when there is a need for a common set of functions to be

accessed by a sequence of spawned child processes. The method of

communication from the parent to the child is through command-line

arguments. In the parent, a far pointer to the function that will be

called is converted to a string and passed as a parameter through a

spawn. In the child, it is then converted back into a far pointer.

There are several considerations to be made when writing code of this

nature:

- For any variables in the parent to be accessed, the routines to be

called must use the _loadds keyword. Not loading DS for the called

function results in the child's DS being used rather than the DS

associated with the function in the parent.

- Even if _loadds is used, however, DS will not be equal to SS,

because the child's stack is the one that is used and there is no

mechanism in C for changing stacks. It is necessary to ensure that

the functions called by the child do not blow out the child's

stack.

- Many of the run-time library routines rely on SS equaling DS;

therefore, one must avoid those routines.

- Preservation of the child's state can be accomplished by using the

_saveregs keyword. This is not necessary when calling C from C;

however, it may be vital if C is being called from MASM.

- All calls must be far because the parent and child are loaded

separately. Different memory models may be used for parent and

child.

- This process obviously produces a general-protection fault (GP

fault) in OS/2. Use dynamic-link libraries to duplicate this

functionality with greater ease, portability, and safety.

Sample Code:

------------

The following is the parent program:

/*

* PARENT.C

*/

#include <stdio.h>

#include <stdlib.h>

#include <process.h>

int far _saveregs _loadds foo(void);

void main(void);

int k = 0, l = 0; /* Globals to be accessed inside foo */

int far _saveregs _loadds foo(void)

{

int i, /* Return value */

j; /* Indexing */

for (j = 1; j < 10; j++) {

k = k + j;

l = k * j;

}

i = k + l;

return (i);

}

void main()

{

int (far _saveregs _loadds * fooaddr) (void); /* foo() pointer */

char address[16]; /* address to pass */

printf("Now inside parent main().\n");

fooaddr = (int (far _saveregs _loadds *) (void)) foo;

ultoa((unsigned long) fooaddr, address, 10);

printf("Address of foo(): %s\n", address);

spawnlp(P_WAIT, "child.exe", "child.exe", address, NULL);

printf("Back inside parent main().\n");

}

The following is the child program:

/*

* CHILD.C

*/

#include <stdio.h>

#include <stdlib.h>

void main(int argc, char **argv)

{

int (far _loadds _saveregs * fooaddr)(void);

/* Pointer to parent's function */

int i; /* Function return value */

printf(" Now in child.\n");

fooaddr = (int (far _loadds _saveregs *)(void))atol(argv[1]);

printf(" Received: %ld\n", fooaddr);

printf(" Calling foo().\n");

i = fooaddr();

printf(" Result of foo(): %d\n", i);

printf(" Leaving child.\n");

}

Additional reference words: 6.0 6.00 6.0a 6.00a 6.0ax 6.00ax quickc

2.0 2.00 2.01 2.5 2.50 2.51 7.00