Re: [take24 0/6] kevent: Generic event handling mechanism.

Ulrich Drepper
2006-11-21T17:02:57Z

Evgeniy Polyakov wrote:
>> You don't want to have a channel like this. The userlevel code doesn't
>> know which threads are waiting in the kernel on the event queue. And it
>> seems to be much more complicated then simply have an kevent call which
>> tells the kernel "wake up N or 1 more threads since I cannot handle it".
>> Basically a futex_wake()-like call.
>
> Kernel does not know about any threads which waits for events, it only
> has queue of events, it can only wake those who was parked in
> kevent_get_events() or kevent_wait(), but syscall will return only when
> condition it waits on is true, i.e. when there is new event in the ready
> queue and/or ring buffer has empty slots, but kernel will wake them up
> in any case if those conditions are true.
>
> How should it know which syscall should be interrupted when special syscall
> is called?

It's not about interrupting any threads.

The issue is that the wakeup of a thread from the kevent_wait call
constitutes an "event notification". If, as it should be, only one
thread is woken than this information mustn't get lost. If the woken
thread cannot work on the events it got notified for, then it must tell
the kernel about it so that, *if* there are other threads waiting in
kevent_wait, one of those other threads can be woken.

What is needed is a simple "wake another thread waiting on this event
queue" syscall. Yes, in theory we could open an additional pipe with
each event queue and use it for waking threads, but this is influencing
the ABI through the use of a file descriptor. It's much better to have
an explicit way to do this.

> No AIO, but syscall.
> Only syscall time matters.
> Syscall starts, it sould be sometime stopped. When it should be stopped?
> It should be stopped after some time after it was started!
>
> I still do not understand how will you use absolute timeout values
> there. Please exaplain.

What is there to explain? If you are waiting for events which must
coincide with real-world events you'll naturally will want to formulate
something like "wait for X until 10:15h". You cannot formulate this
correctly with relative timeouts since the realtime clock might be adjusted.

> futex_wait() uses relative timeouts:
> static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
>
> Kernel use relative timeouts.

Look again. This time at the implementation. For FUTEX_LOCK_PI the
timeout is an absolute timeout.

> We have not have such symmetry.
> Other event handling interfaces can not work with events, which do not
> have file descriptor behind them. Kevent can and works.
> Signals are just usual events.
>
> You request to get events - and you get them.
> You request to not get events during syscall - you remove events.

None of this matches what I'm talking about. If you want to block a
signal for the duration of the kevent_wait call this is nothing you can
do by registering an event.

Registering events has nothing to do with signal masks. They are not
modified. It is the program's responsibility to set the mask up
correctly. Just like sigwaitinfo() etc expect all signals which are
waited on to be blocked.

The signal mask handling is orthogonal to all this and must be explicit.
In some cases explicit pthread_sigmask/sigprocmask calls. But this is
not atomic if a signal must be masked/unmasked for the *_wait call.
This is why we have variants like pselect/ppoll/epoll_pwait which
explicitly and *atomically* change the signal mask for the duration of
the call.

> Btw, please point me to the discussion about real life usefullness of
> that parameter for epoll. I read thread where sys_pepoll() was
> intruduced, but except some theoretical handwaving about possible
> usefullness there are no real signs of that requirement.

Don't search for epoll_pwait, it's not widely used yet. Search for
pselect, which is standardized. You'll find plenty of uses of that
interface. The number is certainly depressed in the moment since until
recently there was no correct implementation on Linux. And the
interface is mostly used in real-time contexts where signals are more
commonly used.

> What is the ground research or extended explaination about
> blocking/unblocking some signals during syscall execution?

Why is this even a question? Have you done programming with signals?
You hatred of signals makes me think this isn't the case.

You might want to unblock a signal on a *_wait call if it can be used to
interrupt the wait but you don't want this to happen during when the
thread is working on a request.

You might want to block a signal, for instance, around a sigwaitinfo
call or, in this case, a kevent_wait call where the signal might be
delivered to the queue.

There are countless possibilities. Signals are very flexible.

> There are _no_ additional syscalls.
> I just introduced new case for event type.

Which is a new syscall. All demultiplexer cases are no syscalls.
Which, BTW, implies that unrecognized types should actually cause a
ENOSYS return value (this affects kevent_break). We've been over this
many times. If EINVAL is return this case cannot be distinguished from
invalid parameters. This is crucial for future extensions where
userland (esp glibc) needs to be able to determine whether a new feature
is supported on the system.

> You _need_ it to be done, since any kernel kevent user must have
> enqueue/dequeue/callback callbacks. It is just an implementation of that
> callbacks.

I don't question that. But there is no need to add the callback. It
extends the kernel ABI/API. And for what? A vastly inferior timer
implementation compared to the POSIX timers. And this while all that
needs to be done is to extend the POSIX timer code slightly to handle
SIGEV_KEVENT in addition to the other notification methods currently
used. If you do it right then the code can be shared with the file AIO
code which currently is circulated as well and which uses parts of the
POSIX timer infrastructure.

> Btw, how POSIX API should be extended to allow to queue events - queue
> is required (which is created when user calls kevent_init() or
> previoisly opened /dev/kevent), how should it be accessed, since it is
> just a file descriptor in process task_struct.

I've explained this multiple times. The struct sigevent structure needs
to be extended to get a new part in the union. Something like

struct {
int kevent_fd;
void *data;
} _sigev_kevent;

Then define SIGEV_KEVENT as a value distinct from the other SIGEV_
values. In the code which handles setup of timers (the timer_create
syscall), recognize SIGEV_KEVENT and handle it appropriately. I.e.,
call into the code to register the event source, just like you'd do with
the current interface. Then add the code to post an event to the event
queue where currently signals would be sent et voilà.

--
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖