[comp.sys.sun] Child control with the Notifier

carver@atmos-modelling.chemistry.cambridge.ac.uk (Glenn Carver) (10/05/90)

I'm having problems trying to get the child control that I need with an
application using SunView.

The structure of the program comprises main.c which sets up the
application window and calls window_main_loop().  Then when the user
presses a button on the window, a notify procedure gets called which
consists of a loop over roughly 100 iterations.  On each pass of the loop,
a child is created to perform a small task.  The time of the child in
relation to the time of each loop pass is small so each child terminates
before the next child is created. 

My problem is that I cannot avoid the maximum process limit. Normally, a
wait(2) call would clear the terminated child. However, according to the
SunView manual, I cannot do a wait(2) call using SunView but have to
register a wait3 event handler via notify_set_wait3_func().

I tried registering the default handler notify_default_wait3() but this
did not help. While the program was running, using the ps command still
shows child processes that are <exiting>, so that after 30 passes of the
loop I have 30 <exiting> children.  However, when the loop and my notify
proc terminate and control returns to the notifier, the child processes
disappear.  This suggests that the child processes are not fully 'reaped'
until control returns to the notifier.

Is there any way out of this?  Can I, for example, register my own wait3
event handler which itself calls wait(2), or does this still violate the
notify convention. Or alternatively, can I force the notifier to do a
wait() whilst still in the loop to remove the child process previously
created completely.

Please email me directly.  I will summarise.  All help much
appreciated. Currently using SunOS 3.5.

Glenn Carver                              Phone (44-223) 336521
Cambridge University, UK.        email: carver@atm.ch.cam.ac.uk

Mark_Weiser.PARC@xerox.com (11/01/90)

The problem is that you have to give control back to the notifier so that
it can do the wait for you and reap the children.  As long as you are in
your loop the notifier cannot do anything.

This is a very common problem, and the solution I use is to, rather than
loop, schedule myself to run again ASAP and return to the notifier,
keeping track of the iterations with a global variable.  This problem came
up so often that I wrote the following  simple routines to make it easier
to schedule an arbitrary procedure call in the future:

/*
 * Call procedure f in a little while.
 */

struct call_wrapper {
	/* Dynamically allocating a wrapper ensures unique notifier id's. */
	void (*f)();
}

do_with_delay(f, secs, usecs)
void (*f)();
int secs, usecs;
{
	Notify_value do_the_call();
	struct call_wrapper *w;
	struct itimerval timer;

	/* Sigh, so much work just to wait a bit before starting up. */
	timer.it_interval.tv_usec = 0;
	timer.it_interval.tv_sec = 0;
	timer.it_value.tv_usec = usecs;
	timer.it_value.tv_sec = secs;
 	w = (struct call_wrapper *)calloc(sizeof(struct call_wrapper), 1);
	w->f = f;
	notify_set_itimer_func(w, do_the_call,
		ITIMER_REAL, &timer, NULL);
}

/*
 * Wrapper to make sure procedures from do_with_delay return good values
 * to the notifier.
 */
Notify_value
do_the_call(w, which)
struct call_wrapper *w;
{
	(*(w->f))();
	free(w);
	return NOTIFY_DONE;
}