Open System Services Programmer's Guide

/* flexible than exec */
/* find next available cpu */
do {
cpuindex = (++cpuindex == cpucount) ? 0 : cpuindex;
} while (((cpumask >> (15-cpuindex)) & 1) == 0);
peparm.pe_cpu = cpuindex;
inherit.flags = 0;
if ((newpid = fork()) < 0)
{
fprintf(stderr, "fork() failed [errno %d]\n", errno);
exit(1);
}
else if (newpid == 0)
{
/* we are child ... spawn grandchild to avoid zombie processes */
tdm_spawn(childargv[0], 0, NULL, &inherit,
childargv, environ, &peparm, &perslt);
exit(0); /* child goes away */
}
else
{
/* we are parent */
fprintf(stderr, "dserver spawn'ed in cpu %d\n", peparm.pe_cpu);
wait(&newpid); /* wait for child to avoid zombie child process */
close(STDIN_FILENO);
close(STDOUT_FILENO);
}
} /* end while (1) */
}
Using Static Servers Spread Across Available Processors
Example 38 can be further optimized as a launcher for iterative static servers, as shown in
Example 39 (page 143). This program uses AF_UNIX sockets and launches a static server in each
processor as soon as it starts; that provides maximum scalability immediately and slightly better
responsiveness by eliminating the process-creation delay when handling each new connection.
The server program in Example 39 is compiled as a linked program file named slaunch1. The
server program in Example 40 is compiled as a linked program file named sserver. (A requester
program, shown in Example 44 (page 182), is also compiled as a linked program file named
requester2.) All programs are secured for execution in the current working directory.
In this application, slaunch1 creates an AF_INET socket and listens for incoming connections
from one or more copies of requester2. It then starts a copy of sserver in each available
processor.
142 Managing Processes