base/tasklets/tasklets.c

Go to the documentation of this file.
00001 /**
00002  * @ingroup tasklets
00003  * @file
00004  *
00005  * Implementation of the @ref tasklets "RTAI tasklets module".
00006  *
00007  * @author Paolo Mantegazza
00008  *
00009  * @note Copyright &copy; 1999-2006 Paolo Mantegazza <mantegazza@aero.polimi.it>
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License as
00013  * published by the Free Software Foundation; either version 2 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00024  */
00025 
00026 /**
00027  * @defgroup tasklets module
00028  *
00029  * The tasklets module adds an interesting feature along the line, pioneered
00030  * by RTAI, of a symmetric usage of all its services inter-intra kernel and 
00031  * user space, both for soft and hard real time applications.   In such a way 
00032  * you have opened a whole spectrum of development and implementation
00033  * lanes, allowing maximum flexibility with uncompromized performances.
00034  *
00035  * The new services provided can be useful when you have many tasks, both 
00036  * in kernel and user space, that must execute simple, often ripetitive, 
00037  * functions, both in soft and hard real time, asynchronously within their 
00038  * parent application. Such tasks are here called tasklets and can be of 
00039  * two kinds: normal tasklets and timed tasklets (timers).
00040  *
00041  * It must be noted that only timers should need to be made available both in
00042  * user and kernel space.   In fact normal tasklets in kernel space are nothing
00043  * but standard functions that can be directly executed by calling them, so
00044  * there would be no need for any special treatment.   However to maintain full
00045  * usage symmetry and to ease any possible porting from one address space to
00046  * the other, plain tasklets can be used in the same way from whatever address 
00047  * space.
00048  *
00049  * Tasklets should be used where and whenever the standard hard real time 
00050  * RTAI tasks are used.  Instances of such applications are timed polling and 
00051  * simple Programmable Logic Controllers (PLC) like sequences of services.   
00052  * Obviously there are many others instances that can make it sufficient the 
00053  * use of tasklets, either normal or timers.   In general such an approach can 
00054  * be a very useful complement to fully featured tasks in controlling complex
00055  * machines and systems, both for basic and support services.
00056  *
00057  * It is remarked that the implementation found here for timed tasklets rely on
00058  * server support tasks, one per cpu, that execute the related timer functions, 
00059  * either in oneshot or periodic mode, on the base of their time deadline and 
00060  * according to their, user assigned, priority. Instead, as told above, plain 
00061  * tasklets are just functions executed from kernel space; their execution 
00062  * needs no server and is simply triggered by calling a given service function 
00063  * at due time, either from a kernel task or interrupt handler requiring, or in
00064  * charge of, their execution whenever they are needed.
00065  *
00066  * Note that in user space you run within the memory of the process owning the
00067  * tasklet function so you MUST lock all of your tasks memory in core, by
00068  * using mlockall, to prevent it being swapped out.   Pre grow also your stack 
00069  * to the largest size needed during the execution of your application, see 
00070  * mlockall usage in Linux mans.
00071  *
00072  * The RTAI distribution contains many useful examples that demonstrate the use
00073  * of most tasklets services, both in kernel and user space.
00074  *
00075  *@{*/
00076 
00077 #include <linux/module.h>
00078 #include <linux/version.h>
00079 #include <linux/proc_fs.h>
00080 #include <linux/sched.h>
00081 #include <linux/slab.h>
00082 #include <linux/interrupt.h>
00083 #include <asm/uaccess.h>
00084 #include <asm/system.h>
00085 #include <asm/rtai_sched.h>
00086 #include <rtai_tasklets.h>
00087 #include <rtai_lxrt.h>
00088 #include <rtai_malloc.h>
00089 #include <rtai_schedcore.h>
00090 
00091 MODULE_LICENSE("GPL");
00092 
00093 extern struct epoch_struct boot_epoch;
00094 
00095 DEFINE_LINUX_CR0
00096 
00097 #ifdef CONFIG_SMP
00098 #define NUM_CPUS           RTAI_NR_CPUS
00099 #define TIMED_TIMER_CPUID  (timed_timer->cpuid)
00100 #define TIMER_CPUID        (timer->cpuid)
00101 #define LIST_CPUID         (cpuid)
00102 #else
00103 #define NUM_CPUS           1
00104 #define TIMED_TIMER_CPUID  (0)
00105 #define TIMER_CPUID        (0)
00106 #define LIST_CPUID         (0)
00107 #endif
00108 
00109 
00110 static struct rt_tasklet_struct timers_list[NUM_CPUS] =
00111 { { &timers_list[0], &timers_list[0], RT_SCHED_LOWEST_PRIORITY, 0, 0, RT_TIME_END, 0LL, NULL, 0UL, 0UL, 0, NULL, NULL, 0, 
00112 #ifdef  CONFIG_RTAI_LONG_TIMED_LIST
00113 { NULL } 
00114 #endif
00115 }, };
00116 
00117 static struct rt_tasklet_struct tasklets_list =
00118 { &tasklets_list, &tasklets_list, };
00119 
00120 static spinlock_t timers_lock[NUM_CPUS] = { SPIN_LOCK_UNLOCKED, };
00121 static spinlock_t tasklets_lock = SPIN_LOCK_UNLOCKED;
00122 
00123 static struct rt_fun_entry rt_tasklet_fun[]  __attribute__ ((__unused__));
00124 
00125 static struct rt_fun_entry rt_tasklet_fun[] = {
00126     { 0, rt_init_tasklet },         //   0
00127     { 0, rt_delete_tasklet },           //   1
00128     { 0, rt_insert_tasklet },           //   2
00129     { 0, rt_remove_tasklet },           //   3
00130     { 0, rt_tasklet_use_fpu },          //   4
00131     { 0, rt_insert_timer },         //   5
00132     { 0, rt_remove_timer },         //   6
00133     { 0, rt_set_timer_priority },       //   7
00134     { 0, rt_set_timer_firing_time },    //   8
00135     { 0, rt_set_timer_period },         //   9
00136     { 0, rt_set_tasklet_handler },      //  10
00137     { 0, rt_set_tasklet_data },         //  11
00138     { 0, rt_exec_tasklet },         //  12
00139     { 0, rt_wait_tasklet_is_hard },     //  13
00140     { 0, rt_set_tasklet_priority },     //  14
00141     { 0, rt_register_task },        //  15
00142     { 0, rt_get_timer_times },      //  16  
00143     { 0, rt_get_timer_overrun },        //  17  
00144         
00145 /* Posix timers support */  
00146 
00147     { 0, rt_ptimer_create },        //  18
00148     { 0, rt_ptimer_settime },       //  19
00149     { 0, rt_ptimer_overrun },       //  20
00150     { 0, rt_ptimer_gettime },       //  21
00151     { 0, rt_ptimer_delete }         //  22  
00152     
00153 /* End Posix timers support */
00154     
00155 };
00156 
00157 #ifdef CONFIG_RTAI_LONG_TIMED_LIST
00158 
00159 /* BINARY TREE */
00160 static inline void enq_timer(struct rt_tasklet_struct *timed_timer)
00161 {
00162     struct rt_tasklet_struct *timerh, *tmrnxt, *timer;
00163     rb_node_t **rbtn, *rbtpn = NULL;
00164     timer = timerh = &timers_list[TIMED_TIMER_CPUID];
00165     rbtn = &timerh->rbr.rb_node;
00166 
00167     while (*rbtn) {
00168         rbtpn = *rbtn;
00169         tmrnxt = rb_entry(rbtpn, struct rt_tasklet_struct, rbn);
00170         if (timer->firing_time > tmrnxt->firing_time) {
00171             rbtn = &(rbtpn)->rb_right;
00172         } else {
00173             rbtn = &(rbtpn)->rb_left;
00174             timer = tmrnxt;
00175         }
00176     }
00177     rb_link_node(&timed_timer->rbn, rbtpn, rbtn);
00178     rb_insert_color(&timed_timer->rbn, &timerh->rbr);
00179     timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer;
00180     timed_timer->next = timer;
00181 }
00182 
00183 #define rb_erase_timer(timer) \
00184 rb_erase(&(timer)->rbn, &timers_list[NUM_CPUS > 1 ? (timer)->cpuid : 0].rbr)
00185 
00186 #else /* !CONFIG_RTAI_LONG_TIMED_LIST */
00187 
00188 /* LINEAR */
00189 static inline void enq_timer(struct rt_tasklet_struct *timed_timer)
00190 {
00191     struct rt_tasklet_struct *timer;
00192     timer = &timers_list[TIMED_TIMER_CPUID];
00193         while (timed_timer->firing_time > (timer = timer->next)->firing_time);
00194     timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer;
00195     timed_timer->next = timer;
00196 }
00197 
00198 #define rb_erase_timer(timer)
00199 
00200 #endif /* CONFIG_RTAI_LONG_TIMED_LIST */
00201 
00202 static inline void rem_timer(struct rt_tasklet_struct *timer)
00203 {
00204     (timer->next)->prev = timer->prev;
00205     (timer->prev)->next = timer->next;
00206     timer->next = timer->prev = timer;
00207     rb_erase_timer(timer);
00208 }
00209 
00210 /**
00211  * Insert a tasklet in the list of tasklets to be processed.
00212  *
00213  * rt_insert_tasklet insert a tasklet in the list of tasklets to be processed.
00214  *
00215  * @param tasklet is the pointer to the tasklet structure to be used to manage
00216  * the tasklet at hand.
00217  *
00218  * @param handler is the tasklet function to be executed.
00219  *
00220  * @param data is an unsigned long to be passed to the handler.   Clearly by an
00221  * appropriate type casting one can pass a pointer to whatever data structure
00222  * and type is needed.
00223  *
00224  * @param id is a unique unsigned number to be used to identify the tasklet
00225  * tasklet. It is typically required by the kernel space service, interrupt
00226  * handler ot task, in charge of executing a user space tasklet.   The support
00227  * functions nam2num() and num2nam() can be used for setting up id from a six
00228  * character string.
00229  *
00230  * @param pid is an integer that marks a tasklet either as being a kernel or
00231  * user space one. Despite its name you need not to know the pid of the tasklet
00232  * parent process in user space.   Simple use 0 for kernel space and 1 for user
00233  * space.
00234  *
00235  * @retval 0 on success
00236  * @return a negative number to indicate that an invalid handler address has
00237  * been passed.
00238  *
00239  */
00240 
00241 RTAI_SYSCALL_MODE int rt_insert_tasklet(struct rt_tasklet_struct *tasklet, int priority, void (*handler)(unsigned long), unsigned long data, unsigned long id, int pid)
00242 {
00243     unsigned long flags;
00244 
00245 // tasklet initialization
00246     if (!handler || !id) {
00247         return -EINVAL;
00248     }
00249     tasklet->uses_fpu = 0;
00250     tasklet->priority = priority;
00251     tasklet->handler  = handler;
00252     tasklet->data     = data;
00253     tasklet->id       = id;
00254     if (!pid) {
00255         tasklet->task = 0;
00256     } else {
00257         (tasklet->task)->priority = priority;
00258         rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00259     }
00260 // tasklet insertion tasklets_list
00261     flags = rt_spin_lock_irqsave(&tasklets_lock);
00262     tasklet->next             = &tasklets_list;
00263     tasklet->prev             = tasklets_list.prev;
00264     (tasklets_list.prev)->next = tasklet;
00265     tasklets_list.prev         = tasklet;
00266     rt_spin_unlock_irqrestore(flags, &tasklets_lock);
00267     return 0;
00268 }
00269 
00270 /**
00271  * Remove a tasklet in the list of tasklets to be processed.
00272  *
00273  * rt_remove_tasklet remove a tasklet from the list of tasklets to be processed.
00274  *
00275  * @param tasklet is the pointer to the tasklet structure to be used to manage
00276  * the tasklet at hand.
00277  *
00278  */
00279 
00280 RTAI_SYSCALL_MODE void rt_remove_tasklet(struct rt_tasklet_struct *tasklet)
00281 {
00282     if (tasklet->next && tasklet->prev && tasklet->next != tasklet && tasklet->prev != tasklet) {
00283         unsigned long flags;
00284         flags = rt_spin_lock_irqsave(&tasklets_lock);
00285         (tasklet->next)->prev = tasklet->prev;
00286         (tasklet->prev)->next = tasklet->next;
00287         tasklet->next = tasklet->prev = tasklet;
00288         rt_spin_unlock_irqrestore(flags, &tasklets_lock);
00289     }
00290 }
00291 
00292 /**
00293  * Find a tasklet identified by its id.
00294  *
00295  * @param id is the unique unsigned long to be used to identify the tasklet.
00296  *
00297  * The support functions nam2num() and num2nam() can be used for setting up id
00298  * from a six character string.
00299  *
00300  * @return the pointer to a tasklet handler on success
00301  * @retval 0 to indicate that @a id is not a valid identifier so that the
00302  * related tasklet was not found.
00303  *
00304  */
00305 
00306 struct rt_tasklet_struct *rt_find_tasklet_by_id(unsigned long id)
00307 {
00308     struct rt_tasklet_struct *tasklet;
00309 
00310     tasklet = &tasklets_list;
00311     while ((tasklet = tasklet->next) != &tasklets_list) {
00312         if (id == tasklet->id) {
00313             return tasklet;
00314         }
00315     }
00316     return 0;
00317 }
00318 
00319 /**
00320  * Exec a tasklet.
00321  *
00322  * rt_exec_tasklet execute a tasklet from the list of tasklets to be processed.
00323  *
00324  * @param tasklet is the pointer to the tasklet structure to be used to manage
00325  * the tasklet @a tasklet.
00326  *
00327  * Kernel space tasklets addresses are usually available directly and can be
00328  * easily be used in calling rt_tasklet_exec.   In fact one can call the related
00329  * handler directly without using such a support  function, which is mainly
00330  * supplied for symmetry and to ease the porting of applications from one space
00331  * to the other.
00332  *
00333  * User space tasklets instead must be first found within the tasklet list by
00334  * calling rt_find_tasklet_by_id() to get the tasklet address to be used
00335  * in rt_tasklet_exec().
00336  *
00337  */
00338 
00339 RTAI_SYSCALL_MODE int rt_exec_tasklet(struct rt_tasklet_struct *tasklet)
00340 {
00341     if (tasklet && tasklet->next != tasklet && tasklet->prev != tasklet) {
00342         if (!tasklet->task) {
00343             tasklet->handler(tasklet->data);
00344         } else {
00345             rt_task_resume(tasklet->task);
00346         }
00347         return 0;
00348     }
00349     return -EINVAL;
00350 }
00351 
00352 RTAI_SYSCALL_MODE void rt_set_tasklet_priority(struct rt_tasklet_struct *tasklet, int priority)
00353 {
00354     tasklet->priority = priority;
00355     if (tasklet->task) {
00356         (tasklet->task)->priority = priority;
00357     }
00358 }
00359 
00360 RTAI_SYSCALL_MODE int rt_set_tasklet_handler(struct rt_tasklet_struct *tasklet, void (*handler)(unsigned long))
00361 {
00362     if (!handler) {
00363         return -EINVAL;
00364     }
00365     tasklet->handler = handler;
00366     if (tasklet->task) {
00367         rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00368     }
00369     return 0;
00370 }
00371 
00372 RTAI_SYSCALL_MODE void rt_set_tasklet_data(struct rt_tasklet_struct *tasklet, unsigned long data)
00373 {
00374     tasklet->data = data;
00375     if (tasklet->task) {
00376         rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00377     }
00378 }
00379 
00380 RTAI_SYSCALL_MODE RT_TASK *rt_tasklet_use_fpu(struct rt_tasklet_struct *tasklet, int use_fpu)
00381 {
00382     tasklet->uses_fpu = use_fpu ? 1 : 0;
00383     return tasklet->task;
00384 }
00385 
00386 static RT_TASK timers_manager[NUM_CPUS];
00387 
00388 static inline void asgn_min_prio(int cpuid)
00389 {
00390 // find minimum priority in timers_struct 
00391     RT_TASK *timer_manager;
00392     struct rt_tasklet_struct *timer, *timerl;
00393     spinlock_t *lock;
00394     unsigned long flags;
00395     int priority;
00396 
00397     priority = (timer = (timerl = &timers_list[LIST_CPUID])->next)->priority;
00398     flags = rt_spin_lock_irqsave(lock = &timers_lock[LIST_CPUID]);
00399     while ((timer = timer->next) != timerl) {
00400         if (timer->priority < priority) {
00401             priority = timer->priority;
00402         }
00403         rt_spin_unlock_irqrestore(flags, lock);
00404         flags = rt_spin_lock_irqsave(lock);
00405     }
00406     rt_spin_unlock_irqrestore(flags, lock);
00407     flags = rt_global_save_flags_and_cli();
00408     if ((timer_manager = &timers_manager[LIST_CPUID])->priority > priority) {
00409         timer_manager->priority = priority;
00410         if (timer_manager->state == RT_SCHED_READY) {
00411             rem_ready_task(timer_manager);
00412             enq_ready_task(timer_manager);
00413         }
00414     }
00415     rt_global_restore_flags(flags);
00416 }
00417 
00418 static inline void set_timer_firing_time(struct rt_tasklet_struct *timer, RTIME firing_time)
00419 {
00420     if (timer->next != timer && timer->prev != timer) {
00421         spinlock_t *lock;
00422         unsigned long flags;
00423 
00424         timer->firing_time = firing_time;
00425         flags = rt_spin_lock_irqsave(lock = &timers_lock[TIMER_CPUID]);
00426         rem_timer(timer);
00427         enq_timer(timer);
00428         rt_spin_unlock_irqrestore(flags, lock);
00429     }
00430 }
00431 
00432 /**
00433  * Insert a timer in the list of timers to be processed.
00434  *
00435  * rt_insert_timer insert a timer in the list of timers to be processed.  Timers
00436  * can be either periodic or oneshot.   A periodic timer is reloaded at each
00437  * expiration so that it executes with the assigned periodicity.   A oneshot
00438  * timer is fired just once and then removed from the timers list. Timers can be
00439  * reinserted or modified within their handlers functions.
00440  *
00441  * @param timer is the pointer to the timer structure to be used to manage the
00442  * timer at hand.
00443  *
00444  * @param priority is the priority to be used to execute timers handlers when
00445  * more than one timer has to be fired at the same time.It can be assigned any
00446  * value such that: 0 < priority < RT_LOWEST_PRIORITY.
00447  *
00448  * @param firing_time is the time of the first timer expiration.
00449  *
00450  * @param period is the period of a periodic timer. A periodic timer keeps
00451  * calling its handler at  firing_time + k*period k = 0, 1.  To define a oneshot
00452  * timer simply use a null period.
00453  * 
00454  * @param handler is the timer function to be executed at each timer expiration.
00455  *
00456  * @param data is an unsigned long to be passed to the handler.   Clearly by a 
00457  * appropriate type casting one can pass a pointer to whatever data structure
00458  * and type is needed.
00459  *
00460  * @param pid is an integer that marks a timer either as being a kernel or user
00461  * space one. Despite its name you need not to know the pid of the timer parent
00462  * process in user space. Simple use 0 for kernel space and 1 for user space.
00463  *
00464  * @retval 0 on success
00465  * @retval EINVAL if @a handler is an invalid handler address
00466  *
00467  */
00468 
00469 RTAI_SYSCALL_MODE int rt_insert_timer(struct rt_tasklet_struct *timer, int priority, RTIME firing_time, RTIME period, void (*handler)(unsigned long), unsigned long data, int pid)
00470 {
00471     spinlock_t *lock;
00472     unsigned long flags, cpuid;
00473     RT_TASK *timer_manager;
00474 
00475 // timer initialization
00476     timer->uses_fpu    = 0;
00477     
00478     if (pid >= 0) {
00479         if (!handler) {
00480             return -EINVAL;
00481         }
00482         timer->handler   = handler; 
00483         timer->data              = data;
00484     } else {
00485         if (timer->handler != NULL || timer->handler == (void *)1) {
00486             timer->handler = (void *)1; 
00487             timer->data    = data;
00488         }       
00489     }
00490     
00491     timer->priority    = priority;  
00492     REALTIME2COUNT(firing_time)
00493     timer->firing_time = firing_time;
00494     timer->period      = period;
00495     
00496     if (!pid) {
00497         timer->task = 0;
00498         timer->cpuid = cpuid = NUM_CPUS > 1 ? rtai_cpuid() : 0;
00499     } else {
00500         timer->cpuid = cpuid = NUM_CPUS > 1 ? (timer->task)->runnable_on_cpus : 0;
00501         (timer->task)->priority = priority;
00502         rt_copy_to_user(timer->usptasklet, timer, sizeof(struct rt_usp_tasklet_struct));
00503     }
00504 // timer insertion in timers_list
00505     flags = rt_spin_lock_irqsave(lock = &timers_lock[LIST_CPUID]);
00506     enq_timer(timer);
00507     rt_spin_unlock_irqrestore(flags, lock);
00508 // timers_manager priority inheritance
00509     if (timer->priority < (timer_manager = &timers_manager[LIST_CPUID])->priority) {
00510         timer_manager->priority = timer->priority;
00511     }
00512 // timers_task deadline inheritance
00513     flags = rt_global_save_flags_and_cli();
00514     if (timers_list[LIST_CPUID].next == timer && (timer_manager->state & RT_SCHED_DELAYED) && firing_time < timer_manager->resume_time) {
00515         timer_manager->resume_time = firing_time;
00516         rem_timed_task(timer_manager);
00517         enq_timed_task(timer_manager);
00518         rt_schedule();
00519     }
00520     rt_global_restore_flags(flags);
00521     return 0;
00522 }
00523 
00524 /**
00525  * Remove a timer in the list of timers to be processed.
00526  *
00527  * rt_remove_timer remove a timer from the list of the timers to be processed.
00528  *
00529  * @param timer is the pointer to the timer structure to be used to manage the
00530  * timer at hand.
00531  *
00532  */
00533 
00534 RTAI_SYSCALL_MODE void rt_remove_timer(struct rt_tasklet_struct *timer)
00535 {
00536     if (timer->next && timer->prev && timer->next != timer && timer->prev != timer) {
00537         spinlock_t *lock;
00538         unsigned long flags;
00539         flags = rt_spin_lock_irqsave(lock = &timers_lock[TIMER_CPUID]);
00540         rem_timer(timer);
00541         rt_spin_unlock_irqrestore(flags, lock);
00542         asgn_min_prio(TIMER_CPUID);
00543     }
00544 }
00545 
00546 /**
00547  * Change the priority of an existing timer.
00548  *
00549  * rt_set_timer_priority change the priority of an existing timer.
00550  *
00551  * @param timer is the pointer to the timer structure to be used to manage the
00552  * timer at hand.
00553  *
00554  * @param priority is the priority to be used to execute timers handlers when
00555  * more than one timer has to be fired at the same time. It can be assigned any
00556  * value such that: 0 < priority < RT_LOWEST_PRIORITY.
00557  *
00558  * This function can be used within the timer handler.
00559  *
00560  */
00561 
00562 RTAI_SYSCALL_MODE void rt_set_timer_priority(struct rt_tasklet_struct *timer, int priority)
00563 {
00564     timer->priority = priority;
00565     if (timer->task) {
00566         (timer->task)->priority = priority;
00567     }
00568     asgn_min_prio(TIMER_CPUID);
00569 }
00570 
00571 /**
00572  * Change the firing time of a timer.
00573  * 
00574  * rt_set_timer_firing_time changes the firing time of a periodic timer
00575  * overloading any existing value, so that the timer next shoot will take place
00576  * at the new firing time. Note that if a oneshot timer has its firing time
00577  * changed after it has already expired this function has no effect. You
00578  * should reinsert it in the timer list with the new firing time.
00579  *
00580  * @param timer is the pointer to the timer structure to be used to manage the
00581  * timer at hand.
00582  *
00583  * @param firing_time is the new time of the first timer expiration.
00584  *
00585  * This function can be used within the timer handler.
00586  *
00587  * @retval 0 on success.
00588  *
00589  */
00590 
00591 RTAI_SYSCALL_MODE void rt_set_timer_firing_time(struct rt_tasklet_struct *timer, RTIME firing_time)
00592 {
00593     unsigned long flags;
00594     RT_TASK *timer_manager;
00595 
00596     set_timer_firing_time(timer, firing_time);
00597     flags = rt_global_save_flags_and_cli();
00598     if (timers_list[TIMER_CPUID].next == timer && ((timer_manager = &timers_manager[TIMER_CPUID])->state & RT_SCHED_DELAYED) && firing_time < timer_manager->resume_time) {
00599         timer_manager->resume_time = firing_time;
00600         rem_timed_task(timer_manager);
00601         enq_timed_task(timer_manager);
00602         rt_schedule();
00603     }
00604     rt_global_restore_flags(flags);
00605 }
00606 
00607 /**
00608  * Change the period of a timer.
00609  * 
00610  * rt_set_timer_period changes the period of a periodic timer. Note that the new
00611  * period will be used to pace the timer only after the expiration of the firing
00612  * time already in place. Using this function with a period different from zero
00613  * for a oneshot timer, that has not expired yet, will transform it into a
00614  * periodic timer.
00615  *
00616  * @param timer is the pointer to the timer structure to be used to manage the
00617  * timer at hand.
00618  *
00619  * @param period is the new period of a periodic timer.
00620  *
00621  * The macro #rt_fast_set_timer_period  can substitute the corresponding
00622  * function in kernel space if both the existing timer period and the new one
00623  * fit into an 32 bits integer.
00624  *
00625  * This function an be used within the timer handler.
00626  *
00627  * @retval 0 on success.
00628  *
00629  */
00630 
00631 RTAI_SYSCALL_MODE void rt_set_timer_period(struct rt_tasklet_struct *timer, RTIME period)
00632 {
00633     spinlock_t *lock;
00634     unsigned long flags;
00635     flags = rt_spin_lock_irqsave(lock = &timers_lock[TIMER_CPUID]);
00636     timer->period = period;
00637     rt_spin_unlock_irqrestore(flags, lock);
00638 }
00639 
00640 RTAI_SYSCALL_MODE void rt_get_timer_times(struct rt_tasklet_struct *timer, RTIME timer_times[])
00641 {
00642     RTIME firing;
00643     
00644     firing = -rt_get_time();
00645     firing += timer->firing_time;
00646         
00647     timer_times[0] = firing > 0 ? firing : -1;
00648     timer_times[1] = timer->period;
00649 }
00650 
00651 RTAI_SYSCALL_MODE RTIME rt_get_timer_overrun(struct rt_tasklet_struct *timer)
00652 {
00653     return timer->overrun;
00654 }
00655 
00656 static int TimersManagerPrio = 0;
00657 RTAI_MODULE_PARM(TimersManagerPrio, int);
00658 
00659 // the timers_manager task function
00660 
00661 static void rt_timers_manager(long cpuid)
00662 {
00663     RTIME now;
00664     RT_TASK *timer_manager;
00665     struct rt_tasklet_struct *tmr, *timer, *timerl;
00666     spinlock_t *lock;
00667     unsigned long flags, timer_tol;
00668     int priority, used_fpu;
00669 
00670     timer_manager = &timers_manager[LIST_CPUID];
00671     timerl = &timers_list[LIST_CPUID];
00672     lock = &timers_lock[LIST_CPUID];
00673     timer_tol = tuned.timers_tol[LIST_CPUID];
00674 
00675     while (1) {
00676         int retval;
00677         retval = rt_sleep_until((timerl->next)->firing_time);
00678 //      now = timer_manager->resume_time + timer_tol;
00679         now = rt_get_time() + timer_tol;
00680 // find all the timers to be fired, in priority order
00681         while (1) {
00682             used_fpu = 0;
00683             tmr = timer = timerl;
00684             priority = RT_SCHED_LOWEST_PRIORITY;
00685             flags = rt_spin_lock_irqsave(lock);
00686             while ((tmr = tmr->next)->firing_time <= now) {
00687                 if (tmr->priority < priority) {
00688                     priority = (timer = tmr)->priority;
00689                 }
00690             }
00691             rt_spin_unlock_irqrestore(flags, lock);
00692             if (timer == timerl) {
00693                 if (timer_manager->priority > TimersManagerPrio) {
00694                     timer_manager->priority = TimersManagerPrio;
00695                 }
00696                 break;
00697             }
00698             timer_manager->priority = priority;
00699 #if 1
00700             flags = rt_spin_lock_irqsave(lock);
00701             rem_timer(timer);
00702             if (timer->period) {
00703                 timer->firing_time += timer->period;
00704                 enq_timer(timer);
00705             }
00706             rt_spin_unlock_irqrestore(flags, lock);
00707 #else
00708             if (!timer->period) {
00709                 flags = rt_spin_lock_irqsave(lock);
00710                 rem_timer(timer);
00711                 rt_spin_unlock_irqrestore(flags, lock);
00712             } else {
00713                 set_timer_firing_time(timer, timer->firing_time + timer->period);
00714             }
00715 #endif
00716     //  if (retval != RTE_TMROVRN) {
00717             tmr->overrun = 0;
00718             if (!timer->task) {
00719                 if (!used_fpu && timer->uses_fpu) {
00720                     used_fpu = 1;
00721                     save_fpcr_and_enable_fpu(linux_cr0);
00722                     save_fpenv(timer_manager->fpu_reg);
00723                 }
00724                 timer->handler(timer->data);
00725             } else {
00726                 rt_task_resume(timer->task);
00727             }
00728     //  } else {
00729     //      tmr->overrun++;
00730     //  }
00731         }
00732         if (used_fpu) {
00733             restore_fpenv(timer_manager->fpu_reg);
00734             restore_fpcr(linux_cr0);
00735         }
00736 // set next timers_manager priority according to the highest priority timer
00737         asgn_min_prio(LIST_CPUID);
00738 // if no more timers in timers_struct remove timers_manager from tasks list
00739     }
00740 }
00741 
00742 /**
00743  * Init, in kernel space, a tasklet structure to be used in user space.
00744  *
00745  * rt_tasklet_init allocate a tasklet structure (struct rt_tasklet_struct) in
00746  * kernel space to be used for the management of a user space tasklet.
00747  *
00748  * This function is to be used only for user space tasklets. In kernel space
00749  * it is just an empty macro, as the user can, and must  allocate the related
00750  * structure directly, either statically or dynamically.
00751  *
00752  * @return the pointer to the tasklet structure the user space application must
00753  * use to access all its related services.
00754  */
00755 struct rt_tasklet_struct *rt_init_tasklet(void)
00756 {
00757     struct rt_tasklet_struct *tasklet;
00758     if ((tasklet = rt_malloc(sizeof(struct rt_tasklet_struct)))) {
00759         memset(tasklet, 0, sizeof(struct rt_tasklet_struct));
00760     }
00761     return tasklet;
00762 }
00763 
00764 RTAI_SYSCALL_MODE void rt_register_task(struct rt_tasklet_struct *tasklet, struct rt_tasklet_struct *usptasklet, RT_TASK *task)
00765 {
00766     tasklet->task = task;
00767     tasklet->usptasklet = usptasklet;
00768     rt_copy_to_user(usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00769 }
00770 
00771 RTAI_SYSCALL_MODE int rt_wait_tasklet_is_hard(struct rt_tasklet_struct *tasklet, long thread)
00772 {
00773 #define POLLS_PER_SEC 100
00774     int i;
00775     tasklet->thread = thread;
00776     for (i = 0; i < POLLS_PER_SEC/5; i++) {
00777         if (!tasklet->task || !((tasklet->task)->state & RT_SCHED_SUSPENDED)) {
00778             current->state = TASK_INTERRUPTIBLE;
00779             schedule_timeout(HZ/POLLS_PER_SEC);
00780         } else {
00781             return 0;
00782         }
00783     }
00784     return 1;
00785 #undef POLLS_PER_SEC
00786 }
00787 
00788 /**
00789  * Delete, in kernel space, a tasklet structure to be used in user space.
00790  *
00791  * rt_tasklet_delete free a tasklet structure (struct rt_tasklet_struct) in
00792  * kernel space that was allocated by rt_tasklet_init.
00793  *
00794  * @param tasklet is the pointer to the tasklet structure (struct
00795  * rt_tasklet_struct) returned by rt_tasklet_init.
00796  *
00797  * This function is to be used only for user space tasklets. In kernel space
00798  * it is just an empty macro, as the user can, and must  allocate the related
00799  * structure directly, either statically or dynamically.
00800  *
00801  */
00802 
00803 RTAI_SYSCALL_MODE int rt_delete_tasklet(struct rt_tasklet_struct *tasklet)
00804 {
00805     int thread;
00806 
00807     rt_remove_tasklet(tasklet);
00808     tasklet->handler = 0;
00809     rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00810     rt_task_resume(tasklet->task);
00811     thread = tasklet->thread;   
00812     rt_free(tasklet);
00813     return thread;  
00814 }
00815 
00816 /*
00817  * Posix Timers support function
00818  */
00819  
00820  
00821 static int PosixTimers = POSIX_TIMERS;
00822 RTAI_MODULE_PARM(PosixTimers, int);
00823 
00824 static spinlock_t ptimer_lock = SPIN_LOCK_UNLOCKED;
00825 static volatile int ptimer_index;
00826 struct ptimer_list { int t_indx, p_idx; struct ptimer_list *p_ptr; struct rt_tasklet_struct *timer;} *posix_timer;
00827 
00828 static int init_ptimers(void)
00829 {
00830     int i;
00831     
00832     if (!(posix_timer = (struct ptimer_list *)kmalloc((PosixTimers)*sizeof(struct ptimer_list), GFP_KERNEL))) {
00833         printk("Init MODULE no memory for Posix Timer's list.\n");
00834         return -ENOMEM;
00835     }
00836     for (i = 0; i < PosixTimers; i++) {
00837         posix_timer[i].t_indx = posix_timer[i].p_idx = i;
00838         posix_timer[i].p_ptr = posix_timer + i;
00839     }
00840     return 0;
00841 
00842 }
00843 
00844 static void cleanup_ptimers(void)
00845 {
00846     kfree(posix_timer);
00847 } 
00848  
00849 static inline int get_ptimer_indx(struct rt_tasklet_struct *timer)
00850 {
00851     unsigned long flags;
00852 
00853     flags = rt_spin_lock_irqsave(&ptimer_lock);
00854     if (ptimer_index < PosixTimers) {
00855         struct ptimer_list *p;
00856         p = posix_timer[ptimer_index++].p_ptr;
00857         p->timer = timer;
00858         rt_spin_unlock_irqrestore(flags, &ptimer_lock);
00859         return p->t_indx;
00860     }
00861     rt_spin_unlock_irqrestore(flags, &ptimer_lock);
00862     return 0;
00863 }
00864 
00865 static inline int gvb_ptimer_indx(int itimer)
00866 {
00867     unsigned long flags;
00868 
00869     flags = rt_spin_lock_irqsave(&ptimer_lock);
00870     if (itimer < PosixTimers) {
00871         struct ptimer_list *tmp_p;
00872         int tmp_place;
00873         tmp_p = posix_timer[--ptimer_index].p_ptr;
00874         tmp_place = posix_timer[itimer].p_idx;
00875         posix_timer[itimer].p_idx = ptimer_index;
00876         posix_timer[ptimer_index].p_ptr = &posix_timer[itimer];
00877         tmp_p->p_idx = tmp_place;
00878         posix_timer[tmp_place].p_ptr = tmp_p;
00879         rt_spin_unlock_irqrestore(flags, &ptimer_lock);
00880         return 0;
00881     }
00882     rt_spin_unlock_irqrestore(flags, &ptimer_lock);
00883     return -EINVAL;
00884 }
00885 
00886 RTAI_SYSCALL_MODE timer_t rt_ptimer_create(struct rt_tasklet_struct *timer, void (*handler)(unsigned long), unsigned long data, long pid, long thread)
00887 {
00888     if (thread) {
00889         rt_wait_tasklet_is_hard(timer, thread);
00890     }
00891     timer->next = timer;
00892     timer->prev = timer;
00893     timer->data = data;
00894     timer->handler = handler;
00895     return get_ptimer_indx(timer);
00896 }
00897 EXPORT_SYMBOL(rt_ptimer_create);
00898 
00899 RTAI_SYSCALL_MODE void rt_ptimer_settime(timer_t timer, const struct itimerspec *value, unsigned long data, long flags)
00900 {
00901     struct rt_tasklet_struct *tasklet;
00902     RTIME now;
00903     
00904     tasklet = posix_timer[timer].timer;
00905     rt_remove_timer(tasklet);
00906     now = rt_get_time();
00907     if (flags == TIMER_ABSTIME) {
00908         if (timespec2count(&(value->it_value)) < now) {
00909             now -= timespec2count (&(value->it_value));
00910         }else {
00911             now = 0;
00912         }
00913     }   
00914     if (timespec2count ( &(value->it_value)) > 0) {
00915         if (data) {
00916             rt_insert_timer(tasklet, 0, now + timespec2count ( &(value->it_value) ), timespec2count ( &(value->it_interval) ), NULL, data, -1);
00917         } else {
00918             rt_insert_timer(tasklet, 0, now + timespec2count ( &(value->it_value) ), timespec2count ( &(value->it_interval) ), tasklet->handler, tasklet->data, 0);
00919         }
00920     }
00921 }
00922 EXPORT_SYMBOL(rt_ptimer_settime);
00923 
00924 RTAI_SYSCALL_MODE int rt_ptimer_overrun(timer_t timer)
00925 {
00926     return rt_get_timer_overrun(posix_timer[timer].timer);
00927 }
00928 EXPORT_SYMBOL(rt_ptimer_overrun);
00929 
00930 RTAI_SYSCALL_MODE void rt_ptimer_gettime(timer_t timer, RTIME timer_times[])
00931 {
00932     rt_get_timer_times(posix_timer[timer].timer, timer_times);
00933 }
00934 EXPORT_SYMBOL(rt_ptimer_gettime);
00935 
00936 RTAI_SYSCALL_MODE int rt_ptimer_delete(timer_t timer, long space)
00937 {
00938     struct rt_tasklet_struct *tasklet;
00939     int rtn = 0;
00940     
00941     tasklet = posix_timer[timer].timer;
00942     gvb_ptimer_indx(timer);
00943     rt_remove_tasklet(tasklet); 
00944     if (space) {
00945         tasklet->handler = 0;
00946         rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_usp_tasklet_struct));
00947         rt_task_resume(tasklet->task);
00948         rtn = tasklet->thread;  
00949     } 
00950     rt_free(tasklet);
00951     return rtn;
00952 }       
00953 EXPORT_SYMBOL(rt_ptimer_delete);
00954 
00955  /*
00956  * End Posix timers support function
00957  */
00958 
00959 static int TaskletsStacksize = TASKLET_STACK_SIZE;
00960 RTAI_MODULE_PARM(TaskletsStacksize, int);
00961 
00962 int __rtai_tasklets_init(void)
00963 {
00964     int cpuid;
00965 
00966     if(set_rt_fun_ext_index(rt_tasklet_fun, TASKLETS_IDX)) {
00967         printk("Recompile your module with a different index\n");
00968         return -EACCES;
00969         }
00970     if (init_ptimers()) {
00971         return -ENOMEM;
00972     }   
00973     for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
00974         timers_lock[cpuid] = timers_lock[0];
00975         timers_list[cpuid] = timers_list[0];
00976         timers_list[cpuid].cpuid = cpuid;
00977         timers_list[cpuid].next = timers_list[cpuid].prev = &timers_list[cpuid];
00978         rt_task_init_cpuid(&timers_manager[cpuid], rt_timers_manager, cpuid, TaskletsStacksize, TimersManagerPrio, 0, 0, cpuid);
00979         rt_task_resume(&timers_manager[cpuid]);
00980     }
00981     printk(KERN_INFO "RTAI[tasklets]: loaded.\n");
00982     return 0;
00983 }
00984 
00985 void __rtai_tasklets_exit(void)
00986 {
00987     int cpuid;
00988     reset_rt_fun_ext_index(rt_tasklet_fun, TASKLETS_IDX);
00989     cleanup_ptimers();    
00990     for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
00991         rt_task_delete(&timers_manager[cpuid]);
00992     }
00993     printk(KERN_INFO "RTAI[tasklets]: unloaded.\n");
00994 }
00995 
00996 /*@}*/
00997 
00998 #ifndef CONFIG_RTAI_TASKLETS_BUILTIN
00999 module_init(__rtai_tasklets_init);
01000 module_exit(__rtai_tasklets_exit);
01001 #endif /* !CONFIG_RTAI_TASKLETS_BUILTIN */
01002 
01003 #ifdef CONFIG_KBUILD
01004 EXPORT_SYMBOL(rt_insert_tasklet);
01005 EXPORT_SYMBOL(rt_remove_tasklet);
01006 EXPORT_SYMBOL(rt_find_tasklet_by_id);
01007 EXPORT_SYMBOL(rt_exec_tasklet);
01008 EXPORT_SYMBOL(rt_set_tasklet_priority);
01009 EXPORT_SYMBOL(rt_set_tasklet_handler);
01010 EXPORT_SYMBOL(rt_set_tasklet_data);
01011 EXPORT_SYMBOL(rt_tasklet_use_fpu);
01012 EXPORT_SYMBOL(rt_insert_timer);
01013 EXPORT_SYMBOL(rt_remove_timer);
01014 EXPORT_SYMBOL(rt_set_timer_priority);
01015 EXPORT_SYMBOL(rt_set_timer_firing_time);
01016 EXPORT_SYMBOL(rt_set_timer_period);
01017 EXPORT_SYMBOL(rt_init_tasklet);
01018 EXPORT_SYMBOL(rt_register_task);
01019 EXPORT_SYMBOL(rt_wait_tasklet_is_hard);
01020 EXPORT_SYMBOL(rt_delete_tasklet);
01021 EXPORT_SYMBOL(rt_get_timer_times);
01022 EXPORT_SYMBOL(rt_get_timer_overrun);
01023 #endif /* CONFIG_KBUILD */

Generated on Tue Feb 2 17:46:05 2010 for RTAI API by  doxygen 1.4.7