Subject: Re: pthreads in userland, signals, and itimer.
To: None <wennmach@geo.Uni-Koeln.DE>
From: Michael Graff <explorer@flame.org>
List: tech-kern
Date: 11/09/1999 07:17:52
"Dr. Lex Wennmacher" <wennmach@geo.Uni-Koeln.DE> writes:

> I can very well understand your need for more timers and
> signals. But I think just adding SIGTHREAD and thread timers is
> suboptimal. We should be looking for a more general solution to the
> problem.

As do I, now.

> A threading library would just issue this system call and get a
> currently unused timer/signal pair, install a signal handler and set
> the timer (in the usual fashion). Threading libraries share (the
> new) timers with other libraries and applications.

This will add a lot of new timers/signals, but I do see the need.
I'll look into this idea.  I don't know how much of an impact it will
have on things like context switches and the like, but in the case
where no timers are allocated in this way things should be reasonably
fast.

Decisions to make:

(1)  Should we have, say, 16 virtual and 16 real timers?  Or 8/8?
     Remember that for each virtual timer there will be more work to
     do at context switch time, and for each real timer there will be
     an additional timeout in the kernel.

(2)  Should we not decide on the layout of timers, but do even more
     work in the clock tick checking every possible virtual timer?

I suspect we'd need to attach something like this to every process,
and keep it resident, since I'd like to avoid the real/virtual timer
split, but have only 16 timers, of which 3 are "pre-allocated" for the
already present ITIMER_* values.  This excludes ITIMER_THREAD and
ITIMER_THREADV, but if those are used, that still leaves 11 new timers
that processes can use.

struct itimer_control {
	struct itimerval itimer;
	struct proc *p;
	u_int32_t flags;
};

The proc pointer is needed because timeout() only takes one argument.
We could bypass that by having to check each itimer in the process to
see if it has expired or not, but I think it would be faster to just
"know" which itimer has expired.

Alternate method:

struct proc {
	...
	u_int16_t itimer_virtual;
	u_int16_t itimer_active;
	u_int16_t itimer_allocated;
	struct itimerval itimers[16];
	...
};

Then, on each context switch, something like this:

	virtual_timers = itimer_virtual & itimer_active;
	for each bit set {
		check expiration.  If expired, signal.
	}

The more I think about it, the more this bit probably makes sense.

We could make this 32 instead of 16 more easily using the second
method, I think...

--Michael