base/tasklets/tasklets.c

Go to the documentation of this file.
00001 /** 00002 * @ingroup tasklets 00003 * @file 00004 * 00005 * Implementation of the @ref tasklets "mini LXRT RTAI tasklets module". 00006 * 00007 * @author Paolo Mantegazza 00008 * 00009 * @note Copyright &copy;1999-2003 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 mini RTAI LXRT tasklets module 00028 * 00029 * The MINI_RTAI_LXRT tasklets module adds an interesting new feature along the 00030 * line, pioneered by RTAI, of a symmetric usage of all its services inter-intra 00031 * kernel and user space, both for soft and hard real time applications. In 00032 * such a way 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 in 00036 * kernel and user space, that must execute in soft/hard real time but do not 00037 * need any RTAI scheduler service that could lead to a task block. Such tasks 00038 * are here called tasklets and can be of two kinds: normal tasklets and timed 00039 * 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, also normal tasklet functions can be used in whatever address 00047 * space. 00048 * 00049 * Note that if, at this point, you are reminded to similar Linux kernel 00050 * services you are not totally wrong. They are not exactly the same, because 00051 * of their symmetric availability in kernel and user space, but the basic idea 00052 * behind them is clearly fairly similar. 00053 * 00054 * Tasklets should be used whenever the standard hard real time tasks available 00055 * with RTAI and LXRT schedulers can be a waist of resources and the execution 00056 * of simple, possibly timed, functions could often be more than 00057 * enough. Instances of such applications are timed polling and simple 00058 * Programmable Logic Controllers (PLC) like sequences of services. Obviously 00059 * there are many others instances that can make it sufficient the use of 00060 * tasklets, either normal or timers. In general such an approach can be a 00061 * very useful complement to fully featured tasks in controlling complex 00062 * machines and systems, both for basic and support services. 00063 * 00064 * It is remarked that the implementation found here for timed tasklets rely on 00065 * a server support task that executes the related timer functions, either in 00066 * oneshot or periodic mode, on the base of their time deadline and according to 00067 * their, user assigned, priority. Instead, as told above, plain tasklets are 00068 * just functions executed from kernel space; their execution needs no server 00069 * and is simply triggered by calling a given service function at due time, 00070 * either from a kernel task or interrupt handler requiring, or in charge of, 00071 * their execution when they are needed. Once more it is important to recall 00072 * that all non blocking RTAI scheduler services can be used in any tasklet 00073 * function. Blocking services must absolutely be avoided. They will 00074 * deadlock the timers server task, executing task or interrupt handler, 00075 * whichever applies, so that no more tasklet functions will be executed. 00076 * 00077 * User and kernel space MINI_RTAI_LXRT applications can cooperate and 00078 * synchronize by using shared memory. It has been called MINI_RTAI_LXRT because 00079 * it is a kind of light soft/hard real time server that can partially 00080 * substitute RTAI and LXRT in simple applications, i.e. if the constraints 00081 * hinted above are wholly satisfied. So MINI_RTAI_LXRT can be used in kernel 00082 * and user space, with any RTAI scheduler. Its implementations has been very 00083 * easy, as it is nothing but what its name implies. LXRT made all the needed 00084 * tools already available. In fact it duplicates a lot of LXRT so that its 00085 * final production version will be fully integrated with it, ASAP. However, 00086 * at the moment, it cannot work with LXRT yet. 00087 * 00088 * Note that in user space you run within the memory of the process owning the 00089 * tasklet function so you MUST lock all of your processes memory in core, by 00090 * using mlockall, to prevent it being swapped out. Also abundantly pre grow 00091 * your stack to the largest size needed during the execution of your 00092 * application, see mlockall usage in Linux manuals. 00093 * 00094 * The RTAI distribution contains many useful examples that demonstrate the use 00095 * of most services, both in kernel and user space. 00096 * 00097 *@{*/ 00098 00099 #include <linux/module.h> 00100 #include <linux/version.h> 00101 #include <linux/proc_fs.h> 00102 #include <linux/sched.h> 00103 #include <linux/slab.h> 00104 #include <linux/interrupt.h> 00105 #include <asm/uaccess.h> 00106 #include <asm/system.h> 00107 #include <asm/rtai_sched.h> 00108 #include <rtai_tasklets.h> 00109 #include <rtai_lxrt.h> 00110 #include <rtai_malloc.h> 00111 #include <rtai_schedcore.h> 00112 00113 MODULE_LICENSE("GPL"); 00114 00115 #ifdef CONFIG_RTAI_MALLOC 00116 #define sched_malloc(size) rt_malloc((size)) 00117 #define sched_free(adr) rt_free((adr)) 00118 #else 00119 #define sched_malloc(size) kmalloc((size), GFP_KERNEL) 00120 #define sched_free(adr) kfree((adr)) 00121 #endif 00122 00123 DEFINE_LINUX_CR0 00124 00125 static struct rt_tasklet_struct timers_list = 00126 { &timers_list, &timers_list, RT_SCHED_LOWEST_PRIORITY, 0, RT_TIME_END, 0LL, 0, 0, 0, 00127 #ifdef CONFIG_RTAI_LONG_TIMED_LIST 00128 /**/0, NULL, NULL, { NULL } 00129 #endif 00130 }; 00131 00132 static struct rt_tasklet_struct tasklets_list = 00133 { &tasklets_list, &tasklets_list, }; 00134 00135 static spinlock_t tasklets_lock = SPIN_LOCK_UNLOCKED; 00136 static spinlock_t timers_lock = SPIN_LOCK_UNLOCKED; 00137 00138 static struct rt_fun_entry rt_tasklet_fun[] __attribute__ ((__unused__)); 00139 00140 static struct rt_fun_entry rt_tasklet_fun[] = { 00141 { 0, rt_init_tasklet }, // 0 00142 { 0, rt_delete_tasklet }, // 1 00143 { 0, rt_insert_tasklet }, // 2 00144 { 0, rt_remove_tasklet }, // 3 00145 { 0, rt_tasklet_use_fpu }, // 4 00146 { 0, rt_insert_timer }, // 5 00147 { 0, rt_remove_timer }, // 6 00148 { 0, rt_set_timer_priority }, // 7 00149 { 0, rt_set_timer_firing_time }, // 8 00150 { 0, rt_set_timer_period }, // 9 00151 { 0, rt_set_tasklet_handler }, // 10 00152 { 0, rt_set_tasklet_data }, // 11 00153 { 0, rt_exec_tasklet }, // 12 00154 { 0, rt_wait_tasklet_is_hard }, // 13 00155 { 0, rt_set_tasklet_priority }, // 14 00156 { 0, rt_register_task }, // 15 00157 }; 00158 00159 #ifdef CONFIG_RTAI_LONG_TIMED_LIST 00160 00161 /* BINARY TREE */ 00162 static inline void enq_timer(struct rt_tasklet_struct *timed_timer) 00163 { 00164 struct rt_tasklet_struct *timerh, *tmrnxt, *timer; 00165 rb_node_t **rbtn, *rbtpn = NULL; 00166 timer = timerh = &timers_list; 00167 rbtn = &timerh->rbr.rb_node; 00168 00169 while (*rbtn) { 00170 rbtpn = *rbtn; 00171 tmrnxt = rb_entry(rbtpn, struct rt_tasklet_struct, rbn); 00172 if (timer->firing_time > tmrnxt->firing_time) { 00173 rbtn = &(rbtpn)->rb_right; 00174 } else { 00175 rbtn = &(rbtpn)->rb_left; 00176 timer = tmrnxt; 00177 } 00178 } 00179 rb_link_node(&timed_timer->rbn, rbtpn, rbtn); 00180 rb_insert_color(&timed_timer->rbn, &timerh->rbr); 00181 timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer; 00182 timed_timer->next = timer; 00183 } 00184 00185 static inline void rem_timer(struct rt_tasklet_struct *timer) 00186 { 00187 (timer->next)->prev = timer->prev; 00188 (timer->prev)->next = timer->next; 00189 timer->next = timer->prev = timer; 00190 rb_erase(&timer->rbn, &timers_list.rbr); 00191 } 00192 00193 #else /* !CONFIG_RTAI_LONG_TIMED_LIST */ 00194 00195 /* LINEAR */ 00196 static inline void enq_timer(struct rt_tasklet_struct *timed_timer) 00197 { 00198 struct rt_tasklet_struct *timer; 00199 timer = &timers_list; 00200 while (timed_timer->firing_time >= (timer = timer->next)->firing_time); 00201 timer->prev = (timed_timer->prev = timer->prev)->next = timed_timer; 00202 timed_timer->next = timer; 00203 } 00204 00205 static inline void rem_timer(struct rt_tasklet_struct *timer) 00206 { 00207 (timer->next)->prev = timer->prev; 00208 (timer->prev)->next = timer->next; 00209 timer->next = timer->prev = timer; 00210 } 00211 00212 #endif /* CONFIG_RTAI_LONG_TIMED_LIST */ 00213 00214 /** 00215 * Insert a tasklet in the list of tasklets to be processed. 00216 * 00217 * rt_insert_tasklet insert a tasklet in the list of tasklets to be processed. 00218 * 00219 * @param tasklet is the pointer to the tasklet structure to be used to manage 00220 * the tasklet at hand. 00221 * 00222 * @param handler is the tasklet function to be executed. 00223 * 00224 * @param data is an unsigned long to be passed to the handler. Clearly by an 00225 * appropriate type casting one can pass a pointer to whatever data structure 00226 * and type is needed. 00227 * 00228 * @param id is a unique unsigned number to be used to identify the tasklet 00229 * tasklet. It is typically required by the kernel space service, interrupt 00230 * handler ot task, in charge of executing a user space tasklet. The support 00231 * functions nam2num() and num2nam() can be used for setting up id from a six 00232 * character string. 00233 * 00234 * @param pid is an integer that marks a tasklet either as being a kernel or 00235 * user space one. Despite its name you need not to know the pid of the tasklet 00236 * parent process in user space. Simple use 0 for kernel space and 1 for user 00237 * space. 00238 * 00239 * @retval 0 on success 00240 * @return a negative number to indicate that an invalid handler address has 00241 * been passed. 00242 * 00243 */ 00244 00245 int rt_insert_tasklet(struct rt_tasklet_struct *tasklet, int priority, void (*handler)(unsigned long), unsigned long data, unsigned long id, int pid) 00246 { 00247 unsigned long flags; 00248 00249 // tasklet initialization 00250 if (!handler || !id) { 00251 return -EINVAL; 00252 } 00253 tasklet->uses_fpu = 0; 00254 tasklet->priority = priority; 00255 tasklet->handler = handler; 00256 tasklet->data = data; 00257 tasklet->id = id; 00258 if (!pid) { 00259 tasklet->task = 0; 00260 } else { 00261 (tasklet->task)->priority = priority; 00262 rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_tasklet_struct)); 00263 } 00264 // tasklet insertion tasklets_list 00265 flags = rt_spin_lock_irqsave(&tasklets_lock); 00266 tasklet->next = &tasklets_list; 00267 tasklet->prev = tasklets_list.prev; 00268 (tasklets_list.prev)->next = tasklet; 00269 tasklets_list.prev = tasklet; 00270 rt_spin_unlock_irqrestore(flags, &tasklets_lock); 00271 return 0; 00272 } 00273 00274 /** 00275 * Remove a tasklet in the list of tasklets to be processed. 00276 * 00277 * rt_remove_tasklet remove a tasklet from the list of tasklets to be processed. 00278 * 00279 * @param tasklet is the pointer to the tasklet structure to be used to manage 00280 * the tasklet at hand. 00281 * 00282 */ 00283 00284 void rt_remove_tasklet(struct rt_tasklet_struct *tasklet) 00285 { 00286 if (tasklet->next != tasklet && tasklet->prev != tasklet) { 00287 unsigned long flags; 00288 flags = rt_spin_lock_irqsave(&tasklets_lock); 00289 (tasklet->next)->prev = tasklet->prev; 00290 (tasklet->prev)->next = tasklet->next; 00291 tasklet->next = tasklet->prev = tasklet; 00292 rt_spin_unlock_irqrestore(flags, &tasklets_lock); 00293 } 00294 } 00295 00296 /** 00297 * Find a tasklet identified by its id. 00298 * 00299 * @param id is the unique unsigned long to be used to identify the tasklet. 00300 * 00301 * The support functions nam2num() and num2nam() can be used for setting up id 00302 * from a six character string. 00303 * 00304 * @return the pointer to a tasklet handler on success 00305 * @retval 0 to indicate that @a id is not a valid identifier so that the 00306 * related tasklet was not found. 00307 * 00308 */ 00309 00310 struct rt_tasklet_struct *rt_find_tasklet_by_id(unsigned long id) 00311 { 00312 struct rt_tasklet_struct *tasklet; 00313 00314 tasklet = &tasklets_list; 00315 while ((tasklet = tasklet->next) != &tasklets_list) { 00316 if (id == tasklet->id) { 00317 return tasklet; 00318 } 00319 } 00320 return 0; 00321 } 00322 00323 /** 00324 * Exec a tasklet. 00325 * 00326 * rt_exec_tasklet execute a tasklet from the list of tasklets to be processed. 00327 * 00328 * @param tasklet is the pointer to the tasklet structure to be used to manage 00329 * the tasklet @a tasklet. 00330 * 00331 * Kernel space tasklets addresses are usually available directly and can be 00332 * easily be used in calling rt_tasklet_exec. In fact one can call the related 00333 * handler directly without using such a support function, which is mainly 00334 * supplied for symmetry and to ease the porting of applications from one space 00335 * to the other. 00336 * 00337 * User space tasklets instead must be first found within the tasklet list by 00338 * calling rt_find_tasklet_by_id() to get the tasklet address to be used 00339 * in rt_tasklet_exec(). 00340 * 00341 */ 00342 00343 int rt_exec_tasklet(struct rt_tasklet_struct *tasklet) 00344 { 00345 if (tasklet && tasklet->next != tasklet && tasklet->prev != tasklet) { 00346 if (!tasklet->task) { 00347 tasklet->handler(tasklet->data); 00348 } else { 00349 rt_task_resume(tasklet->task); 00350 } 00351 return 0; 00352 } 00353 return -EINVAL; 00354 } 00355 00356 void rt_set_tasklet_priority(struct rt_tasklet_struct *tasklet, int priority) 00357 { 00358 tasklet->priority = priority; 00359 if (tasklet->task) { 00360 (tasklet->task)->priority = priority; 00361 } 00362 } 00363 00364 int rt_set_tasklet_handler(struct rt_tasklet_struct *tasklet, void (*handler)(unsigned long)) 00365 { 00366 if (!handler) { 00367 return -EINVAL; 00368 } 00369 tasklet->handler = handler; 00370 if (tasklet->task) { 00371 rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_tasklet_struct)); 00372 } 00373 return 0; 00374 } 00375 00376 void rt_set_tasklet_data(struct rt_tasklet_struct *tasklet, unsigned long data) 00377 { 00378 tasklet->data = data; 00379 if (tasklet->task) { 00380 rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_tasklet_struct)); 00381 } 00382 } 00383 00384 RT_TASK *rt_tasklet_use_fpu(struct rt_tasklet_struct *tasklet, int use_fpu) 00385 { 00386 tasklet->uses_fpu = use_fpu ? 1 : 0; 00387 return tasklet->task; 00388 } 00389 00390 static RT_TASK timers_manager; 00391 00392 static inline void asgn_min_prio(void) 00393 { 00394 // find minimum priority in timers_struct 00395 struct rt_tasklet_struct *timer; 00396 unsigned long flags; 00397 int priority; 00398 00399 priority = (timer = timers_list.next)->priority; 00400 flags = rt_spin_lock_irqsave(&timers_lock); 00401 while ((timer = timer->next) != &timers_list) { 00402 if (timer->priority < priority) { 00403 priority = timer->priority; 00404 } 00405 rt_spin_unlock_irqrestore(flags, &timers_lock); 00406 flags = rt_spin_lock_irqsave(&timers_lock); 00407 } 00408 rt_spin_unlock_irqrestore(flags, &timers_lock); 00409 flags = rt_global_save_flags_and_cli(); 00410 if (timers_manager.priority > priority) { 00411 timers_manager.priority = priority; 00412 if (timers_manager.state == RT_SCHED_READY) { 00413 rem_ready_task(&timers_manager); 00414 enq_ready_task(&timers_manager); 00415 } 00416 } 00417 rt_global_restore_flags(flags); 00418 } 00419 00420 static inline void set_timer_firing_time(struct rt_tasklet_struct *timer, RTIME firing_time) 00421 { 00422 if (timer->next != timer && timer->prev != timer) { 00423 unsigned long flags; 00424 00425 timer->firing_time = firing_time; 00426 flags = rt_spin_lock_irqsave(&timers_lock); 00427 rem_timer(timer); 00428 enq_timer(timer); 00429 rt_spin_unlock_irqrestore(flags, &timers_lock); 00430 } 00431 } 00432 00433 /** 00434 * Insert a timer in the list of timers to be processed. 00435 * 00436 * rt_insert_timer insert a timer in the list of timers to be processed. Timers 00437 * can be either periodic or oneshot. A periodic timer is reloaded at each 00438 * expiration so that it executes with the assigned periodicity. A oneshot 00439 * timer is fired just once and then removed from the timers list. Timers can be 00440 * reinserted or modified within their handlers functions. 00441 * 00442 * @param timer is the pointer to the timer structure to be used to manage the 00443 * timer at hand. 00444 * 00445 * @param priority is the priority to be used to execute timers handlers when 00446 * more than one timer has to be fired at the same time.It can be assigned any 00447 * value such that: 0 < priority < RT_LOWEST_PRIORITY. 00448 * 00449 * @param firing_time is the time of the first timer expiration. 00450 * 00451 * @param period is the period of a periodic timer. A periodic timer keeps 00452 * calling its handler at firing_time + k*period k = 0, 1. To define a oneshot 00453 * timer simply use a null period. 00454 * 00455 * @param handler is the timer function to be executed at each timer expiration. 00456 * 00457 * @param data is an unsigned long to be passed to the handler. Clearly by a 00458 * appropriate type casting one can pass a pointer to whatever data structure 00459 * and type is needed. 00460 * 00461 * @param pid is an integer that marks a timer either as being a kernel or user 00462 * space one. Despite its name you need not to know the pid of the timer parent 00463 * process in user space. Simple use 0 for kernel space and 1 for user space. 00464 * 00465 * @retval 0 on success 00466 * @retval EINVAL if @a handler is an invalid handler address 00467 * 00468 */ 00469 00470 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) 00471 { 00472 unsigned long flags; 00473 00474 // timer initialization 00475 if (!handler) { 00476 return -EINVAL; 00477 } 00478 timer->uses_fpu = 0; 00479 timer->priority = priority; 00480 timer->firing_time = firing_time; 00481 timer->period = period; 00482 timer->handler = handler; 00483 timer->data = data; 00484 if (!pid) { 00485 timer->task = 0; 00486 } else { 00487 (timer->task)->priority = priority; 00488 rt_copy_to_user(timer->usptasklet, timer, sizeof(struct rt_tasklet_struct)); 00489 } 00490 // timer insertion in timers_list 00491 flags = rt_spin_lock_irqsave(&timers_lock); 00492 enq_timer(timer); 00493 rt_spin_unlock_irqrestore(flags, &timers_lock); 00494 // timers_manager priority inheritance 00495 if (timer->priority < timers_manager.priority) { 00496 timers_manager.priority = timer->priority; 00497 } 00498 // timers_task deadline inheritance 00499 flags = rt_global_save_flags_and_cli(); 00500 if (timers_list.next == timer && (timers_manager.state & RT_SCHED_DELAYED) && firing_time < timers_manager.resume_time) { 00501 timers_manager.resume_time = firing_time; 00502 rem_timed_task(&timers_manager); 00503 enq_timed_task(&timers_manager); 00504 rt_schedule(); 00505 } 00506 rt_global_restore_flags(flags); 00507 return 0; 00508 } 00509 00510 /** 00511 * Remove a timer in the list of timers to be processed. 00512 * 00513 * rt_remove_timer remove a timer from the list of the timers to be processed. 00514 * 00515 * @param timer is the pointer to the timer structure to be used to manage the 00516 * timer at hand. 00517 * 00518 */ 00519 00520 void rt_remove_timer(struct rt_tasklet_struct *timer) 00521 { 00522 if (timer->next != timer && timer->prev != timer) { 00523 unsigned long flags; 00524 flags = rt_spin_lock_irqsave(&timers_lock); 00525 rem_timer(timer); 00526 rt_spin_unlock_irqrestore(flags, &timers_lock); 00527 asgn_min_prio(); 00528 } 00529 } 00530 00531 /** 00532 * Change the priority of an existing timer. 00533 * 00534 * rt_set_timer_priority change the priority of an existing timer. 00535 * 00536 * @param timer is the pointer to the timer structure to be used to manage the 00537 * timer at hand. 00538 * 00539 * @param priority is the priority to be used to execute timers handlers when 00540 * more than one timer has to be fired at the same time. It can be assigned any 00541 * value such that: 0 < priority < RT_LOWEST_PRIORITY. 00542 * 00543 * This function can be used within the timer handler. 00544 * 00545 */ 00546 00547 void rt_set_timer_priority(struct rt_tasklet_struct *timer, int priority) 00548 { 00549 timer->priority = priority; 00550 if (timer->task) { 00551 (timer->task)->priority = priority; 00552 } 00553 asgn_min_prio(); 00554 } 00555 00556 /** 00557 * Change the firing time of a timer. 00558 * 00559 * rt_set_timer_firing_time changes the firing time of a periodic timer 00560 * overloading any existing value, so that the timer next shoot will take place 00561 * at the new firing time. Note that if a oneshot timer has its firing time 00562 * changed after it has already expired this function has no effect. You 00563 * should reinsert it in the timer list with the new firing time. 00564 * 00565 * @param timer is the pointer to the timer structure to be used to manage the 00566 * timer at hand. 00567 * 00568 * @param firing_time is the new time of the first timer expiration. 00569 * 00570 * This function can be used within the timer handler. 00571 * 00572 * @retval 0 on success. 00573 * 00574 */ 00575 00576 void rt_set_timer_firing_time(struct rt_tasklet_struct *timer, RTIME firing_time) 00577 { 00578 unsigned long flags; 00579 00580 set_timer_firing_time(timer, firing_time); 00581 flags = rt_global_save_flags_and_cli(); 00582 if (timers_list.next == timer && (timers_manager.state & RT_SCHED_DELAYED) && firing_time < timers_manager.resume_time) { 00583 timers_manager.resume_time = firing_time; 00584 rem_timed_task(&timers_manager); 00585 enq_timed_task(&timers_manager); 00586 rt_schedule(); 00587 } 00588 rt_global_restore_flags(flags); 00589 } 00590 00591 /** 00592 * Change the period of a timer. 00593 * 00594 * rt_set_timer_period changes the period of a periodic timer. Note that the new 00595 * period will be used to pace the timer only after the expiration of the firing 00596 * time already in place. Using this function with a period different from zero 00597 * for a oneshot timer, that has not expired yet, will transform it into a 00598 * periodic timer. 00599 * 00600 * @param timer is the pointer to the timer structure to be used to manage the 00601 * timer at hand. 00602 * 00603 * @param period is the new period of a periodic timer. 00604 * 00605 * The macro #rt_fast_set_timer_period can substitute the corresponding 00606 * function in kernel space if both the existing timer period and the new one 00607 * fit into an 32 bits integer. 00608 * 00609 * This function an be used within the timer handler. 00610 * 00611 * @retval 0 on success. 00612 * 00613 */ 00614 00615 void rt_set_timer_period(struct rt_tasklet_struct *timer, RTIME period) 00616 { 00617 unsigned long flags; 00618 flags = rt_spin_lock_irqsave(&timers_lock); 00619 timer->period = period; 00620 rt_spin_unlock_irqrestore(flags, &timers_lock); 00621 } 00622 00623 // the timers_manager task function 00624 00625 static void rt_timers_manager(long dummy) 00626 { 00627 RTIME now; 00628 struct rt_tasklet_struct *tmr, *timer; 00629 unsigned long flags; 00630 int priority, used_fpu; 00631 00632 while (1) { 00633 rt_sleep_until((timers_list.next)->firing_time); 00634 now = timers_manager.resume_time + tuned.timers_tol[0]; 00635 // find all the timers to be fired, in priority order 00636 while (1) { 00637 used_fpu = 0; 00638 tmr = timer = &timers_list; 00639 priority = RT_SCHED_LOWEST_PRIORITY; 00640 flags = rt_spin_lock_irqsave(&timers_lock); 00641 while ((tmr = tmr->next)->firing_time <= now) { 00642 if (tmr->priority < priority) { 00643 priority = (timer = tmr)->priority; 00644 } 00645 } 00646 timers_manager.priority = priority; 00647 rt_spin_unlock_irqrestore(flags, &timers_lock); 00648 if (timer == &timers_list) { 00649 break; 00650 } 00651 if (!timer->period) { 00652 flags = rt_spin_lock_irqsave(&timers_lock); 00653 rem_timer(timer); 00654 rt_spin_unlock_irqrestore(flags, &timers_lock); 00655 } else { 00656 set_timer_firing_time(timer, timer->firing_time + timer->period); 00657 } 00658 if (!timer->task) { 00659 if (!used_fpu && timer->uses_fpu) { 00660 used_fpu = 1; 00661 save_fpcr_and_enable_fpu(linux_cr0); 00662 save_fpenv(timers_manager.fpu_reg); 00663 } 00664 timer->handler(timer->data); 00665 } else { 00666 rt_task_resume(timer->task); 00667 } 00668 } 00669 if (used_fpu) { 00670 restore_fpenv(timers_manager.fpu_reg); 00671 restore_fpcr(linux_cr0); 00672 } 00673 // set next timers_manager priority according to the highest priority timer 00674 asgn_min_prio(); 00675 // if no more timers in timers_struct remove timers_manager from tasks list 00676 } 00677 } 00678 00679 /** 00680 * Init, in kernel space, a tasklet structure to be used in user space. 00681 * 00682 * rt_tasklet_init allocate a tasklet structure (struct rt_tasklet_struct) in 00683 * kernel space to be used for the management of a user space tasklet. 00684 * 00685 * This function is to be used only for user space tasklets. In kernel space 00686 * it is just an empty macro, as the user can, and must allocate the related 00687 * structure directly, either statically or dynamically. 00688 * 00689 * @return the pointer to the tasklet structure the user space application must 00690 * use to access all its related services. 00691 */ 00692 struct rt_tasklet_struct *rt_init_tasklet(void) 00693 { 00694 struct rt_tasklet_struct *tasklet; 00695 tasklet = sched_malloc(sizeof(struct rt_tasklet_struct)); 00696 memset(tasklet, 0, sizeof(struct rt_tasklet_struct)); 00697 return tasklet; 00698 } 00699 00700 void rt_register_task(struct rt_tasklet_struct *tasklet, struct rt_tasklet_struct *usptasklet, RT_TASK *task) 00701 { 00702 tasklet->task = task; 00703 tasklet->usptasklet = usptasklet; 00704 rt_copy_to_user(usptasklet, tasklet, sizeof(struct rt_tasklet_struct)); 00705 } 00706 00707 void rt_wait_tasklet_is_hard(struct rt_tasklet_struct *tasklet, int thread) 00708 { 00709 tasklet->thread = thread; 00710 while (!tasklet->task || !((tasklet->task)->state & RT_SCHED_SUSPENDED)) { 00711 current->state = TASK_INTERRUPTIBLE; 00712 schedule_timeout(2); 00713 } 00714 } 00715 00716 /** 00717 * Delete, in kernel space, a tasklet structure to be used in user space. 00718 * 00719 * rt_tasklet_delete free a tasklet structure (struct rt_tasklet_struct) in 00720 * kernel space that was allocated by rt_tasklet_init. 00721 * 00722 * @param tasklet is the pointer to the tasklet structure (struct 00723 * rt_tasklet_struct) returned by rt_tasklet_init. 00724 * 00725 * This function is to be used only for user space tasklets. In kernel space 00726 * it is just an empty macro, as the user can, and must allocate the related 00727 * structure directly, either statically or dynamically. 00728 * 00729 */ 00730 00731 int rt_delete_tasklet(struct rt_tasklet_struct *tasklet) 00732 { 00733 int thread; 00734 00735 rt_remove_tasklet(tasklet); 00736 tasklet->handler = 0; 00737 rt_copy_to_user(tasklet->usptasklet, tasklet, sizeof(struct rt_tasklet_struct)); 00738 rt_task_resume(tasklet->task); 00739 thread = tasklet->thread; 00740 sched_free(tasklet); 00741 return thread; 00742 } 00743 00744 static int tasklets_stacksize = TASKLET_STACK_SIZE; 00745 MODULE_PARM(tasklets_stacksize, "i"); 00746 00747 static RT_TASK *rt_base_linux_task; 00748 00749 int __rtai_tasklets_init(void) 00750 { 00751 RT_TASK *rt_linux_tasks[NR_RT_CPUS]; 00752 rt_base_linux_task = rt_get_base_linux_task(rt_linux_tasks); 00753 if (rt_sched_type() == RT_SCHED_MUP) { 00754 tuned.timers_tol[0] = tuned.timers_tol[timers_manager.runnable_on_cpus]; 00755 } 00756 if(rt_base_linux_task->task_trap_handler[0]) { 00757 if(((int (*)(void *, int))rt_base_linux_task->task_trap_handler[0])(rt_tasklet_fun, TSKIDX)) { 00758 printk("Recompile your module with a different index\n"); 00759 return -EACCES; 00760 } 00761 } 00762 rt_task_init(&timers_manager, rt_timers_manager, 0, tasklets_stacksize, RT_SCHED_LOWEST_PRIORITY, 0, 0); 00763 rt_task_resume(&timers_manager); 00764 printk(KERN_INFO "RTAI[tasklets]: loaded.\n"); 00765 return 0; 00766 } 00767 00768 void __rtai_tasklets_exit(void) 00769 { 00770 rt_task_delete(&timers_manager); 00771 if(rt_base_linux_task->task_trap_handler[1]) { 00772 ((int (*)(void *, int))rt_base_linux_task->task_trap_handler[1])(rt_tasklet_fun, TSKIDX); 00773 } 00774 printk(KERN_INFO "RTAI[tasklets]: unloaded.\n"); 00775 } 00776 00777 /*@}*/ 00778 00779 #ifndef CONFIG_RTAI_TASKLETS_BUILTIN 00780 module_init(__rtai_tasklets_init); 00781 module_exit(__rtai_tasklets_exit); 00782 #endif /* !CONFIG_RTAI_TASKLETS_BUILTIN */ 00783 00784 #ifdef CONFIG_KBUILD 00785 EXPORT_SYMBOL(rt_insert_tasklet); 00786 EXPORT_SYMBOL(rt_remove_tasklet); 00787 EXPORT_SYMBOL(rt_find_tasklet_by_id); 00788 EXPORT_SYMBOL(rt_exec_tasklet); 00789 EXPORT_SYMBOL(rt_set_tasklet_priority); 00790 EXPORT_SYMBOL(rt_set_tasklet_handler); 00791 EXPORT_SYMBOL(rt_set_tasklet_data); 00792 EXPORT_SYMBOL(rt_tasklet_use_fpu); 00793 EXPORT_SYMBOL(rt_insert_timer); 00794 EXPORT_SYMBOL(rt_remove_timer); 00795 EXPORT_SYMBOL(rt_set_timer_priority); 00796 EXPORT_SYMBOL(rt_set_timer_firing_time); 00797 EXPORT_SYMBOL(rt_set_timer_period); 00798 EXPORT_SYMBOL(rt_init_tasklet); 00799 EXPORT_SYMBOL(rt_register_task); 00800 EXPORT_SYMBOL(rt_wait_tasklet_is_hard); 00801 EXPORT_SYMBOL(rt_delete_tasklet); 00802 #endif /* CONFIG_KBUILD */

Generated on Thu Nov 20 11:49:53 2008 for RTAI API by doxygen 1.3.8