From owner-freebsd-hackers Sun Jul 29 13:21:17 2001 Delivered-To: freebsd-hackers@freebsd.org Received: from harrier.mail.pas.earthlink.net (harrier.mail.pas.earthlink.net [207.217.121.12]) by hub.freebsd.org (Postfix) with ESMTP id 39FCB37B401 for ; Sun, 29 Jul 2001 13:21:06 -0700 (PDT) (envelope-from tlambert2@mindspring.com) Received: from mindspring.com (dialup-209.245.140.234.Dial1.SanJose1.Level3.net [209.245.140.234]) by harrier.mail.pas.earthlink.net (EL-8_9_3_3/8.9.3) with ESMTP id NAA23806; Sun, 29 Jul 2001 13:20:08 -0700 (PDT) Message-ID: <3B646AAB.688669C5@mindspring.com> Date: Sun, 29 Jul 2001 12:57:31 -0700 From: Terry Lambert Reply-To: tlambert2@mindspring.com X-Mailer: Mozilla 4.7 [en]C-CCK-MCD {Sony} (Win98; U) X-Accept-Language: en MIME-Version: 1.0 To: y-carden@uniandes.edu.co Cc: hackers@FreeBSD.ORG Subject: Re: Invoking a userland function from kerne References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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