Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Jul 2001 12:57:31 -0700
From:      Terry Lambert <tlambert2@mindspring.com>
To:        y-carden@uniandes.edu.co
Cc:        hackers@FreeBSD.ORG
Subject:   Re: Invoking a userland function from kerne
Message-ID:  <3B646AAB.688669C5@mindspring.com>
References:  <M2001072710454811702@vaca.uniandes.edu.co>

next in thread | previous in thread | raw e-mail | index | archive | help
y-carden@uniandes.edu.co wrote:
> Now, I need manage Timed Events:
> 
> Two RTP related events must occur which are timed. They are:
> 
> 1.RTCP (control RTP packages) reports must be sent periodically.
> 2.BYE (a control RTP package) packets may be reconsidered for transmission.
> 
> To support scheduling, timed events are handled by two functions,
> RTPSchedule() and RTPExecute().
> 
> The first of these functions is written by the user(user process).
> It is called by the RTP kernel module (originally the library)
> to request scheduling of events at some predetermined time.

Called, or invoked?

If it's invoked (no parameters needed), then you can implement
a kevent that occurs at the right time.  The main look of your
program listens for kevents, including this one, and then it
dispatches the event  to the RTPSchedule() function.

If, on the other hand, you need to pass parameters, then you
should implement it differently.  My suggestion would be to
implement a system call/ioctl that takes the address of a
parameter block structure as an argument, and then sleeps on
a well known address (tsleep for 4.x, msleep for -current),
waiting for a request from the kernel.  When the kernel wants
to make the request to user space, it copies out the request
parameters into the parameter block structure, and then wakes
up the sleeping process (via wakeup).  When that process runs
in user space, it calls RTPSchedule() with the results of the
system call, which are really the parameters for the schedule
call.  Once this has completed, it makes the same system call
again, goes back to sleep, and waits for the next schedule
request from the kernel.  THe call back down _could_ provide
the results of the RTPSchedule() function to the kernel module,
if necessary (via copyin; you would need to set up a flag field
so that the first call down ends up doing nothing, since it
will have no "results" to give the kernel module).

This is backward from the way that people normally use a system
call interface, but there is a lot of precedent, including a
lot of NFS implementations, which do this sort of thing.

If you need to do user space processing on top of that, then
you should look at the sfork system call man page.  It will
tell you how to get another process context into your single
process, so that you can have a blocking context on which to
make your call.  If you modify scheduling parameters in user
space from the other part of your process, you will need to
actually protect your data structures.  You can implement a
light weight lock to do this using the cmpxchgl (compare and
exchange, locked) instruction (assuming this is x86; other
architectures will have other instructions).  You should not
hold this lock over system calls, etc..  If you need help with
the lock, you should look at the code in atomic.h in -current,
which has implementations of these operations (most are much
more complicated than they need to be).


> void RTPSchedule(int id, void* opaque, struct timeval *tp);
> 
> rtperror RTPExecute(int id, void* opaque);
> 
> The RTP kernel module will call RTPSchedule, and pass it the context cid
> and an opaque piece of data, opaque. It will also pass the time for
> which the scheduled event is to occur, tp. At the appropriate time,
> tp, the application should call RTPExecute, and pass it the opaque
> token provided in the call to RTPSchedule, in addition to the identifier
> id.

IMO, you would be much better off implementing most of this
in the kernel, using the existing timer functions; the policy
could still live in user space.  Realize that this will not
be true Real Time, since your process will have to get a quantum
in order to be able to run the scheduler.


> This general mechanism allows for the RTP kernel module to schedule
> arbitrary timed events. All information about the nature of the
> events is kept internal. The opaque data is used internally to
> identify particular events.

You may want to check out "setitimer", and do the minor work
needed to manage the deltas from one event to another in order
to achieve minimal latency.  Realize, again, that anything you
end up doing will actually fire at "the next quantum following
the even expiration", rather than "immediately, at the event
expiration; hopefully this is high enough granularity for you,
though I suspect you will want to decrease the size of the
quantum using sysctl, to ensure things run faster, and may also
want to use rtprio to set the priority on the process (to make
sure no other process gets the quantum before your, which could
lead to a multiqiantum lag, if your system is at all loaded).
If you use the sfork approach (above), then you will need to
remember to set it on both the parent and the child (sfork'ed)
process.


> So, my original question was:
> Into my kernel code, How I can call to
> RTPSchedule() userland function?
> 
> You say me that I can do with kevent() facility.
> 
> How I can do it exactly?

You send an event to user space, and the user space code is
built around an event processing loop (I'm surprised that
the user space threads implementation has not be rebuilt
around kevent, actually).

This is the same as the system call "completing" actually
being a call back into user space (per above), but the
request and the completion are asynchronous, and, unlike
non-blocking fd's, they are not required to be retried in
the event that they can not go through immediately.


> I apologize perhaps the following is stupid,
> but from the user process  I can call kevent()
> for a file descriptor and into kernel when I need
> call to RTPSchedule() instead I would try for example to write
> to file descriptor to trigger the event.  Can I do this?
> I don't sure but into kernel it can't write to file descriptor.

You can send events using KNOTE().  These have to be noted on a
file descriptor, yes, but you can do that using a pseudo device
for your kernel module, which KNOTE()'s when it wants the user
space program to make a policy decision.

Again, this only works if your main program loop is a kevent loop
waiting for events.

If your main program is more traditional, which is probable,
given the library description you have provided, then the sfork()
and inverted system call interface is probably your best bet.

-- Terry



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3B646AAB.688669C5>