rtai_tasklets.h
1 /** 2 * @ingroup tasklets 3 * @file 4 * 5 * Interface of the @ref tasklets "mini LXRT RTAI tasklets module". 6 * 7 * @author Paolo Mantegazza 8 * 9 * @note Copyright © 1999-2003 Paolo Mantegazza <mantegazza@aero.polimi.it> 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of the 14 * License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 */ 25 26 #ifndef _RTAI_TASKLETS_H 27 #define _RTAI_TASKLETS_H 28 29 /** 30 * @addtogroup tasklets 31 *@{*/ 32 33 #include <rtai_types.h> 34 #include <rtai_sched.h> 35 36 #define TASKLETS_IDX 1 37 38 #define INIT 0 39 #define DELETE 1 40 #define TASK_INSERT 2 41 #define TASK_REMOVE 3 42 #define USE_FPU 4 43 #define TIMER_INSERT 5 44 #define TIMER_REMOVE 6 45 #define SET_TASKLETS_PRI 7 46 #define SET_FIR_TIM 8 47 #define SET_PER 9 48 #define SET_HDL 10 49 #define SET_DAT 11 50 #define EXEC_TASKLET 12 51 #define WAIT_IS_HARD 13 52 #define SET_TSK_PRI 14 53 #define REG_TASK 15 54 #define GET_TMR_TIM 16 55 #define GET_TMR_OVRN 17 56 57 /* Posix timers support */ 58 59 #define PTIMER_CREATE 18 60 #define PTIMER_SETTIME 19 61 #define PTIMER_OVERRUN 20 62 #define PTIMER_GETTIME 21 63 #define PTIMER_DELETE 22 64 65 #define POSIX_TIMERS 128 66 67 /* End Posix timers support */ 68 69 struct rt_task_struct; 70 71 #define TASKLET_STACK_SIZE 8196 72 73 struct rt_usp_tasklet_struct { 74 struct rt_tasklet_struct *next, *prev; 75 int priority, uses_fpu, cpuid; 76 RTIME firing_time, period; 77 void (*handler)(unsigned long); 78 unsigned long data, id; 79 long thread; 80 struct rt_task_struct *task; 81 struct rt_tasklet_struct *usptasklet; 82 int overrun; 83 }; 84 85 #ifdef __KERNEL__ 86 87 struct rt_tasklet_struct { 88 struct rt_tasklet_struct *next, *prev; 89 int priority, uses_fpu, cpuid; 90 RTIME firing_time, period; 91 void (*handler)(unsigned long); 92 unsigned long data, id; 93 long thread; 94 struct rt_task_struct *task; 95 struct rt_tasklet_struct *usptasklet; 96 int overrun; 97 #ifdef CONFIG_RTAI_LONG_TIMED_LIST 98 rb_root_t rbr; 99 rb_node_t rbn; 100 #endif 101 }; 102 103 #ifdef __cplusplus 104 extern "C" { 105 #endif /* !__cplusplus */ 106 107 int __rtai_tasklets_init(void); 108 109 void __rtai_tasklets_exit(void); 110 111 struct rt_tasklet_struct *rt_init_tasklet(void); 112 113 RTAI_SYSCALL_MODE int rt_delete_tasklet(struct rt_tasklet_struct *tasklet); 114 115 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); 116 117 RTAI_SYSCALL_MODE void rt_remove_tasklet(struct rt_tasklet_struct *tasklet); 118 119 struct rt_tasklet_struct *rt_find_tasklet_by_id(unsigned long id); 120 121 RTAI_SYSCALL_MODE int rt_exec_tasklet(struct rt_tasklet_struct *tasklet); 122 123 RTAI_SYSCALL_MODE void rt_set_tasklet_priority(struct rt_tasklet_struct *tasklet, int priority); 124 125 RTAI_SYSCALL_MODE int rt_set_tasklet_handler(struct rt_tasklet_struct *tasklet, void (*handler)(unsigned long)); 126 127 #define rt_fast_set_tasklet_handler(t, h) do { (t)->handler = (h); } while (0) 128 129 RTAI_SYSCALL_MODE void rt_set_tasklet_data(struct rt_tasklet_struct *tasklet, unsigned long data); 130 131 #define rt_fast_set_tasklet_data(t, d) \ 132 do { \ 133 (t)->data = (d); \ 134 } while (0) 135 136 /** 137 * Notify the use of floating point operations within any tasklet/timer. 138 * 139 * rt_tasklets_use_fpu notifies that there is at least one tasklet/timer using 140 * floating point calculations within its handler function. 141 * 142 * @param use_fpu set/resets the use of floating point calculations: 143 * - a value different from 0 sets the use of floating point calculations ; 144 * - a 0 value resets the no floating calculations state. 145 * 146 * Note that the use of floating calculations is assigned once for all and is 147 * valid for all tasklets/timers. If just one handler needs it all of them 148 * will have floating point support. An optimized floating point support, 149 * i.e. on a per tasklet/timer base will add an unnoticeable performance 150 * improvement on most CPUs. However such an optimization is not rule out a 151 * priori, if anybody can prove it is really important. 152 * 153 * This function and macro can be used within the timer handler. 154 * 155 */ 156 RTAI_SYSCALL_MODE struct rt_task_struct *rt_tasklet_use_fpu(struct rt_tasklet_struct *tasklet, int use_fpu); 157 158 /** 159 * Init, in kernel space, a timed tasklet, simply called timer, structure 160 * to be used in user space. 161 * 162 * rt_timer_init allocate a timer tasklet structure (struct rt_tasklet_struct) 163 * in kernel space to be used for the management of a user space timer. 164 * 165 * This function is to be used only for user space timers. In kernel space 166 * it is just an empty macro, as the user can, and must allocate the related 167 * structure directly, either statically or dynamically. 168 * 169 * @return the pointer to the timer structure the user space application must 170 * use to access all its related services. 171 * 172 */ 173 #define rt_init_timer rt_init_tasklet 174 175 /** 176 * Delete, in kernel space, a timed tasklet, simply called timer, structure 177 * to be used in user space. 178 * 179 * rt_timer_delete free a timer tasklet structure (struct rt_tasklet_struct) in 180 * kernel space that was allocated by rt_timer_init. 181 * 182 * @param timer is a pointer to a timer tasklet structure (struct 183 * rt_tasklet_struct). 184 * 185 * This function is to be used only for user space timers. In kernel space 186 * it is just an empty macro, as the user can, and must allocate the related 187 * structure directly, either statically or dynamically. 188 * 189 */ 190 #define rt_delete_timer rt_delete_tasklet 191 192 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); 193 194 RTAI_SYSCALL_MODE void rt_remove_timer(struct rt_tasklet_struct *timer); 195 196 RTAI_SYSCALL_MODE void rt_set_timer_priority(struct rt_tasklet_struct *timer, int priority); 197 198 RTAI_SYSCALL_MODE void rt_set_timer_firing_time(struct rt_tasklet_struct *timer, RTIME firing_time); 199 200 RTAI_SYSCALL_MODE void rt_set_timer_period(struct rt_tasklet_struct *timer, RTIME period); 201 202 RTAI_SYSCALL_MODE void rt_get_timer_times(struct rt_tasklet_struct *timer, RTIME timer_times[]); 203 204 RTAI_SYSCALL_MODE RTIME rt_get_timer_overrun(struct rt_tasklet_struct *timer); 205 206 /* Posix timers support */ 207 208 RTAI_SYSCALL_MODE timer_t rt_ptimer_create(struct rt_tasklet_struct *timer, void (*handler)(unsigned long), unsigned long data, long pid, long thread); 209 210 RTAI_SYSCALL_MODE void rt_ptimer_settime(timer_t timer, const struct itimerspec *value, unsigned long data, long flags); 211 212 RTAI_SYSCALL_MODE int rt_ptimer_overrun(timer_t timer); 213 214 RTAI_SYSCALL_MODE void rt_ptimer_gettime(timer_t timer, RTIME timer_times[]); 215 216 RTAI_SYSCALL_MODE int rt_ptimer_delete(timer_t timer, long space); 217 218 /* End Posix timers support */ 219 220 #define rt_fast_set_timer_period(t, p) \ 221 do { \ 222 (t)->period = (p); \ 223 } while (0) 224 225 /** 226 * Change the timer handler. 227 * 228 * rt_set_timer_handler changes the timer handler function overloading any 229 * existing value, so that at the next timer firing the new handler will be 230 * used. Note that if a oneshot timer has its handler changed after it has 231 * already expired this function has no effect. You should reinsert it in the 232 * timer list with the new handler. 233 * 234 * @param timer is the pointer to the timer structure to be used to manage the 235 * timer at hand. 236 * 237 * @param handler is the new handler. 238 * 239 * The macro rt_fast_set_timer_handler can safely be used to substitute the 240 * corresponding function in kernel space. 241 * 242 * This function and macro can be used within the timer handler. 243 * 244 * @retval 0 on success. 245 * 246 */ 247 #define rt_set_timer_handler rt_set_tasklet_handler 248 249 #define rt_fast_set_timer_handler(t, h) do { (t)->handler = (h); } while (0) 250 251 /** 252 * Change the data passed to a timer. 253 * 254 * rt_set_timer_data changes the timer data, overloading any existing value, so 255 * that at the next timer firing the new data will be used. Note that if a 256 * oneshot timer has its data changed after it is already expired this function 257 * has no effect. You should reinsert it in the timer list with the new data. 258 * 259 * @param timer is the pointer to the timer structure to be used to manage the 260 * timer at hand. 261 * 262 * @param data is the new data. 263 * 264 * The macro rt_fast_set_timer_data can safely be used substitute the 265 * corresponding function in kernel space. 266 * 267 * This function and macro can be used within the timer handler. 268 * 269 * @retval 0 on success. 270 * 271 */ 272 #define rt_set_timer_data rt_set_tasklet_data 273 274 #define rt_fast_set_timer_data(t, d) do { (t)->data = (d); } while (0) 275 276 #define rt_timer_use_fpu rt_tasklet_use_fpu 277 278 RTAI_SYSCALL_MODE int rt_wait_tasklet_is_hard(struct rt_tasklet_struct *tasklet, long thread); 279 280 RTAI_SYSCALL_MODE void rt_register_task(struct rt_tasklet_struct *tasklet, struct rt_tasklet_struct *usptasklet, struct rt_task_struct *task); 281 282 #ifdef __cplusplus 283 } 284 #endif /* __cplusplus */ 285 286 #else /* !__KERNEL__ */ 287 288 #include <sys/types.h> 289 #include <sys/wait.h> 290 #include <sys/mman.h> 291 #include <stdarg.h> 292 293 #include <rtai_lxrt.h> 294 295 #define rt_tasklet_struct rt_usp_tasklet_struct 296 #if 0 297 struct rt_tasklet_struct { 298 struct rt_tasklet_struct *next, *prev; 299 int priority, uses_fpu, cpuid; 300 RTIME firing_time, period; 301 void (*handler)(unsigned long); 302 unsigned long data, id; 303 long thread; 304 struct rt_task_struct *task; 305 struct rt_tasklet_struct *usptasklet; 306 int overrun; 307 #ifdef CONFIG_RTAI_LONG_TIMED_LIST 308 struct { void *rb_parent; int rb_color; void *rb_right, *rb_left; } rbn; 309 struct { void *rb_node; } rbr; 310 #endif 311 }; 312 #endif 313 314 #ifndef __SUPPORT_TASKLET__ 315 #define __SUPPORT_TASKLET__ 316 317 struct support_tasklet_s { struct rt_tasklet_struct *tasklet; pthread_t thread; volatile int done; }; 318 319 static int support_tasklet(struct support_tasklet_s *args) 320 { 321 RT_TASK *task; 322 struct rt_tasklet_struct usptasklet; 323 324 if ((task = rt_thread_init((unsigned long)args->tasklet, 98, 0, SCHED_FIFO, 0xF))) { 325 { 326 struct { struct rt_tasklet_struct *tasklet, *usptasklet; RT_TASK *task; } reg = { args->tasklet, &usptasklet, task }; 327 rtai_lxrt(TASKLETS_IDX, sizeof(reg), REG_TASK, ®); 328 } 329 rt_grow_and_lock_stack(TASKLET_STACK_SIZE/2); 330 mlockall(MCL_CURRENT | MCL_FUTURE); 331 rt_make_hard_real_time(); 332 args->done = 1; 333 while (1) { 334 rt_task_suspend(task); 335 if (usptasklet.handler) { 336 usptasklet.handler(usptasklet.data); 337 } else { 338 break; 339 } 340 } 341 rt_make_soft_real_time(); 342 rt_task_delete(task); 343 return 0; 344 } 345 printf("CANNOT INIT SUPPORT TASKLET\n"); 346 return -1; 347 348 } 349 #endif /* __SUPPORT_TASKLET__ */ 350 351 #ifdef __cplusplus 352 extern "C" { 353 #endif /* __cplusplus */ 354 355 RTAI_PROTO(void, rt_delete_tasklet, (struct rt_tasklet_struct *tasklet)); 356 357 RTAI_PROTO(struct rt_tasklet_struct *, rt_init_tasklet, (void)) 358 { 359 int is_hard; 360 struct support_tasklet_s arg; 361 362 if ((arg.tasklet = (struct rt_tasklet_struct*)rtai_lxrt(TASKLETS_IDX, SIZARG, INIT, &arg).v[LOW])) { 363 if ((is_hard = rt_is_hard_real_time(NULL))) { 364 rt_make_soft_real_time(); 365 } 366 arg.done = 0; 367 if ((arg.thread = rt_thread_create((void *)support_tasklet, &arg.tasklet, TASKLET_STACK_SIZE))) { 368 int i; 369 #define POLLS_PER_SEC 100 370 for (i = 0; i < POLLS_PER_SEC/5 && !arg.done; i++) { 371 struct timespec delay = { 0, 1000000000/POLLS_PER_SEC }; 372 nanosleep(&delay, NULL); 373 } 374 #undef POLLS_PER_SEC 375 if (!arg.done || rtai_lxrt(TASKLETS_IDX, SIZARG, WAIT_IS_HARD, &arg).i[LOW]) { 376 goto notdone; 377 } 378 } else { 379 notdone: 380 rt_delete_tasklet(arg.tasklet); 381 arg.tasklet = NULL; 382 } 383 if (is_hard) { 384 rt_make_hard_real_time(); 385 } 386 } 387 return arg.tasklet; 388 } 389 390 #define rt_init_timer rt_init_tasklet 391 392 RTAI_PROTO(void, rt_delete_tasklet, (struct rt_tasklet_struct *tasklet)) 393 { 394 int thread; 395 struct { struct rt_tasklet_struct *tasklet; } arg = { tasklet }; 396 if ((thread = rtai_lxrt(TASKLETS_IDX, SIZARG, DELETE, &arg).i[LOW])) { 397 rt_thread_join(thread); 398 } 399 } 400 401 #define rt_delete_timer rt_delete_tasklet 402 403 RTAI_PROTO(int, rt_insert_timer,(struct rt_tasklet_struct *timer, 404 int priority, 405 RTIME firing_time, 406 RTIME period, 407 void (*handler)(unsigned long), 408 unsigned long data, 409 int pid)) 410 { 411 struct { struct rt_tasklet_struct *timer; long priority; RTIME firing_time; RTIME period; void (*handler)(unsigned long); unsigned long data; long pid; } arg = { timer, priority, firing_time, period, handler, data, pid }; 412 return rtai_lxrt(TASKLETS_IDX, SIZARG, TIMER_INSERT, &arg).i[LOW]; 413 } 414 415 RTAI_PROTO(void, rt_remove_timer, (struct rt_tasklet_struct *timer)) 416 { 417 struct { struct rt_tasklet_struct *timer; } arg = { timer }; 418 rtai_lxrt(TASKLETS_IDX, SIZARG, TIMER_REMOVE, &arg); 419 } 420 421 RTAI_PROTO(void, rt_set_timer_priority, (struct rt_tasklet_struct *timer, int priority)) 422 { 423 struct { struct rt_tasklet_struct *timer; long priority; } arg = { timer, priority }; 424 rtai_lxrt(TASKLETS_IDX, SIZARG, SET_TASKLETS_PRI, &arg); 425 } 426 427 RTAI_PROTO(void, rt_set_timer_firing_time, (struct rt_tasklet_struct *timer, RTIME firing_time)) 428 { 429 struct { struct rt_tasklet_struct *timer; RTIME firing_time; } arg = { timer, firing_time }; 430 rtai_lxrt(TASKLETS_IDX, SIZARG, SET_FIR_TIM, &arg); 431 } 432 433 RTAI_PROTO(void, rt_set_timer_period, (struct rt_tasklet_struct *timer, RTIME period)) 434 { 435 struct { struct rt_tasklet_struct *timer; RTIME period; } arg = { timer, period }; 436 rtai_lxrt(TASKLETS_IDX, SIZARG, SET_PER, &arg); 437 } 438 439 RTAI_PROTO(void, rt_get_timer_times, (struct rt_tasklet_struct *timer, RTIME timer_times[])) 440 { 441 if (timer_times) { 442 RTIME ltimer_times[2]; 443 struct { struct rt_tasklet_struct *timer; RTIME *timer_times; } arg = { timer, ltimer_times }; 444 rtai_lxrt(TASKLETS_IDX, SIZARG, GET_TMR_TIM, &arg); 445 memcpy(timer_times, ltimer_times, sizeof(ltimer_times)); 446 } 447 } 448 449 RTAI_PROTO(RTIME, rt_get_timer_overrun, (struct rt_tasklet_struct *timer )) 450 { 451 struct { struct rt_tasklet_struct *timer; } arg = { timer }; 452 return rtai_lxrt(TASKLETS_IDX, SIZARG, GET_TMR_OVRN, &arg).rt; 453 } 454 455 RTAI_PROTO(int, rt_set_tasklet_handler, (struct rt_tasklet_struct *tasklet, void (*handler)(unsigned long))) 456 { 457 struct { struct rt_tasklet_struct *tasklet; void (*handler)(unsigned long); } arg = { tasklet, handler }; 458 return rtai_lxrt(TASKLETS_IDX, SIZARG, SET_HDL, &arg).i[LOW]; 459 } 460 461 #define rt_set_timer_handler rt_set_tasklet_handler 462 463 RTAI_PROTO(void, rt_set_tasklet_data, (struct rt_tasklet_struct *tasklet, unsigned long data)) 464 { 465 struct { struct rt_tasklet_struct *tasklet; unsigned long data; } arg = { tasklet, data }; 466 rtai_lxrt(TASKLETS_IDX, SIZARG, SET_DAT, &arg); 467 } 468 469 #define rt_set_timer_data rt_set_tasklet_data 470 471 RTAI_PROTO(RT_TASK *, rt_tasklet_use_fpu, (struct rt_tasklet_struct *tasklet, int use_fpu)) 472 { 473 RT_TASK *task; 474 struct { struct rt_tasklet_struct *tasklet; long use_fpu; } arg = { tasklet, use_fpu }; 475 if ((task = (RT_TASK*)rtai_lxrt(TASKLETS_IDX, SIZARG, USE_FPU, &arg).v[LOW])) { 476 rt_task_use_fpu(task, use_fpu); 477 } 478 return task; 479 } 480 481 #define rt_timer_use_fpu rt_tasklet_use_fpu 482 483 RTAI_PROTO(int, rt_insert_tasklet,(struct rt_tasklet_struct *tasklet, 484 int priority, 485 void (*handler)(unsigned long), 486 unsigned long data, 487 unsigned long id, 488 int pid)) 489 { 490 struct { struct rt_tasklet_struct *tasklet; long priority; void (*handler)(unsigned long); unsigned long data; unsigned long id; long pid; } arg = { tasklet, priority, handler, data, id, pid }; 491 return rtai_lxrt(TASKLETS_IDX, SIZARG, TASK_INSERT, &arg).i[LOW]; 492 } 493 494 RTAI_PROTO(void, rt_set_tasklet_priority, (struct rt_tasklet_struct *tasklet, int priority)) 495 { 496 struct { struct rt_tasklet_struct *tasklet; long priority; } arg = { tasklet, priority }; 497 rtai_lxrt(TASKLETS_IDX, SIZARG, SET_TSK_PRI, &arg); 498 } 499 500 RTAI_PROTO(void, rt_remove_tasklet, (struct rt_tasklet_struct *tasklet)) 501 { 502 struct { struct rt_tasklet_struct *tasklet; } arg = { tasklet }; 503 rtai_lxrt(TASKLETS_IDX, SIZARG, TASK_REMOVE, &arg); 504 } 505 506 RTAI_PROTO(int, rt_exec_tasklet, (struct rt_tasklet_struct *tasklet)) 507 { 508 struct { struct rt_tasklet_struct *tasklet; } arg = { tasklet }; 509 return rtai_lxrt(TASKLETS_IDX, SIZARG, EXEC_TASKLET, &arg).i[LOW]; 510 } 511 512 #include <stdlib.h> 513 514 struct rt_tasklets_struct { volatile int in, out, avb, ntasklets; struct rt_tasklet_struct **tasklets; unsigned long lock; }; 515 516 RTAI_PROTO(struct rt_tasklets_struct *, rt_create_tasklets, (int ntasklets)) 517 { 518 struct rt_tasklets_struct *tasklets; 519 if ((tasklets = (struct rt_tasklets_struct *)malloc(sizeof(struct rt_tasklets_struct)))) { 520 if ((tasklets->tasklets = (struct rt_tasklet_struct **)malloc(ntasklets*sizeof(struct rt_tasklet_struct *)))) { 521 int i; 522 for (i = 0; i < ntasklets; i++) { 523 if (!(tasklets->tasklets[i] = rt_init_tasklet())) { 524 int k; 525 for (k = 0; k < i; k++) { 526 rt_delete_tasklet(tasklets->tasklets[k]); 527 } 528 free(tasklets->tasklets); 529 goto free_tasklets; 530 } 531 } 532 tasklets->lock = 0; 533 tasklets->ntasklets = tasklets->avb = tasklets->in = tasklets->out = ntasklets; 534 return tasklets; 535 } else { 536 free_tasklets: 537 free(tasklets); 538 } 539 } 540 return NULL; 541 } 542 543 #define rt_create_timers rt_create_tasklets 544 545 RTAI_PROTO(void, rt_destroy_tasklets, (struct rt_tasklets_struct *tasklets)) 546 { 547 int i; 548 for (i = 0; i < tasklets->ntasklets; i++) { 549 rt_delete_tasklet(tasklets->tasklets[i]); 550 } 551 free(tasklets->tasklets); 552 free(tasklets); 553 } 554 555 #define rt_destroy_timers rt_destroy_tasklets 556 557 #include <asm/rtai_atomic.h> 558 559 RTAI_PROTO(struct rt_tasklet_struct *, rt_get_tasklet, (struct rt_tasklets_struct *tasklets)) 560 { 561 struct rt_tasklet_struct *tasklet; 562 while (atomic_cmpxchg((void *)&tasklets->lock, 0, 1)); 563 if (tasklets->avb > 0) { 564 if (tasklets->out >= tasklets->ntasklets) { 565 tasklets->out = 0; 566 } 567 tasklets->avb--; 568 tasklet = tasklets->tasklets[tasklets->out++]; 569 tasklets->lock = 0; 570 return tasklet; 571 } 572 tasklets->lock = 0; 573 return NULL; 574 } 575 576 #define rt_get_timer rt_get_tasklet 577 578 RTAI_PROTO(int, rt_gvb_tasklet, (struct rt_tasklet_struct *tasklet, struct rt_tasklets_struct *tasklets)) 579 { 580 while (atomic_cmpxchg((void *)&tasklets->lock, 0, 1)); 581 if (tasklets->avb < tasklets->ntasklets) { 582 if (tasklets->in >= tasklets->ntasklets) { 583 tasklets->in = 0; 584 } 585 tasklets->avb++; 586 tasklets->tasklets[tasklets->in++] = tasklet; 587 tasklets->lock = 0; 588 return 0; 589 } 590 tasklets->lock = 0; 591 return EINVAL; 592 } 593 594 #define rt_gvb_timer rt_gvb_tasklet 595 596 #ifdef __cplusplus 597 } 598 #endif /* __cplusplus */ 599 600 #endif /* __KERNEL__ */ 601 602 /*@}*/ 603 604 #endif /* !_RTAI_TASKLETS_H */