base/ipc/msg/msg.c

Go to the documentation of this file.
00001 /** 00002 * @file 00003 * Message handling functions. 00004 * @author Paolo Mantegazza 00005 * 00006 * @note Copyright (C) 1999-2003 Paolo Mantegazza 00007 * <mantegazza@aero.polimi.it> [ Specific COPYRIGHTS follow along the 00008 * code ] 00009 * 00010 * This program is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU General Public License as 00012 * published by the Free Software Foundation; either version 2 of the 00013 * License, or (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU General Public License 00021 * along with this program; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00023 * 00024 * @ingroup msg 00025 * @ingroup rpc 00026 */ 00027 00028 /** 00029 * @ingroup sched 00030 * @defgroup msg Message handling functions 00031 */ 00032 00033 /** 00034 * @ingroup sched 00035 * @defgroup rpc Remote procedure call functions 00036 */ 00037 00038 #include <rtai_schedcore.h> 00039 00040 MODULE_LICENSE("GPL"); 00041 00042 /* +++++++++++++++++++++++ SHORT INTERTASK MESSAGES +++++++++++++++++++++++++ */ 00043 00044 /* +++++++++++++++++++++++++++++ ASYNC SENDS ++++++++++++++++++++++++++++++++ */ 00045 00046 static inline void reset_task_prio(RT_TASK *task) 00047 { 00048 if (task->owndres & RPCHLF) { 00049 task->owndres -= RPCINC; 00050 } 00051 if (!task->owndres) { 00052 renq_ready_task(task, task->base_priority); 00053 } else if (!(task->owndres & SEMHLF)) { 00054 int priority; 00055 renq_ready_task(task, task->base_priority > (priority = ((task->msg_queue.next)->task)->priority) ? priority : task->base_priority); 00056 } 00057 } 00058 00059 /** 00060 * @ingroup msg 00061 * @anchor rt_send 00062 * @brief Send a message. 00063 * 00064 * rt_send sends the message @e msg to the task @e task. If the 00065 * receiver task is ready to get the message rt_send does not block 00066 * the sending task, but its execution can be preempted if the 00067 * receiving task has a higher priority. Otherwise the caller task is 00068 * blocked and queued up in priority order on the receive list of the sent 00069 * task. 00070 * 00071 * @param task is a pointer to a task structure. 00072 * 00073 * @param msg corresponds to the message that has to be sent. 00074 * 00075 * @return On success, the pointer to the task that received the message is 00076 * returned.<br> 00077 * 0 is returned if the caller is unblocked but the message has not 00078 * been sent, e.g. the task @e task was killed before receiving the 00079 * message.<br> 00080 * A special value is returned as described below in case of 00081 * a failure: 00082 * - @b 0xFFFF: @e task does not refer to a valid task. 00083 * 00084 * @note Since all the messaging functions return a task address 00085 * 0xFFFF could seem an inappropriate return value. However on all the 00086 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 00087 * RTAI task, so it is should be safe always. 00088 */ 00089 RT_TASK *rt_send(RT_TASK *task, unsigned long msg) 00090 { 00091 DECLARE_RT_CURRENT; 00092 unsigned long flags; 00093 00094 if (task->magic != RT_TASK_MAGIC) { 00095 return MSG_ERR; 00096 } 00097 00098 flags = rt_global_save_flags_and_cli(); 00099 ASSIGN_RT_CURRENT; 00100 if ((task->state & RT_SCHED_RECEIVE) && 00101 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00102 task->msg = msg; 00103 task->msg_queue.task = rt_current; 00104 task->ret_queue.task = NOTHING; 00105 rem_timed_task(task); 00106 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00107 enq_ready_task(task); 00108 RT_SCHEDULE(task, cpuid); 00109 } 00110 } else { 00111 rt_current->msg = msg; 00112 rt_current->msg_queue.task = task; 00113 enqueue_blocked(rt_current, &task->msg_queue, 0); 00114 rt_current->state |= RT_SCHED_SEND; 00115 rem_ready_current(rt_current); 00116 rt_schedule(); 00117 } 00118 if (rt_current->msg_queue.task != rt_current) { 00119 rt_current->msg_queue.task = rt_current; 00120 task = (RT_TASK *)0; 00121 } 00122 rt_global_restore_flags(flags); 00123 return task; 00124 } 00125 00126 00127 /** 00128 * @ingroup msg 00129 * @anchor rt_send_if 00130 * @brief Send a message, only if the calling task will not be blocked. 00131 * 00132 * rt_send_if sends the message @e msg to the task @e task if the 00133 * latter is ready to receive, so that the caller task is never 00134 * blocked, but its execution can be preempted if the receiving task is 00135 * ready to receive and has a higher priority. 00136 * 00137 * @param task is a pointer to a task structure. 00138 * 00139 * @param msg corresponds to the message that has to be sent. 00140 * 00141 * @return the pointer to the task @e task that received the message 00142 * is returned upon success.<br> 00143 * @e 0 is returned if the message has not been sent.<br> 00144 * A special value @e 0xFFFF is returned upon failure.<br><br> 00145 * The errors are described below: 00146 * - @b 0: the task @e task was not ready to receive the message. 00147 * - @b 0xFFFF: @e task does not refer to a valid task. 00148 * 00149 * @note Since all the messaging functions return a task address, 00150 * 0xFFFF could seem an inappropriate return value. However on all the 00151 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 00152 * RTAI task, so it is should be safe always. (FIXME) 00153 */ 00154 RT_TASK *rt_send_if(RT_TASK *task, unsigned long msg) 00155 { 00156 DECLARE_RT_CURRENT; 00157 unsigned long flags; 00158 00159 if (task->magic != RT_TASK_MAGIC) { 00160 return MSG_ERR; 00161 } 00162 00163 flags = rt_global_save_flags_and_cli(); 00164 ASSIGN_RT_CURRENT; 00165 if ((task->state & RT_SCHED_RECEIVE) && 00166 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00167 task->msg = msg; 00168 task->msg_queue.task = rt_current; 00169 task->ret_queue.task = NOTHING; 00170 rem_timed_task(task); 00171 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00172 enq_ready_task(task); 00173 RT_SCHEDULE(task, cpuid); 00174 } 00175 if (rt_current->msg_queue.task != rt_current) { 00176 rt_current->msg_queue.task = rt_current; 00177 task = (RT_TASK *)0; 00178 } 00179 } else { 00180 task = (RT_TASK *)0; 00181 } 00182 rt_global_restore_flags(flags); 00183 return task; 00184 } 00185 00186 00187 /** 00188 * @ingroup msg 00189 * @anchor rt_send_until 00190 * brief Send a message with an absolute timeout. 00191 * 00192 * rt_send_until sends the message @e msg to the task @e task. If the 00193 * receiver task is ready to get the message, this function does not 00194 * block the sending task, but its execution can be preempted if the 00195 * receiving task has a higher priority. Otherwise the caller task is 00196 * blocked and queued up in priority order on the receive list of the sent 00197 * task. 00198 * In this case the function returns if: 00199 * - the caller task is in the first place of the waiting queue and 00200 * the receiver gets the message and has a lower priority; 00201 * - a timeout occurs; 00202 * - an error occurs (e.g. the receiver task is killed). 00203 * 00204 * @param task is a pointer to a task structure. 00205 * 00206 * @param msg corresponds to the message that has to be sent. 00207 * 00208 * @param time is the absolute timeout value. 00209 * 00210 * @return the pointer to the task that received the message is 00211 * returned on success i.e. the message received before timeout 00212 * expiration.<br> 00213 * 0 is returned if the message has not been sent. 00214 * A special value is returned on other failure. The errors 00215 * are described below: 00216 * - @b 0: operation timed out, message was not delivered; 00217 * - @b 0xFFFF: @e task does not refer to a valid task. 00218 * 00219 * See also: @ref rt_send_timed(). 00220 * 00221 * @note Since all the messaging functions return a task address 00222 * 0xFFFF could seem an inappropriate return value. However on all 00223 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 00224 * any RTAI task, so it is should be safe always. 00225 */ 00226 RT_TASK *rt_send_until(RT_TASK *task, unsigned long msg, RTIME time) 00227 { 00228 DECLARE_RT_CURRENT; 00229 unsigned long flags; 00230 00231 if (task->magic != RT_TASK_MAGIC) { 00232 return MSG_ERR; 00233 } 00234 00235 flags = rt_global_save_flags_and_cli(); 00236 ASSIGN_RT_CURRENT; 00237 if ((task->state & RT_SCHED_RECEIVE) && 00238 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00239 task->msg = msg; 00240 task->msg_queue.task = rt_current; 00241 task->ret_queue.task = NOTHING; 00242 rem_timed_task(task); 00243 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00244 enq_ready_task(task); 00245 RT_SCHEDULE(task, cpuid); 00246 } 00247 } else { 00248 rt_current->msg_queue.task = task; 00249 if ((rt_current->resume_time = time) > rt_time_h) { 00250 rt_current->msg = msg; 00251 enqueue_blocked(rt_current, &task->msg_queue, 0); 00252 rt_current->state |= (RT_SCHED_SEND | RT_SCHED_DELAYED); 00253 rem_ready_current(rt_current); 00254 enq_timed_task(rt_current); 00255 rt_schedule(); 00256 } else { 00257 rt_current->queue.prev = rt_current->queue.next = &rt_current->queue; 00258 } 00259 } 00260 if (rt_current->msg_queue.task != rt_current) { 00261 if ((void *)rt_current->blocked_on > SOMETHING) { 00262 dequeue_blocked(rt_current); 00263 } 00264 rt_current->msg_queue.task = rt_current; 00265 task = (RT_TASK *)0; 00266 } 00267 rt_global_restore_flags(flags); 00268 return task; 00269 } 00270 00271 00272 /** 00273 * @ingroup msg 00274 * @anchor rt_send_timed 00275 * brief Send a message with a relative timeout. 00276 * 00277 * rt_send_timed sends the message @e msg to the task @e task. If the 00278 * receiver task is ready to get the message, this function does not 00279 * block the sending task, but its execution can be preempted if the 00280 * receiving task has a higher priority. Otherwise the caller task is 00281 * blocked and queued up in priority order on the receive list of the sent 00282 * task. 00283 * In this case the function returns if: 00284 * - the caller task is in the first place of the waiting queue and 00285 * the receiver gets the message and has a lower priority; 00286 * - a timeout occurs; 00287 * - an error occurs (e.g. the receiver task is killed). 00288 * 00289 * @param task is a pointer to a task structure. 00290 * 00291 * @param msg corresponds to the message that has to be sent. 00292 * 00293 * @param delay is the timeout relative to the current time. 00294 * 00295 * @return on success, the pointer to the task that received the 00296 * message i.e. the message received before timeout expiration.<br> 00297 * 0 if the message has not been sent.<br> 00298 * A special value on other failure. The errors 00299 * are described below: 00300 * - @b 0: operation timed out, message was not delivered; 00301 * - @b 0xFFFF: @e task does not refer to a valid task. 00302 * 00303 * See also: @ref rt_send_until(). 00304 * 00305 * @note Since all the messaging functions return a task address 00306 * 0xFFFF could seem an inappropriate return value. However on all 00307 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 00308 * any RTAI task, so it is should be safe always. (FIXME) 00309 */ 00310 00311 RT_TASK *rt_send_timed(RT_TASK *task, unsigned long msg, RTIME delay) 00312 { 00313 return rt_send_until(task, msg, get_time() + delay); 00314 } 00315 00316 /* ++++++++++++++++++++++++++++++++ RPCS +++++++++++++++++++++++++++++++++++ */ 00317 00318 /** 00319 * @ingroup rpc 00320 * @anchor rt_rpc 00321 * @brief Make a remote procedure call 00322 * 00323 * rt_rpc makes a Remote Procedure Call (RPC). rt_rpc is used for 00324 * synchronous inter task messaging as it sends the message @e msg to the 00325 * task @e task and blocks waiting until a return is 00326 * received from the called task. So the caller task is always blocked 00327 * and queued up in priority order while the receiver 00328 * inheredits the blocked sender priority if it is higher (lower in value) 00329 * than its. 00330 * The receiver task may get the message with any 00331 * rt_receive function. It can send an answer with @ref rt_return(). 00332 * 00333 * @param task pointer to a RT_TASK structure. 00334 * 00335 * @param msg message to send. 00336 * 00337 * @param reply points to a buffer provided by the caller were the 00338 * returned result message, any 4 bytes integer, is to be place. 00339 * 00340 * @return On success, task (the pointer to the task that received the 00341 * message) is returned. If the message has not been sent (e.g. the 00342 * task @e task was killed before receiving the message) 0 is returned. 00343 * On other failure, a special value is returned as described below: 00344 * - @b 0: the receiver task was killed before receiving the message. 00345 * - @b 0xFFFF: @e task does not refer to a valid task. 00346 * 00347 * See also: rt_receive_*, @ref rt_return(), @ref rt_isrpc(). 00348 * 00349 * @note Since all the messaging functions return a task address, 00350 * 0xFFFF could seem an inappropriate return value. However on 00351 * all the CPUs RTAI runs on, 0xFFFF is not an address that can 00352 * be used by any RTAI task, so it is should be always safe.<br> 00353 * The trio @ref rt_rpc(), @ref rt_receive(), @ref rt_return() 00354 * implement functions similar to its peers send-receive-replay 00355 * found in QNX, except that in RTAI only four bytes messages 00356 * contained in any integer can be exchanged. That's so because 00357 * it is more efficient and often enough. If you need to pass 00358 * arbitrarely long messages see the extended intertask messaging 00359 * functions. Moreover note also that we prefer 00360 * the idea of calling a function by using a message and then 00361 * wait for a return value since it is believed to give a better 00362 * idea of what is meant for synchronous message passing. For 00363 * a more truly QNX like way of inter task messaging use the support 00364 * of the upper cased functions: rt_Send-rt_Recieve-rt_Reply. 00365 */ 00366 RT_TASK *rt_rpc(RT_TASK *task, unsigned long to_do, void *result) 00367 { 00368 00369 DECLARE_RT_CURRENT; 00370 unsigned long flags; 00371 00372 if (task->magic != RT_TASK_MAGIC) { 00373 return MSG_ERR; 00374 } 00375 00376 flags = rt_global_save_flags_and_cli(); 00377 ASSIGN_RT_CURRENT; 00378 if ((task->state & RT_SCHED_RECEIVE) && 00379 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00380 rt_current->msg = task->msg = to_do; 00381 task->msg_queue.task = rt_current; 00382 task->ret_queue.task = NOTHING; 00383 rem_timed_task(task); 00384 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00385 enq_ready_task(task); 00386 } 00387 enqueue_blocked(rt_current, &task->ret_queue, 0); 00388 rt_current->state |= RT_SCHED_RETURN; 00389 } else { 00390 rt_current->msg = to_do; 00391 enqueue_blocked(rt_current, &task->msg_queue, 0); 00392 rt_current->state |= RT_SCHED_RPC; 00393 } 00394 task->owndres += RPCINC; 00395 pass_prio(task, rt_current); 00396 rem_ready_current(rt_current); 00397 rt_current->msg_queue.task = task; 00398 RT_SCHEDULE_BOTH(task, cpuid); 00399 if (rt_current->msg_queue.task == rt_current) { 00400 *(unsigned long *)result = rt_current->msg; 00401 } else { 00402 rt_current->msg_queue.task = rt_current; 00403 task = (RT_TASK *)0; 00404 } 00405 rt_global_restore_flags(flags); 00406 return task; 00407 } 00408 00409 00410 /** 00411 * @ingroup rpc 00412 * @anchor rt_rpc_if 00413 * @brief Make a remote procedure call, only if the calling task will 00414 * not be blocked. 00415 * 00416 * rt_rpc_if tries to make a Remote Procedure Call (RPC). If the 00417 * receiver task is ready to accept a message rt_rpc_if sends the 00418 * message @e msg then it always block until a return is received. In 00419 * this case the caller task is blocked and queued up 00420 * in priority order while the receiver 00421 * inheredits the blocked sender priority if it is higher (lower in value) 00422 * than its. 00423 * If the receiver is not ready 00424 * rt_rpc_if returns immediately. The receiver task may get the 00425 * message with any rt_receive function. It can send the answer with 00426 * @ref rt_return(). 00427 * 00428 * @param task pointer to a RT_TASK structure. 00429 * 00430 * @param msg message to send. 00431 * 00432 * @param reply points to a buffer provided by the caller. 00433 * 00434 * @return On success, task (the pointer to the task that received the 00435 * message) is returned. If message has not been sent, 0 is 00436 * returned. On other failure, a special value is returned as 00437 * described below: 00438 * - @b 0: The task @e task was not ready to receive the message or 00439 * it was killed before sending the reply. 00440 * - @b 0xFFFF: @e task does not refer to a valid task. 00441 * 00442 * See also: notes under @ref rt_rpc(). 00443 * 00444 * @note Since all the messaging functions return a task address, 00445 * 0xFFFF could seem an inappropriate return value. However on 00446 * all the CPUs RTAI runs on, 0xFFFF is not an address that can 00447 * be used by any RTAI task, so it is should be safe always. 00448 */ 00449 RT_TASK *rt_rpc_if(RT_TASK *task, unsigned long to_do, void *result) 00450 { 00451 DECLARE_RT_CURRENT; 00452 unsigned long flags; 00453 00454 if (task->magic != RT_TASK_MAGIC) { 00455 return MSG_ERR; 00456 } 00457 flags = rt_global_save_flags_and_cli(); 00458 ASSIGN_RT_CURRENT; 00459 if ((task->state & RT_SCHED_RECEIVE) && 00460 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00461 rt_current->msg = task->msg = to_do; 00462 task->msg_queue.task = rt_current; 00463 task->ret_queue.task = NOTHING; 00464 rem_timed_task(task); 00465 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00466 enq_ready_task(task); 00467 } 00468 enqueue_blocked(rt_current, &task->ret_queue, 0); 00469 rt_current->state |= RT_SCHED_RETURN; 00470 task->owndres += RPCINC; 00471 pass_prio(task, rt_current); 00472 rem_ready_current(rt_current); 00473 rt_current->msg_queue.task = task; 00474 RT_SCHEDULE_BOTH(task, cpuid); 00475 if (rt_current->msg_queue.task == rt_current) { 00476 *(unsigned long *)result = rt_current->msg; 00477 } else { 00478 rt_current->msg_queue.task = rt_current; 00479 task = (RT_TASK *)0; 00480 } 00481 } else { 00482 task = (RT_TASK *)0; 00483 } 00484 rt_global_restore_flags(flags); 00485 return task; 00486 } 00487 00488 00489 /** 00490 * @ingroup rpc 00491 * @anchor rt_rpc_until 00492 * @brief Make a remote procedure call with an absolute timeout. 00493 * 00494 * rt_rpc_until makes a Remote Procedure Call. It sends the message @e 00495 * msg to the task @e task then always waits until a return is 00496 * received or a timeout occurs. So the caller task is always blocked 00497 * and queued up in priority order while the receiver 00498 * inheredits the blocked sender priority if it is higher (lower in value) 00499 * than its. 00500 * The receiver task may get the message with any @ref 00501 * rt_receive() function. It can send the answer with @ref rt_return(). 00502 * 00503 * @param task pointer to a RT_TASK structure. 00504 * 00505 * @param msg message to send. 00506 * 00507 * @param reply points to a buffer provided by the caller. 00508 * 00509 * @param time is an absolute timeout value. 00510 * 00511 * @return On success, task (the pointer to the task that received the 00512 * message) is returned. If message has not been sent or no answer 00513 * arrived, 0 is returned. 00514 * On other failure, a special value is returned as described below: 00515 * - @b 0: The message could not be sent or the answer did not arrived 00516 * in time. 00517 * - @b 0xFFFF: @e task does not refer to a valid task. 00518 * 00519 * See also: @ref rt_receive(), @ref rt_return(), @ref rt_isrpc(). 00520 * 00521 * @note Since all the messaging functions return a task address, 0xFFFF 00522 * could seem an inappropriate return value. However on all the CPUs 00523 * RTAI runs on, 0xFFFF is not an address that can be used by any RTAI 00524 * task, so it is should be always safe.<br> 00525 * See also the notes under @ref rt_rpc(). 00526 */ 00527 RT_TASK *rt_rpc_until(RT_TASK *task, unsigned long to_do, void *result, RTIME time) 00528 { 00529 DECLARE_RT_CURRENT; 00530 unsigned long flags; 00531 00532 if (task->magic != RT_TASK_MAGIC) { 00533 return MSG_ERR; 00534 } 00535 00536 flags = rt_global_save_flags_and_cli(); 00537 ASSIGN_RT_CURRENT; 00538 if ((rt_current->resume_time = time) <= rt_time_h) { 00539 rt_global_restore_flags(flags); 00540 return (RT_TASK *)0; 00541 } 00542 if ((task->state & RT_SCHED_RECEIVE) && 00543 (!task->msg_queue.task || task->msg_queue.task == rt_current)) { 00544 rt_current->msg = task->msg = to_do; 00545 task->msg_queue.task = rt_current; 00546 task->ret_queue.task = NOTHING; 00547 rem_timed_task(task); 00548 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RECEIVE | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00549 enq_ready_task(task); 00550 } 00551 rt_current->state |= (RT_SCHED_RETURN | RT_SCHED_DELAYED); 00552 } else { 00553 rt_current->msg = to_do; 00554 rt_current->state |= (RT_SCHED_RPC | RT_SCHED_DELAYED); 00555 } 00556 enqueue_blocked(rt_current, &task->ret_queue, 0); 00557 task->owndres += RPCINC; 00558 pass_prio(task, rt_current); 00559 rem_ready_current(rt_current); 00560 rt_current->msg_queue.task = task; 00561 enq_timed_task(rt_current); 00562 RT_SCHEDULE_BOTH(task, cpuid); 00563 if (rt_current->msg_queue.task == rt_current) { 00564 *(unsigned long *)result = rt_current->msg; 00565 } else { 00566 if ((void *)rt_current->blocked_on > SOMETHING) { 00567 dequeue_blocked(rt_current); 00568 } 00569 reset_task_prio(task); 00570 rt_current->msg_queue.task = rt_current; 00571 task = (RT_TASK *)0; 00572 } 00573 rt_global_restore_flags(flags); 00574 return task; 00575 } 00576 00577 00578 /** 00579 * @ingroup rpc 00580 * @anchor rt_rpc_timed 00581 * @brief Make a remote procedure call with a relative timeout. 00582 * 00583 * rt_rpc_timed makes a Remote Procedure Call. It sends the message @e 00584 * msg to the task @e task then always waits until a return is 00585 * received or a timeout occurs. So the caller task is always blocked 00586 * and queued up in priority order while the receiver 00587 * inheredits the blocked sender priority if it is higher (lower in value) 00588 * than its. 00589 * The receiver task may get the message with any @ref 00590 * rt_receive() function. It can send the answer with @ref rt_return(). 00591 * 00592 * @param task pointer to a RT_TASK structure. 00593 * 00594 * @param msg message to send. 00595 * 00596 * @param reply points to a buffer provided by the caller. 00597 * 00598 * @param delay is a timeout relative to the current time. 00599 * 00600 * @return On success, task (the pointer to the task that received the 00601 * message) is returned. If message has not been sent or no answer 00602 * arrived, 0 is returned. 00603 * On other failure, a special value is returned as described below: 00604 * - @b 0: The message could not be sent or the answer did not arrived 00605 * in time. 00606 * - @b 0xFFFF: @e task does not refer to a valid task. 00607 * 00608 * See also: @ref rt_receive(), @ref rt_return(), @ref rt_isrpc(). 00609 * 00610 * @note Since all the messaging functions return a task address, 0xFFFF 00611 * could seem an inappropriate return value. However on all the CPUs 00612 * RTAI runs on, 0xFFFF is not an address that can be used by any RTAI 00613 * task, so it is should be always safe.<br> 00614 * See also the notes under @ref rt_rpc(). 00615 */ 00616 RT_TASK *rt_rpc_timed(RT_TASK *task, unsigned long to_do, void *result, RTIME delay) 00617 { 00618 return rt_rpc_until(task, to_do, result, get_time() + delay); 00619 } 00620 00621 /* ++++++++++++++++++++++++++++++ RPC_RETURN +++++++++++++++++++++++++++++++ */ 00622 00623 /** 00624 * @ingroup rpc 00625 * @anchor rt_isrpc 00626 * @brief Check if sender waits for reply or not. 00627 * 00628 * After receiving a message, by calling rt_isrpc a task can figure 00629 * out whether the sender task @e task is waiting for a reply or 00630 * not. Such an inquiry may be needed when a server task 00631 * must provide services to both rt_sends (FIXME) and rt_rtcs. 00632 * No answer is required if the message is sent by an @e rt_send function 00633 * or the sender called @ref rt_rpc_timed() or @ref rt_rpc_until() but it 00634 * is already timed out. 00635 * 00636 * @param task pointer to a task structure. 00637 * 00638 * @return If the task waits for a return reply, a nonzero value is returned. 00639 * Otherwise 0 is returned. 00640 * 00641 * @note rt_isrpc does not perform any check on pointer task. rt_isrpc 00642 * cannot figure out what RPC result the sender is waiting for.<br> 00643 * @ref rt_return() is intelligent enough to not send an answer to a 00644 * task which is not waiting for it. Therefore using rt_isrpc might not 00645 * be necessary. 00646 */ 00647 int rt_isrpc(RT_TASK *task) 00648 { 00649 return task->state & RT_SCHED_RETURN; 00650 } 00651 00652 00653 /** 00654 * @ingroup rpc 00655 * @anchor rt_return 00656 * @brief Return (sends) the result back to the task that made the 00657 * related remote procedure call. 00658 * 00659 * rt_return sends the result @e result to the task @e task. If the task 00660 * calling rt_rpc is not waiting the answer (i.e. killed or 00661 * timed out) this return message is silently discarded. The returning task 00662 * tries to release any previously inheredited priority inherediting the 00663 * highest priority of any rpcing task still waiting for 00664 * a return, but only if does not own a resource semaphore. In the latter 00665 * case it will keep the eighest inheredited priority till it has released 00666 * the resource ownership and no further message is waiting for a return. 00667 * That means that in the case priority inheritance is coming only 00668 * from rpced messages the task will return to its base priority when no 00669 * further message is queued for a return. Such a scheme automatically 00670 * sets a dynamic priority ceiling in the case priorities are 00671 * inheredited both from intertask messaging and resource semaphores 00672 * ownership. 00673 * 00674 * @return On success, task (the pointer to the task that is got the 00675 * reply) is returned. If the reply message has not been sent, 0 is 00676 * returned. On other failure, a special value is returned as 00677 * described below: 00678 * - @b 0: The reply message was not delivered. 00679 * - @b 0xFFFF: @e task does not refer to a valid task. 00680 * 00681 * @note Since all the messaging functions return a task address, 00682 * 0xFFFF could seem an inappropriate return value. However on all the 00683 * CPUs RTAI runs on, 0xFFFF is not an address that can be used by any 00684 * RTAI task, so it is should be always safe. 00685 * 00686 * See also: notes under @ref rt_rpc(). 00687 */ 00688 RT_TASK *rt_return(RT_TASK *task, unsigned long result) 00689 { 00690 DECLARE_RT_CURRENT; 00691 unsigned long flags; 00692 00693 if (task->magic != RT_TASK_MAGIC) { 00694 return MSG_ERR; 00695 } 00696 00697 flags = rt_global_save_flags_and_cli(); 00698 ASSIGN_RT_CURRENT; 00699 if ((task->state & RT_SCHED_RETURN) && task->msg_queue.task == rt_current) { 00700 int sched; 00701 dequeue_blocked(task); 00702 if (rt_current->owndres & RPCHLF) { 00703 rt_current->owndres -= RPCINC; 00704 } 00705 if (!rt_current->owndres) { 00706 sched = renq_current(rt_current, rt_current->base_priority); 00707 } else if (!(rt_current->owndres & SEMHLF)) { 00708 int priority; 00709 sched = renq_current(rt_current, rt_current->base_priority > (priority = ((rt_current->msg_queue.next)->task)->priority) ? priority : rt_current->base_priority); 00710 } else { 00711 sched = 0; 00712 } 00713 task->msg = result; 00714 task->msg_queue.task = task; 00715 rem_timed_task(task); 00716 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_RETURN | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00717 enq_ready_task(task); 00718 if (sched) { 00719 RT_SCHEDULE_BOTH(task, cpuid); 00720 } else { 00721 RT_SCHEDULE(task, cpuid); 00722 } 00723 } else if (sched) { 00724 rt_schedule(); 00725 } 00726 } else { 00727 task = (RT_TASK *)0; 00728 } 00729 rt_global_restore_flags(flags); 00730 return task; 00731 } 00732 00733 /* ++++++++++++++++++++++++++++++ RECEIVES +++++++++++++++++++++++++++++++++ */ 00734 00735 /** 00736 * @ingroup msg 00737 * @anchor rt_evdrp 00738 * @brief Eavedrop (spy) the content of a message. 00739 * 00740 * rt_evdrp spies the content of a message from the task specified by @e task 00741 * while leaving it on the queue. To actually receive the message any of the 00742 * rt_receive function must be used specifically. If task 00743 * is equal to 0, the caller eavdrops the first message of its receive queue, 00744 * if any. rt_evdrp never blocks. 00745 * 00746 * @param task is a pointer to a @e RT_TASK structure. 00747 * 00748 * @param msg points to any 4 bytes word buffer provided by the 00749 * caller. 00750 * 00751 * @return a pointer to the sender task is returned upon success.<br> 00752 * 0 is returned if no message is available. 00753 * A special value is returned on other failure. The errors 00754 * are described below: 00755 * - @b 0: the sender task was killed before sending the message; 00756 * - @b 0xFFFF: @e task does not refer to a valid task. 00757 * 00758 * @note Since all the messaging functions return a task address 00759 * 0xFFFF could seem an inappropriate return value. However on all 00760 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 00761 * any RTAI task, so it is should be always safe. 00762 */ 00763 RT_TASK *rt_evdrp(RT_TASK *task, void *msg) 00764 { 00765 DECLARE_RT_CURRENT; 00766 00767 if (task && task->magic != RT_TASK_MAGIC) { 00768 return MSG_ERR; 00769 } 00770 00771 ASSIGN_RT_CURRENT; 00772 if (!task) task = (rt_current->msg_queue.next)->task; 00773 if ((task->state & (RT_SCHED_SEND | RT_SCHED_RPC)) && task->msg_queue.task == rt_current) { 00774 *(unsigned long *)msg = task->msg; 00775 } else { 00776 task = (RT_TASK *)0; 00777 } 00778 return task; 00779 } 00780 00781 00782 /** 00783 * @ingroup msg 00784 * @anchor rt_receive 00785 * @brief Receive a message. 00786 * 00787 * rt_receive gets a message from the task specified by task. If task 00788 * is equal to 0, the caller accepts messages from any task. If there 00789 * is a pending message, rt_receive does not block but can be 00790 * preempted if the task that rt_sent the just received message has a 00791 * higher priority. The task will not block if it receives rpced messages 00792 * since rpcing tasks always waits for a returned message. Moreover it 00793 * inheredits the highest priority of any rpcing task waiting on the receive 00794 * queue. The receiving task will then recover its priority as explained in 00795 * rt_return. Otherwise the caller task is blocked waiting for any 00796 * message to be sent/rpced. 00797 * 00798 * @param task is a pointer to a @e RT_TASK structure. 00799 * 00800 * @param msg points to any 4 bytes word buffer provided by the 00801 * caller. 00802 * 00803 * @return a pointer to the sender task is returned upon success.<br> 00804 * 0 is returned if the caller is unblocked but no message has 00805 * been received (e.g. the task @e task was killed before sending the 00806 * message.)<br> 00807 * A special value is returned on other failure. The errors 00808 * are described below: 00809 * - @b 0: the sender task was killed before sending the message; 00810 * - @b 0xFFFF: @e task does not refer to a valid task. 00811 * 00812 * @note Since all the messaging functions return a task address 00813 * 0xFFFF could seem an inappropriate return value. However on all 00814 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 00815 * any RTAI task, so it is should be always safe. 00816 */ 00817 RT_TASK *rt_receive(RT_TASK *task, void *msg) 00818 { 00819 DECLARE_RT_CURRENT; 00820 unsigned long flags; 00821 00822 if (task && task->magic != RT_TASK_MAGIC) { 00823 return MSG_ERR; 00824 } 00825 00826 flags = rt_global_save_flags_and_cli(); 00827 ASSIGN_RT_CURRENT; 00828 if (!task) task = (rt_current->msg_queue.next)->task; 00829 if ((task->state & (RT_SCHED_SEND | RT_SCHED_RPC)) && task->msg_queue.task == rt_current) { 00830 dequeue_blocked(task); 00831 rem_timed_task(task); 00832 *(unsigned long *)msg = task->msg; 00833 rt_current->msg_queue.task = task; 00834 if (task->state & RT_SCHED_SEND) { 00835 task->msg_queue.task = task; 00836 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEND | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00837 enq_ready_task(task); 00838 RT_SCHEDULE(task, cpuid); 00839 } 00840 } else if (task->state & RT_SCHED_RPC) { 00841 enqueue_blocked(task, &rt_current->ret_queue, 0); 00842 task->state = (task->state & ~(RT_SCHED_RPC | RT_SCHED_DELAYED)) | RT_SCHED_RETURN; 00843 } 00844 } else { 00845 rt_current->ret_queue.task = SOMETHING; 00846 rt_current->state |= RT_SCHED_RECEIVE; 00847 rem_ready_current(rt_current); 00848 rt_current->msg_queue.task = task != rt_current ? task : (RT_TASK *)0; 00849 rt_schedule(); 00850 *(unsigned long *)msg = rt_current->msg; 00851 } 00852 if (rt_current->ret_queue.task) { 00853 rt_current->ret_queue.task = NOTHING; 00854 task = (RT_TASK *)0; 00855 } else { 00856 task = rt_current->msg_queue.task; 00857 } 00858 rt_current->msg_queue.task = rt_current; 00859 rt_global_restore_flags(flags); 00860 if (task && (struct proxy_t *)task->stack_bottom) { 00861 if (((struct proxy_t *)task->stack_bottom)->receiver == rt_current) { 00862 rt_return(task, 0); 00863 } 00864 } 00865 return task; 00866 } 00867 00868 00869 /** 00870 * @ingroup msg 00871 * @anchor rt_receive_if 00872 * @brief Receive a message, only if the calling task is not blocked. 00873 * 00874 * rt_receive_if tries to get a message from the task specified by 00875 * task. If task is equal to 0, the caller accepts messages from any 00876 * task. The caller task is never blocked but can be preempted if the 00877 * task that rt_sent the just received message has a 00878 * higher priority. The task will not block if it receives rpced messages 00879 * since rpcing tasks always waits for a returned message. Moreover it 00880 * inheredits the highest priority of any rpcing task waiting on the receive 00881 * queue. The receiving task will then recover its priority as explained in 00882 * rt_return. Otherwise the caller task is blocked waiting for any 00883 * message to be sent/rpced. 00884 * 00885 * @param task is a pointer to the task structure. 00886 * 00887 * @param msg points to a buffer provided by the caller. 00888 * 00889 * @return a pointer to the sender task is returned upon success.<br> 00890 * A special value is returned on other failure. The errors are 00891 * described below: 00892 * - @b 0: there was no message to receive; 00893 * - @b 0xFFFF: @e task does not refer to a valid task. 00894 * 00895 * Since all the messaging functions return a task address 0xFFFF 00896 * could seem an inappropriate return value. However on all the CPUs 00897 * RTAI runs on 0xFFFF is not an address that can be used by any RTAI 00898 * task, so it is should be always safe. 00899 */ 00900 RT_TASK *rt_receive_if(RT_TASK *task, void *msg) 00901 { 00902 DECLARE_RT_CURRENT; 00903 unsigned long flags; 00904 00905 if (task && task->magic != RT_TASK_MAGIC) { 00906 return MSG_ERR; 00907 } 00908 00909 flags = rt_global_save_flags_and_cli(); 00910 ASSIGN_RT_CURRENT; 00911 if (!task) task = (rt_current->msg_queue.next)->task; 00912 if ((task->state & (RT_SCHED_SEND | RT_SCHED_RPC)) && task->msg_queue.task == rt_current) { 00913 dequeue_blocked(task); 00914 rem_timed_task(task); 00915 *(unsigned long *)msg = task->msg; 00916 rt_current->msg_queue.task = task; 00917 if (task->state & RT_SCHED_SEND) { 00918 task->msg_queue.task = task; 00919 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEND | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 00920 enq_ready_task(task); 00921 RT_SCHEDULE(task, cpuid); 00922 } 00923 } else if (task->state & RT_SCHED_RPC) { 00924 enqueue_blocked(task, &rt_current->ret_queue, 0); 00925 task->state = (task->state & ~(RT_SCHED_RPC | RT_SCHED_DELAYED)) | RT_SCHED_RETURN; 00926 } 00927 if (rt_current->ret_queue.task) { 00928 rt_current->ret_queue.task = NOTHING; 00929 task = (RT_TASK *)0; 00930 } else { 00931 task = rt_current->msg_queue.task; 00932 } 00933 rt_current->msg_queue.task = rt_current; 00934 } else { 00935 task = (RT_TASK *)0; 00936 } 00937 rt_global_restore_flags(flags); 00938 if (task && (struct proxy_t *)task->stack_bottom) { 00939 if (((struct proxy_t *)task->stack_bottom)->receiver == rt_current) { 00940 rt_return(task, 0); 00941 } 00942 } 00943 return task; 00944 } 00945 00946 00947 /** 00948 * @ingroup msg 00949 * @anchor rt_receive_until 00950 * @brief Receive a message with an absolute timeout. 00951 * 00952 * rt_receive_until receives a message from the task specified by 00953 * task. If task is equal to 0, the caller accepts messages from any 00954 * task. If there is a pending message, rt_receive does not block but 00955 * but can be preempted if the 00956 * task that rt_sent the just received message has a 00957 * higher priority. The task will not block if it receives rpced messages 00958 * since rpcing tasks always waits for a returned message. Moreover it 00959 * inheredits the highest priority of any rpcing task waiting on the receive 00960 * queue. The receiving task will then recover its priority as explained in 00961 * rt_return. Otherwise the caller task is blocked waiting for any 00962 * message to be sent/rpced. 00963 * In this case these functions return if: 00964 * a sender sends a message and has a lower priority; 00965 * any rpced message is received; 00966 * - timeout occurs; 00967 * - an error occurs (e.g. the sender task is killed.) 00968 * 00969 * @param task is a pointer to the task structure. 00970 * 00971 * @param msg points to a buffer provided by the caller. 00972 * 00973 * @param time is an absolute timout value. 00974 * 00975 * @return On success, a pointer to the sender task is returned. 00976 * On other failure, a special value is returned. The errors 00977 * are described below: 00978 * - @b 0: there was no message to receive. 00979 * - @b 0xFFFF: @e task does not refer to a valid task. 00980 * 00981 * @note Since all the messaging functions return a task address 00982 * 0xFFFF could seem an inappropriate return value. However on all 00983 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 00984 * any RTAI task, so it is should be always safe. 00985 * 00986 * See also: @ref rt_receive_timed(). 00987 */ 00988 RT_TASK *rt_receive_until(RT_TASK *task, void *msg, RTIME time) 00989 { 00990 DECLARE_RT_CURRENT; 00991 unsigned long flags; 00992 00993 if (task && task->magic != RT_TASK_MAGIC) { 00994 return MSG_ERR; 00995 } 00996 00997 flags = rt_global_save_flags_and_cli(); 00998 ASSIGN_RT_CURRENT; 00999 if (!task) task = (rt_current->msg_queue.next)->task; 01000 if ((task->state & (RT_SCHED_SEND | RT_SCHED_RPC)) && task->msg_queue.task == rt_current) { 01001 dequeue_blocked(task); 01002 rem_timed_task(task); 01003 *(unsigned long *)msg = task->msg; 01004 rt_current->msg_queue.task = task; 01005 if (task->state & RT_SCHED_SEND) { 01006 task->msg_queue.task = task; 01007 if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_SEND | RT_SCHED_DELAYED)) == RT_SCHED_READY) { 01008 enq_ready_task(task); 01009 RT_SCHEDULE(task, cpuid); 01010 } 01011 } else if (task->state & RT_SCHED_RPC) { 01012 enqueue_blocked(task, &rt_current->ret_queue, 0); 01013 task->state = (task->state & ~(RT_SCHED_RPC | RT_SCHED_DELAYED)) | RT_SCHED_RETURN; 01014 } 01015 } else { 01016 rt_current->ret_queue.task = SOMETHING; 01017 if ((rt_current->resume_time = time) > rt_time_h) { 01018 rt_current->state |= (RT_SCHED_RECEIVE | RT_SCHED_DELAYED); 01019 rem_ready_current(rt_current); 01020 rt_current->msg_queue.task = task != rt_current ? task : (RT_TASK *)0; 01021 enq_timed_task(rt_current); 01022 rt_schedule(); 01023 *(unsigned long *)msg = rt_current->msg; 01024 } 01025 } 01026 if (rt_current->ret_queue.task) { 01027 rt_current->ret_queue.task = NOTHING; 01028 task = (RT_TASK *)0; 01029 } else { 01030 task = rt_current->msg_queue.task; 01031 } 01032 rt_current->msg_queue.task = rt_current; 01033 rt_global_restore_flags(flags); 01034 if (task && (struct proxy_t *)task->stack_bottom) { 01035 if (((struct proxy_t *)task->stack_bottom)->receiver == rt_current) { 01036 rt_return(task, 0); 01037 } 01038 } 01039 return task; 01040 } 01041 01042 01043 /** 01044 * @ingroup msg 01045 * @anchor rt_receive_timed 01046 * @brief Receive a message with a relative timeout. 01047 * 01048 * rt_receive_timed receives a message from the task specified by 01049 * task. If task is equal to 0, the caller accepts messages from any 01050 * task. 01051 * If there is a pending message, rt_receive does not block but 01052 * but can be preempted if the 01053 * task that rt_sent the just received message has a 01054 * higher priority. The task will not block if it receives rpced messages 01055 * since rpcing tasks always waits for a returned message. Moreover it 01056 * inheredits the highest priority of any rpcing task waiting on the receive 01057 * queue. The receiving task will then recover its priority as explained in 01058 * rt_return. Otherwise the caller task is blocked waiting for any 01059 * message to be sent/rpced. 01060 * In this case these functions return if: 01061 * a sender sends a message and has a lower priority; 01062 * any rpced message is received; 01063 * - timeout occurs; 01064 * - an error occurs (e.g. the sender task is killed.) 01065 * 01066 * @param task is a pointer to the task structure. 01067 * 01068 * @param msg points to a buffer provided by the caller. 01069 * 01070 * @param delay is a timeout relative to the current time. 01071 * 01072 * @return On success, a pointer to the sender task is returned. 01073 * On other failure, a special value is returned. The errors 01074 * are described below: 01075 * - @b 0: there was no message to receive. 01076 * - @b 0xFFFF: @e task does not refer to a valid task. 01077 * 01078 * @note Since all the messaging functions return a task address 01079 * 0xFFFF could seem an inappropriate return value. However on all 01080 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01081 * any RTAI task, so it is should be always safe. 01082 * 01083 * See also: @ref rt_receive_until(). 01084 */ 01085 RT_TASK *rt_receive_timed(RT_TASK *task, void *msg, RTIME delay) 01086 { 01087 return rt_receive_until(task, msg, get_time() + delay); 01088 } 01089 01090 /* ++++++++++++++++++++++++++ EXTENDED MESSAGES +++++++++++++++++++++++++++++++ 01091 COPYRIGHT (C) 2003 Pierre Cloutier (pcloutier@poseidoncontrols.com) 01092 Paolo Mantegazza (mantegazza@aero.polimi.it) 01093 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 01094 01095 #define SET_RPC_MCB() \ 01096 do { \ 01097 mcb.sbuf = smsg; \ 01098 mcb.sbytes = ssize; \ 01099 mcb.rbuf = rmsg; \ 01100 mcb.rbytes = rsize; \ 01101 } while (0) 01102 01103 /** 01104 * @ingroup rpcx 01105 * @anchor rt_rpcx 01106 * @brief Make an extended remote procedure call 01107 * 01108 * rt_rpcx makes an extended Remote Procedure Call (RPC). rt_rpcx is used for 01109 * synchronous inter task messaging. It sends an arbitrary @e smsg of size 01110 * @e ssize bytes to the task @e task then it always blocks waiting until a 01111 * message, of size @e rsize bytes at most, is returned in @e rmsg from the 01112 * called task. If the returned message is greater tha rsize it will be 01113 * truncated. So the caller task is always blocked on the receiver priority 01114 * queue while the receiver inheredits the blocked sender priority if it is 01115 * higher (lower in value) than its. The receiver task may get the message 01116 * with any rt_receivex function. It can send an answer with @ref rt_returnx(). 01117 * 01118 * @param task pointer to the RT_TASK structure of the receiver. 01119 * 01120 * @param smsg points to the message to be sent. 01121 * 01122 * @param rmsg points to the message to be returned by the receiver. 01123 * 01124 * @param ssize size of the message to be sent. 01125 * 01126 * @param rsize maximum allowed size for the message to be received. 01127 * 01128 * @return On success, task (the pointer to the task that received the 01129 * message) is returned. If the message has not been sent (e.g. the 01130 * task @e task was killed before receiving the message) 0 is returned. 01131 * 01132 * See also: rt_receivex_*, @ref rt_returnx(), @ref rt_isrpc(). 01133 * 01134 * @note The trio @ref rt_rpcx(), @ref rt_receivex(), @ref rt_returnx() 01135 * implements functions similar to its peers send-receive-reply 01136 * found in QNX. For a even greater compatibility see 01137 * rt_Send-rt_Receive-rt_Reply. 01138 */ 01139 RT_TASK *rt_rpcx(RT_TASK *task, void *smsg, void *rmsg, int ssize, int rsize) 01140 { 01141 if (task) { 01142 struct mcb_t mcb; 01143 SET_RPC_MCB(); 01144 return rt_rpc(task, (unsigned long)&mcb, &mcb.rbytes); 01145 } 01146 return 0; 01147 } 01148 01149 01150 /** 01151 * @ingroup rpcx 01152 * @anchor rt_rpcx_if 01153 * @brief Make an extended remote procedure call, only if the calling task 01154 * will not be blocked. 01155 * 01156 * rt_rpcx_if tries to make an extended Remote Procedure Call (RPC). If the 01157 * receiver task is ready to accept a message rt_rpcx_if sends the 01158 * message as it will be done by rt_rpcx. 01159 * If the receiver is not ready rt_rpcx_if returns immediately. The receiver 01160 * task may get the message with any rt_receivex function. It can send the 01161 * answer with * @ref rt_returnx(). 01162 * 01163 * @param task pointer to the RT_TASK structure of the receiver. 01164 * 01165 * @param smsg points to the message to be sent. 01166 * 01167 * @param rmsg points to the message to be returned by the receiver. 01168 * 01169 * @param ssize size of the message to be sent. 01170 * 01171 * @param rsize maximum allowed size for the message to be received. 01172 * 01173 * @return On success, task (the pointer to the task that received the 01174 * message) is returned. If message has not been sent, 0 is 01175 * returned. On other failure, a special value is returned as 01176 * described below: 01177 * - @b 0: The task @e task was not ready to receive the message or 01178 * it was killed before sending the reply. 01179 * - @b 0xFFFF: @e task does not refer to a valid task. 01180 * 01181 * See also: notes under @ref rt_rpc(). 01182 * 01183 * @note Since all the messaging functions return a task address, 01184 * 0xFFFF could seem an inappropriate return value. However on 01185 * all the CPUs RTAI runs on, 0xFFFF is not an address that can 01186 * be used by any RTAI task, so it is should be always safe. 01187 */ 01188 RT_TASK *rt_rpcx_if(RT_TASK *task, void *smsg, void *rmsg, int ssize, int rsize) 01189 { 01190 if (task) { 01191 struct mcb_t mcb; 01192 SET_RPC_MCB(); 01193 return rt_rpc_if(task, (unsigned long)&mcb, &mcb.rbytes); 01194 } 01195 return 0; 01196 } 01197 01198 01199 /** 01200 * @ingroup rpc 01201 * @anchor rt_rpcx_until 01202 * @brief Make an extended remote procedure call with absolute timeout. 01203 * 01204 * rt_rpcx_until makes an extended Remote Procedure Call (RPC). 01205 * It sends an arbitrary @e smsg of size @e ssize bytes to the task @e task 01206 * then it always blocks waiting until a message, of size @e rsize bytes at 01207 * most, is returned in @e rmsg from the called task or a timeout occurs. 01208 * If the returned message is greater tha rsize it will be truncated. 01209 * So the caller task is always blocked on the receiver priority queue while 01210 * the receiver inheredits the blocked sender priority if it is higher 01211 * (lower in value) than its. The receiver task may get the message with any 01212 * rt_receivex function. It can send an answer with @ref rt_returnx(). 01213 * 01214 * @param task pointer to the RT_TASK structure of the receiver. 01215 * 01216 * @param smsg points to the message to be sent. 01217 * 01218 * @param rmsg points to the message to be returned by the receiver. 01219 * 01220 * @param ssize size of the message to be sent. 01221 * 01222 * @param rsize maximum allowed size for the message to be received. 01223 * 01224 * @param time is an absolute timeout value. 01225 * 01226 * @return On success, task (the pointer to the task that received the 01227 * message) is returned. If message has not been sent or no answer 01228 * arrived, 0 is returned. 01229 * On other failure, a special value is returned as described below: 01230 * - @b 0: The message could not be sent or the answer did not arrived 01231 * in time. 01232 * - @b 0xFFFF: @e task does not refer to a valid task. 01233 * 01234 * See also: @ref rt_receive(), @ref rt_return(), @ref rt_isrpc(). 01235 * 01236 * @note Since all the messaging functions return a task address, 0xFFFF 01237 * could seem an inappropriate return value. However on all the CPUs 01238 * RTAI runs on, 0xFFFF is not an address that can be used by any RTAI 01239 * task, so it is should be always safe.<br> 01240 * See also the notes under @ref rt_rpc(). 01241 */ 01242 RT_TASK *rt_rpcx_until(RT_TASK *task, void *smsg, void *rmsg, int ssize, int rsize, RTIME time) 01243 { 01244 if (task) { 01245 struct mcb_t mcb; 01246 SET_RPC_MCB(); 01247 return rt_rpc_until(task, (unsigned long)&mcb, &mcb.rbytes, time); 01248 } 01249 return 0; 01250 } 01251 01252 01253 /** 01254 * @ingroup rpc 01255 * @anchor rt_rpcx_timed 01256 * @brief Make an extended remote procedure call with a relative timeout. 01257 * 01258 * rt_rpcx_timed makes an extended Remote Procedure Call (RPC). 01259 * It sends an arbitrary @e smsg of size @e ssize bytes to the task @e task 01260 * then it always blocks waiting until a message, of size @e rsize bytes at 01261 * most, is returned in @e rmsg from the called task or a timeout occurs. 01262 * If the returned message is greater tha rsize it will be truncated. 01263 * So the caller task is always blocked on the receiver priority queue while 01264 * the receiver inheredits the blocked sender priority if it is higher 01265 * (lower in value) than its. The receiver task may get the message with any 01266 * rt_receivex function. It can send an answer with @ref rt_returnx(). 01267 * 01268 * @param task pointer to the RT_TASK structure of the receiver. 01269 * 01270 * @param smsg points to the message to be sent. 01271 * 01272 * @param rmsg points to the message to be returned by the receiver. 01273 * 01274 * @param ssize size of the message to be sent. 01275 * 01276 * @param rsize maximum allowed size for the message to be received. 01277 * 01278 * @param delay is the relative timeout. 01279 * 01280 * @return On success, task (the pointer to the task that received the 01281 * message) is returned. If message has not been sent or no answer 01282 * arrived, 0 is returned. 01283 * On other failure, a special value is returned as described below: 01284 * - @b 0: The message could not be sent or the answer did not arrived 01285 * in time. 01286 * - @b 0xFFFF: @e task does not refer to a valid task. 01287 * 01288 * See also: @ref rt_receive(), @ref rt_return(), @ref rt_isrpc(). 01289 * 01290 * @note Since all the messaging functions return a task address, 0xFFFF 01291 * could seem an inappropriate return value. However on all the CPUs 01292 * RTAI runs on, 0xFFFF is not an address that can be used by any RTAI 01293 * task, so it is should be always safe.<br> 01294 * See also the notes under @ref rt_rpc(). 01295 */ 01296 RT_TASK *rt_rpcx_timed(RT_TASK *task, void *smsg, void *rmsg, int ssize, int rsize, RTIME delay) 01297 { 01298 if (task) { 01299 struct mcb_t mcb; 01300 SET_RPC_MCB(); 01301 return rt_rpc_timed(task, (unsigned long)&mcb, &mcb.rbytes, delay); 01302 } 01303 return 0; 01304 } 01305 01306 #define task_mcb (task->mcb) 01307 #define SET_SEND_MCB() \ 01308 do { \ 01309 task_mcb.sbuf = msg; \ 01310 task_mcb.sbytes = size; \ 01311 task_mcb.rbuf = 0; \ 01312 task_mcb.rbytes = 0; \ 01313 } while (0) 01314 01315 /** 01316 * @ingroup msg 01317 * @anchor rt_sendx 01318 * @brief Send an extended message. 01319 * 01320 * rt_sendx sends an arbitrary message @e msg of size @e size bytes to the task 01321 * @e task. If the 01322 * receiver task is ready to get the message rt_sendx does not block 01323 * the sending task, but its execution can be preempted if the 01324 * receiving task has a higher priority. Otherwise the caller task is 01325 * blocked and queued up in priority order on the receive list of the sent 01326 * task. 01327 * 01328 * @param task is a pointer to a task structure. 01329 * 01330 * @param msg points to the message to be sent. 01331 * 01332 * @param size size of the message to be sent. 01333 * 01334 * @return On success, the pointer to the task that received the message is 01335 * returned.<br> 01336 * 0 is returned if the caller is unblocked but the message has not 01337 * been sent, e.g. the task @e task was killed before receiving the 01338 * message.<br> 01339 * A special value is returned as described below in case of 01340 * a failure: 01341 * - @b 0xFFFF: @e task does not refer to a valid task. 01342 * 01343 * @note Since all the messaging functions return a task address 01344 * 0xFFFF could seem an inappropriate return value. However on all the 01345 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 01346 * RTAI task, so it is should be safe always. 01347 */ 01348 RT_TASK *rt_sendx(RT_TASK *task, void *msg, int size) 01349 { 01350 if (task) { 01351 SET_SEND_MCB(); 01352 return rt_send(task, (unsigned long)&task_mcb); 01353 } 01354 return 0; 01355 } 01356 01357 01358 /** 01359 * @ingroup msg 01360 * @anchor rt_sendx_if 01361 * @brief Send an extended message, only if the calling task will not be 01362 * blocked. 01363 * 01364 * rt_sendx_if sends an arbitrary message @e msg of size @e size bytes to the 01365 * task @e task if the latter is ready to receive. So the caller task in never 01366 * blocked but its execution can be preempted if the 01367 * receiving task has a higher priority. 01368 * 01369 * @param task is a pointer to a task structure. 01370 * 01371 * @param msg points to the message to be sent. 01372 * 01373 * @param size size of the message to be sent. 01374 * 01375 * @return On success, the pointer to the task that received the message is 01376 * returned.<br> 01377 * 0 is returned if the caller is unblocked but the message has not 01378 * been sent, e.g. the task @e task was killed before receiving the 01379 * message.<br> 01380 * A special value is returned as described below in case of 01381 * a failure: 01382 * - @b 0xFFFF: @e task does not refer to a valid task. 01383 * 01384 * @note Since all the messaging functions return a task address 01385 * 0xFFFF could seem an inappropriate return value. However on all the 01386 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 01387 * RTAI task, so it is should be safe always. 01388 */ 01389 RT_TASK *rt_sendx_if(RT_TASK *task, void *msg, int size) 01390 { 01391 if (task) { 01392 SET_SEND_MCB(); 01393 return rt_send_if(task, (unsigned long)&task_mcb); 01394 } 01395 return 0; 01396 } 01397 01398 01399 /** 01400 * @ingroup msg 01401 * @anchor rt_sendx_until 01402 * @brief Send an extended message with absolute timeout. 01403 * 01404 * rt_sendx_until sends an arbitrary message @e msg of size @e size bytes to 01405 * the task @e task. If the 01406 * receiver task is ready to get the message rt_sendx_until does not block 01407 * the sending task, but its execution can be preempted if the 01408 * receiving task has a higher priority. Otherwise the caller task is 01409 * blocked and queued up in priority order on the receive list of the sent 01410 * task. 01411 * In this case the function returns if: 01412 * - the caller task is in the first place of the waiting queue and 01413 * the receiver gets the message and has a lower priority; 01414 * - a timeout occurs; 01415 * - an error occurs (e.g. the receiver task is killed). 01416 * 01417 * @param task is a pointer to a task structure. 01418 * 01419 * @param msg points to the message to be sent. 01420 * 01421 * @param size size of the message to be sent. 01422 * 01423 * @param time is an absolute timeout value. 01424 * 01425 * @return On success, the pointer to the task that received the message is 01426 * returned.<br> 01427 * 0 is returned if the caller is unblocked but the message has not 01428 * been sent, e.g. the task @e task was killed before receiving the 01429 * message.<br> 01430 * A special value is returned as described below in case of 01431 * a failure: 01432 * - @b 0: operation timed out, message was not delivered; 01433 * - @b 0xFFFF: @e task does not refer to a valid task. 01434 * 01435 * @note Since all the messaging functions return a task address 01436 * 0xFFFF could seem an inappropriate return value. However on all the 01437 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 01438 * RTAI task, so it is should be safe always. 01439 */ 01440 RT_TASK *rt_sendx_until(RT_TASK *task, void *msg, int size, RTIME time) 01441 { 01442 if (task) { 01443 SET_SEND_MCB(); 01444 return rt_send_until(task, (unsigned long)&task_mcb, time); 01445 } 01446 return 0; 01447 } 01448 01449 01450 /** 01451 * @ingroup msg 01452 * @anchor rt_sendx_timed 01453 * @brief Send an extended message with relative timeout. 01454 * 01455 * rt_sendx_until sends an arbitrary message @e msg of size @e size bytes to 01456 * the task @e task. If the 01457 * receiver task is ready to get the message rt_sendx_until does not block 01458 * the sending task, but its execution can be preempted if the 01459 * receiving task has a higher priority. Otherwise the caller task is 01460 * blocked and queued up in priority order on the receive list of the sent 01461 * task. 01462 * In this case the function returns if: 01463 * - the caller task is in the first place of the waiting queue and 01464 * the receiver gets the message and has a lower priority; 01465 * - a timeout occurs; 01466 * - an error occurs (e.g. the receiver task is killed). 01467 * 01468 * @param task is a pointer to a task structure. 01469 * 01470 * @param msg points to the message to be sent. 01471 * 01472 * @param size size of the message to be sent. 01473 * 01474 * @param delay is r timeout elative to the current time. 01475 * 01476 * @return On success, the pointer to the task that received the message is 01477 * returned.<br> 01478 * 0 is returned if the caller is unblocked but the message has not 01479 * been sent, e.g. the task @e task was killed before receiving the 01480 * message.<br> 01481 * A special value is returned as described below in case of 01482 * a failure: 01483 * - @b 0: operation timed out, message was not delivered; 01484 * - @b 0xFFFF: @e task does not refer to a valid task. 01485 * 01486 * @note Since all the messaging functions return a task address 01487 * 0xFFFF could seem an inappropriate return value. However on all the 01488 * CPUs RTAI runs on 0xFFFF is not an address that can be used by any 01489 * RTAI task, so it is should be safe always. 01490 */ 01491 RT_TASK *rt_sendx_timed(RT_TASK *task, void *msg, int size, RTIME delay) 01492 { 01493 if (task) { 01494 SET_SEND_MCB(); 01495 return rt_send_timed(task, (unsigned long)&task_mcb, delay); 01496 } 01497 return 0; 01498 } 01499 01500 01501 /** 01502 * @ingroup rpc 01503 * @anchor rt_returnx 01504 * @brief Return (sends) an extended result back to the task that made the 01505 * related extended remote procedure call. 01506 * 01507 * rt_returns sends the result @e msg of size @e size to the task @e task. 01508 * If the task calling rt_rpcx is not waiting the answer (i.e. killed or 01509 * timed out) this return message is silently discarded. The returning task 01510 * tries to release any previously inheredited priority inherediting the 01511 * highest priority of any rpcing task still waiting for 01512 * a return, but only if does not own a resource semaphore. In the latter 01513 * case it will keep the eighest inheredited priority till it has released 01514 * the resource ownership and no further message is waiting for a return. 01515 * That means that in the case priority inheritance is coming only 01516 * from rpced messages the task will return to its base priority when no 01517 * further message is queued for a return. Such a scheme automatically 01518 * sets a dynamic priority ceiling in the case priorities are 01519 * inheredited both from intertask messaging and resource semaphores 01520 * ownership. 01521 * 01522 * @return On success, task (the pointer to the task that is got the 01523 * reply) is returned. If the reply message has not been sent, 0 is 01524 * returned. On other failure, a special value is returned as 01525 * described below: 01526 * - @b 0: The reply message was not delivered. 01527 * - @b 0xFFFF: @e task does not refer to a valid task. 01528 * 01529 * @note Since all the messaging functions return a task address, 01530 * 0xFFFF could seem an inappropriate return value. However on all the 01531 * CPUs RTAI runs on, 0xFFFF is not an address that can be used by any 01532 * RTAI task, so it is should be always safe. 01533 * 01534 * See also: notes under @ref rt_rpcx(). 01535 */ 01536 RT_TASK *rt_returnx(RT_TASK *task, void *msg, int size) 01537 { 01538 if (task) { 01539 struct mcb_t *mcb; 01540 if ((mcb = (struct mcb_t *)task->msg)->rbytes < size) { 01541 size = mcb->rbytes; 01542 } 01543 if (size) { 01544 memcpy(mcb->rbuf, msg, size); 01545 } 01546 return rt_return(task, 0); 01547 } 01548 return 0; 01549 } 01550 01551 #define DO_RCV_MSG() \ 01552 do { \ 01553 if ((*len = size <= mcb->sbytes ? size : mcb->sbytes)) { \ 01554 memcpy(msg, mcb->sbuf, *len); \ 01555 } \ 01556 } while (0) 01557 01558 01559 /** 01560 * @ingroup msg 01561 * @anchor rt_evdrpx 01562 * @brief Eavedrop (spy) the content of an extended message. 01563 * 01564 * rt_evdrpx spies the content of a message from the task specified by @e task 01565 * while leaving it on the queue. To actually receive the message any of the 01566 * rt_receivex function must be used specifically. If task 01567 * is equal to 0, the caller eavdrops the first message of its receive queue, 01568 * if any. rt_evdrpix never blocks. 01569 * 01570 * @param task is a pointer to a @e RT_TASK structure. 01571 * 01572 * @param msg points to the message to be eavedropped, without receive. 01573 * 01574 * @param size size of the message to be eavedropped. 01575 * 01576 * @param len is a pointer to an integer to be set to the actual len of the 01577 * eavedropped message. 01578 * 01579 * @return a pointer to the sender task is returned upon success.<br> 01580 * 0 is returned if no message is available. 01581 * A special value is returned on other failure. The errors 01582 * are described below: 01583 * - @b 0: the sender task was killed before sending the message; 01584 * - @b 0xFFFF: @e task does not refer to a valid task. 01585 * 01586 * @note Since all the messaging functions return a task address 01587 * 0xFFFF could seem an inappropriate return value. However on all 01588 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01589 * any RTAI task, so it is should be always safe. 01590 */ 01591 RT_TASK *rt_evdrpx(RT_TASK *task, void *msg, int size, int *len) 01592 { 01593 struct mcb_t *mcb; 01594 if ((task = rt_evdrp(task, (unsigned long *)&mcb))) { 01595 DO_RCV_MSG(); 01596 return task; 01597 } 01598 return 0; 01599 } 01600 01601 01602 /** 01603 * @ingroup msg 01604 * @anchor rt_receivex 01605 * @brief Receive an extended message. 01606 * 01607 * rt_receivex gets an extended message @a msg of size @a size from the task 01608 * specified by @e task task. If task 01609 * is equal to 0, the caller accepts messages from any task. If there 01610 * is a pending message, rt_receivex does not block but can be 01611 * preempted if the task that rt_sent the just received message has a 01612 * higher priority. The task will not block if it receives rpcxed messages 01613 * since rpcxing tasks always wait for a returned message. Moreover it 01614 * inheredits the highest priority of any rpcxing task waiting on the receive 01615 * queue. The receiving task will then recover its priority as explained in 01616 * rt_returnx. Otherwise the caller task is blocked waiting for any 01617 * message to be sentx/rpcxed. 01618 * 01619 * @param task is a pointer to a @e RT_TASK structure. 01620 * 01621 * @param msg points to the message to be eavedropped, without receive. 01622 * 01623 * @param size size of the message to be eavedropped. 01624 * 01625 * @param len is a pointer to an integer to be set to the actual len of the 01626 * eavedropped message. 01627 * 01628 * @return a pointer to the sender task is returned upon success.<br> 01629 * 0 is returned if the caller is unblocked but no message has 01630 * been received (e.g. the task @e task was killed before sending the 01631 * message.)<br> 01632 * A special value is returned on other failure. The errors 01633 * are described below: 01634 * - @b 0: the sender task was killed before sending the message; 01635 * - @b 0xFFFF: @e task does not refer to a valid task. 01636 * 01637 * @note Since all the messaging functions return a task address 01638 * 0xFFFF could seem an inappropriate return value. However on all 01639 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01640 * any RTAI task, so it is should be always safe. 01641 */ 01642 RT_TASK *rt_receivex(RT_TASK *task, void *msg, int size, int *len) 01643 { 01644 struct mcb_t *mcb; 01645 if ((task = rt_receive(task, (unsigned long *)&mcb))) { 01646 DO_RCV_MSG(); 01647 return task; 01648 } 01649 return 0; 01650 } 01651 01652 01653 /** 01654 * @ingroup msg 01655 * @anchor rt_receivex_if 01656 * @brief Receive an extended message, only if the calling task is not blocked. 01657 * 01658 * rt_receivex gets an extended message @a msg of size @a size from the task 01659 * specified by @e task task. If task 01660 * is equal to 0, the caller accepts messages from any task. The caller task 01661 * is never blocked but can be preempted if the task that rt_sentx the just 01662 * received message has a higher priority. 01663 * The task will not block if it receives rpcxed messages 01664 * since rpcxing tasks always wait for a returned message. Moreover it 01665 * inheredits the highest priority of any rpcxing task waiting on the receive 01666 * queue. The receiving task will then recover its priority as explained in 01667 * rt_returnx. Otherwise the caller task is blocked waiting for any 01668 * message to be sentx/rpcxed. 01669 * 01670 * @param task is a pointer to a @e RT_TASK structure. 01671 * 01672 * @param msg points to the message to be eavedropped, without receive. 01673 * 01674 * @param size size of the message to be eavedropped. 01675 * 01676 * @param len is a pointer to an integer to be set to the actual len of the 01677 * eavedropped message. 01678 * 01679 * @return a pointer to the sender task is returned upon success.<br> 01680 * 0 is returned if the caller is unblocked but no message has 01681 * been received (e.g. the task @e task was killed before sending the 01682 * message.)<br> 01683 * A special value is returned on other failure. The errors 01684 * are described below: 01685 * - @b 0: the sender task was killed before sending the message; 01686 * - @b 0xFFFF: @e task does not refer to a valid task. 01687 * 01688 * @note Since all the messaging functions return a task address 01689 * 0xFFFF could seem an inappropriate return value. However on all 01690 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01691 * any RTAI task, so it is should be always safe. 01692 */ 01693 RT_TASK *rt_receivex_if(RT_TASK *task, void *msg, int size, int *len) 01694 { 01695 struct mcb_t *mcb; 01696 if ((task = rt_receive_if(task, (unsigned long *)&mcb))) { 01697 DO_RCV_MSG(); 01698 return task; 01699 } 01700 return 0; 01701 } 01702 01703 01704 /** 01705 * @ingroup msg 01706 * @anchor rt_receivex_until 01707 * @brief Receive an extended message with an absolute timeout. 01708 * 01709 * rt_receivex_until gets an extended message @a msg of size @a size from the 01710 * task specified by @e task task. If task is equal to 0, the caller accepts 01711 * messages from any task. If there is a pending message, rt_receivex does not 01712 * block but can be preempted if the task that rt_sent the just received message 01713 * has a higher priority. The task will not block if it receives rpcxed messages 01714 * since rpcxing tasks always wait for a returned message. Moreover it 01715 * inheredits the highest priority of any rpcxing task waiting on the receive 01716 * queue. The receiving task will then recover its priority as explained in 01717 * rt_returnx. Otherwise the caller task is blocked waiting for any message to 01718 * be sentx/rpcxed. 01719 * 01720 * In this case these functions return if: 01721 * a sender sendxs a message and has a lower priority; 01722 * any rpcxed message is received; 01723 * - timeout occurs; 01724 * - an error occurs (e.g. the sender task is killed.) 01725 * @param task is a pointer to a @e RT_TASK structure. 01726 * 01727 * @param msg points to the message to be eavedropped, without receive. 01728 * 01729 * @param size size of the message to be eavedropped. 01730 * 01731 * @param len is a pointer to an integer to be set to the actual len of the 01732 * eavedropped message. 01733 * 01734 * @param time is an absolute timout value. 01735 * 01736 * @return a pointer to the sender task is returned upon success.<br> 01737 * 0 is returned if the caller is unblocked but no message has 01738 * been received (e.g. the task @e task was killed before sending the 01739 * message.)<br> 01740 * A special value is returned on other failure. The errors 01741 * are described below: 01742 * - @b 0: the sender task was killed before sending the message; 01743 * - @b 0xFFFF: @e task does not refer to a valid task. 01744 * 01745 * @note Since all the messaging functions return a task address 01746 * 0xFFFF could seem an inappropriate return value. However on all 01747 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01748 * any RTAI task, so it is should be always safe. 01749 */ 01750 RT_TASK *rt_receivex_until(RT_TASK *task, void *msg, int size, int *len, RTIME time) 01751 { 01752 struct mcb_t *mcb; 01753 if ((task = rt_receive_until(task, (unsigned long *)&mcb, time))) { 01754 DO_RCV_MSG(); 01755 return task; 01756 } 01757 return 0; 01758 } 01759 01760 01761 /** 01762 * @ingroup msg 01763 * @anchor rt_receivex_timed 01764 * @brief Receive an extended message with a relative timeout. 01765 * 01766 * rt_receivex_until gets an extended message @a msg of size @a size from the 01767 * task specified by @e task task. If task is equal to 0, the caller accepts 01768 * messages from any task. If there is a pending message, rt_receivex does not 01769 * block but can be preempted if the task that rt_sent the just received message 01770 * has a higher priority. The task will not block if it receives rpcxed messages 01771 * since rpcxing tasks always wait for a returned message. Moreover it 01772 * inheredits the highest priority of any rpcxing task waiting on the receive 01773 * queue. The receiving task will then recover its priority as explained in 01774 * rt_returnx. Otherwise the caller task is blocked waiting for any message to 01775 * be sentx/rpcxed. 01776 * 01777 * In this case these functions return if: 01778 * a sender sendxs a message and has a lower priority; 01779 * any rpcxed message is received; 01780 * - timeout occurs; 01781 * - an error occurs (e.g. the sender task is killed.) 01782 * @param task is a pointer to a @e RT_TASK structure. 01783 * 01784 * @param msg points to the message to be eavedropped, without receive. 01785 * 01786 * @param size size of the message to be eavedropped. 01787 * 01788 * @param len is a pointer to an integer to be set to the actual len of the 01789 * eavedropped message. 01790 * 01791 * @param delay is a timeout relative to the current time. 01792 * 01793 * @return a pointer to the sender task is returned upon success.<br> 01794 * 0 is returned if the caller is unblocked but no message has 01795 * been received (e.g. the task @e task was killed before sending the 01796 * message.)<br> 01797 * A special value is returned on other failure. The errors 01798 * are described below: 01799 * - @b 0: the sender task was killed before sending the message; 01800 * - @b 0xFFFF: @e task does not refer to a valid task. 01801 * 01802 * @note Since all the messaging functions return a task address 01803 * 0xFFFF could seem an inappropriate return value. However on all 01804 * the CPUs RTAI runs on 0xFFFF is not an address that can be used by 01805 * any RTAI task, so it is should be always safe. 01806 */ 01807 RT_TASK *rt_receivex_timed(RT_TASK *task, void *msg, int size, int *len, RTIME delay) 01808 { 01809 struct mcb_t *mcb; 01810 if ((task = rt_receive_timed(task, (unsigned long *)&mcb, delay))) { 01811 DO_RCV_MSG(); 01812 return task; 01813 } 01814 return 0; 01815 } 01816 01817 /* +++++++++++++++++++++++++++++++ PROXIES ++++++++++++++++++++++++++++++++++ */ 01818 01819 // What any proxy is supposed to do, raw RTAI implementation. 01820 static void proxy_task(RT_TASK *me) 01821 { 01822 struct proxy_t *my; 01823 unsigned long ret; 01824 01825 my = (struct proxy_t *)me->stack_bottom; 01826 while (1) { 01827 while (my->nmsgs) { 01828 atomic_dec((atomic_t *)&my->nmsgs); 01829 rt_rpc(my->receiver, *((unsigned long *)my->msg), &ret); 01830 } 01831 rt_task_suspend(me); 01832 } 01833 } 01834 01835 // Create a raw proxy agent task. 01836 RT_TASK *__rt_proxy_attach(void (*agent)(long), RT_TASK *task, void *msg, int nbytes, int priority) 01837 { 01838 RT_TASK *proxy, *rt_current; 01839 struct proxy_t *my; 01840 01841 rt_current = _rt_whoami(); 01842 if (!task) { 01843 task = rt_current; 01844 } 01845 01846 if (task->magic != RT_TASK_MAGIC) { 01847 return 0; 01848 } 01849 01850 if (!(proxy = rt_malloc(sizeof(RT_TASK)))) { 01851 return 0; 01852 } 01853 01854 if (priority == -1 && (priority = rt_current->base_priority) == RT_SCHED_LINUX_PRIORITY) { 01855 priority = RT_SCHED_LOWEST_PRIORITY; 01856 } 01857 if (rt_kthread_init(proxy, agent, (long)proxy, PROXY_MIN_STACK_SIZE + nbytes + sizeof(struct proxy_t), priority, 0, 0)) { 01858 rt_free(proxy); 01859 return 0; 01860 } 01861 01862 my = (struct proxy_t *)(proxy->stack_bottom); 01863 my->receiver = task ; 01864 my->msg = ((char *)(proxy->stack_bottom)) + sizeof(struct proxy_t); 01865 my->nmsgs = 0; 01866 my->nbytes = nbytes; 01867 if (msg && nbytes) { 01868 memcpy(my->msg, msg, nbytes); 01869 } 01870 01871 // agent is at *(proxy->stack + 2) 01872 return proxy; 01873 } 01874 01875 // Create a raw proxy task. 01876 RT_TASK *rt_proxy_attach(RT_TASK *task, void *msg, int nbytes, int prio) 01877 { 01878 return __rt_proxy_attach((void *)proxy_task, task, msg, nbytes, prio); 01879 } 01880 01881 // Delete a proxy task (a simplified specific rt_task_delete). 01882 // Note: a self delete will not do the rt_free() call. 01883 int rt_proxy_detach(RT_TASK *proxy) 01884 { 01885 if (!rt_task_delete(proxy)) { 01886 rt_free(proxy); 01887 return 0; 01888 } 01889 return -EINVAL; 01890 } 01891 01892 // Trigger a proxy. 01893 RT_TASK *rt_trigger(RT_TASK *proxy) 01894 { 01895 struct proxy_t *his; 01896 01897 his = (struct proxy_t *)(proxy->stack_bottom); 01898 if (his && proxy->magic == RT_TASK_MAGIC) { 01899 atomic_inc((atomic_t *)&his->nmsgs); 01900 rt_task_resume(proxy); 01901 return his->receiver; 01902 } 01903 return (RT_TASK *)0; 01904 } 01905 01906 #if 1 //def CONFIG_RTAI_INTERNAL_LXRT_SUPPORT 01907 01908 /* ++++++++++++ ANOTHER API SET FOR EXTENDED INTERTASK MESSAGES +++++++++++++++ 01909 COPYRIGHT (C) 2003 Pierre Cloutier (pcloutier@poseidoncontrols.com) 01910 Paolo Mantegazza (mantegazza@aero.polimi.it) 01911 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 01912 01913 #include <asm/uaccess.h> 01914 01915 #include "rtai_registry.h" 01916 #include "rtai_msg.h" 01917 01918 int rt_Send(pid_t pid, void *smsg, void *rmsg, size_t ssize, size_t rsize) 01919 { 01920 RT_TASK *task; 01921 if ((task = pid2rttask(pid))) { 01922 MSGCB cb; 01923 RT_TASK *replier; 01924 unsigned long replylen; 01925 cb.cmd = SYNCMSG; 01926 cb.sbuf = smsg; 01927 cb.sbytes = ssize; 01928 cb.rbuf = rmsg; 01929 cb.rbytes = rsize; 01930 if (!(replier = rt_rpc(task, (unsigned long)&cb, &replylen))) { 01931 return -EINVAL; 01932 } else if (replier != task) { 01933 return -ESRCH; 01934 } 01935 return replylen ; 01936 } 01937 return -ESRCH; 01938 } 01939 01940 pid_t rt_Receive(pid_t pid, void *msg, size_t maxsize, size_t *msglen) 01941 { 01942 RT_TASK *task; 01943 MSGCB *cb; 01944 if ((task = rt_receive(pid ? pid2rttask(pid) : 0, (void *)&cb))) { 01945 if ((pid = rttask2pid(task))) { 01946 *msglen = maxsize <= cb->sbytes ? maxsize : cb->sbytes; 01947 if (*msglen) { 01948 memcpy(msg, cb->sbuf, *msglen); 01949 } 01950 return pid; 01951 } 01952 return -ESRCH; 01953 } 01954 return -EINVAL; 01955 } 01956 01957 pid_t rt_Creceive(pid_t pid, void *msg, size_t maxsize, size_t *msglen, RTIME delay) 01958 { 01959 RT_TASK *task; 01960 MSGCB *cb; 01961 task = pid ? pid2rttask(pid) : 0; 01962 if (delay) { 01963 task = rt_receive_timed(task, (void *)&cb, delay); 01964 } else { 01965 task = rt_receive_if(task, (void *)&cb); 01966 } 01967 if (task) { 01968 if ((pid = rttask2pid(task))) { 01969 *msglen = maxsize <= cb->sbytes ? maxsize : cb->sbytes; 01970 if (*msglen) { 01971 memcpy(msg, cb->sbuf, *msglen); 01972 } 01973 return pid; 01974 } 01975 return 0; 01976 } 01977 return 0; 01978 } 01979 01980 int rt_Reply(pid_t pid, void *msg, size_t size) 01981 { 01982 RT_TASK *task; 01983 if ((task = pid2rttask(pid))) { 01984 MSGCB *cb; 01985 if ((cb = (MSGCB *)task->msg)->cmd == SYNCMSG) { 01986 unsigned long retlen; 01987 RT_TASK *retask; 01988 if ((retlen = size <= cb->rbytes ? size : cb->rbytes)) { 01989 memcpy(cb->rbuf, msg, retlen); 01990 } 01991 if (!(retask = rt_return(task, retlen))) { 01992 return -EINVAL; 01993 } else if (retask != task) { 01994 return -ESRCH; 01995 } 01996 return 0; 01997 } 01998 return -EPERM; 01999 } 02000 return -ESRCH; 02001 } 02002 02003 static void Proxy_Task(RT_TASK *me) 02004 { 02005 struct proxy_t *my; 02006 MSGCB cb; 02007 unsigned long replylen; 02008 my = (struct proxy_t *)me->stack_bottom; 02009 cb.cmd = PROXY; 02010 cb.sbuf = my->msg; 02011 cb.sbytes = my->nbytes; 02012 cb.rbuf = &replylen; 02013 cb.rbytes = sizeof(replylen); 02014 while(1) { 02015 while (my->nmsgs) { 02016 atomic_dec((atomic_t *)&my->nmsgs); 02017 rt_rpc(my->receiver, (unsigned long)(&cb), &replylen); 02018 } 02019 rt_task_suspend(me); 02020 } 02021 } 02022 02023 pid_t rt_Proxy_attach(pid_t pid, void *msg, int nbytes, int prio) 02024 { 02025 RT_TASK *task; 02026 return (task = __rt_proxy_attach((void *)Proxy_Task, pid ? pid2rttask(pid) : 0, msg, nbytes, prio)) ? (task->lnxtsk)->pid : -ENOMEM; 02027 } 02028 02029 int rt_Proxy_detach(pid_t pid) 02030 { 02031 RT_TASK *proxy; 02032 if (!rt_task_delete(proxy = pid2rttask(pid))) { 02033 rt_free(proxy); 02034 return 0; 02035 } 02036 return -EINVAL; 02037 } 02038 02039 pid_t rt_Trigger(pid_t pid) 02040 { 02041 RT_TASK *proxy; 02042 struct proxy_t *his; 02043 if ((proxy = pid2rttask(pid))) { 02044 his = (struct proxy_t *)(proxy->stack_bottom); 02045 if (his && proxy->magic == RT_TASK_MAGIC) { 02046 atomic_inc((atomic_t *)&his->nmsgs); 02047 rt_task_resume(proxy); 02048 return rttask2pid(his->receiver); 02049 } 02050 return -EINVAL; 02051 } 02052 return -ESRCH; 02053 } 02054 02055 02056 pid_t rt_Name_attach(const char *argname) 02057 { 02058 RT_TASK *task; 02059 task = current->rtai_tskext(TSKEXT0) ? (RT_TASK *)current->rtai_tskext(TSKEXT0) : _rt_whoami(); 02060 if (current->comm[0] != 'U' && current->comm[1] != ':') { 02061 strncpy_from_user(task->task_name, argname, RTAI_MAX_NAME_LENGTH); 02062 } else { 02063 strncpy(task->task_name, argname, RTAI_MAX_NAME_LENGTH); 02064 } 02065 task->task_name[RTAI_MAX_NAME_LENGTH - 1] = 0; 02066 return strnlen(task->task_name, RTAI_MAX_NAME_LENGTH) > (RTAI_MAX_NAME_LENGTH - 1) ? -EINVAL : task->lnxtsk ? ((struct task_struct *)current->rtai_tskext(TSKEXT1))->pid : (long)task; 02067 } 02068 02069 pid_t rt_Name_locate(const char *arghost, const char *argname) 02070 { 02071 extern RT_TASK rt_smp_linux_task[]; 02072 int cpuid; 02073 RT_TASK *task; 02074 for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) { 02075 task = &rt_smp_linux_task[cpuid]; 02076 while ((task = task->next)) { 02077 if (!strncmp(argname, task->task_name, RTAI_MAX_NAME_LENGTH - 1)) { 02078 return (struct task_struct *)(task->lnxtsk) ? ((struct task_struct *)(task->lnxtsk)->rtai_tskext(TSKEXT1))->pid : (long)task; 02079 02080 } 02081 } 02082 } 02083 return strlen(argname) <= 6 && (task = rt_get_adr(nam2num(argname))) ? rttask2pid(task) : 0; 02084 } 02085 02086 int rt_Name_detach(pid_t pid) 02087 { 02088 if (pid <= PID_MAX_LIMIT) { 02089 if (pid != ((struct task_struct *)current->rtai_tskext(TSKEXT1))->pid ) { 02090 return -EINVAL; 02091 } 02092 ((RT_TASK *)current->rtai_tskext(TSKEXT0))->task_name[0] = 0; 02093 } else { 02094 ((RT_TASK *)(long)pid)->task_name[0] = 0; 02095 } 02096 return 0; 02097 } 02098 02099 #endif /* CONFIG_RTAI_INTERNAL_LXRT_SUPPORT */ 02100 02101 /* +++++++++++++++++++++ INTERTASK MESSAGES ENTRIES +++++++++++++++++++++++++ */ 02102 02103 struct rt_native_fun_entry rt_msg_entries[] = { 02104 { { 1, rt_send }, SENDMSG }, 02105 { { 1, rt_send_if }, SEND_IF }, 02106 { { 1, rt_send_until }, SEND_UNTIL }, 02107 { { 1, rt_send_timed }, SEND_TIMED }, 02108 { { UW1(2, 0), rt_receive }, RECEIVEMSG }, 02109 { { UW1(2, 0), rt_receive_if }, RECEIVE_IF }, 02110 { { UW1(2, 0), rt_receive_until }, RECEIVE_UNTIL }, 02111 { { UW1(2, 0), rt_receive_timed }, RECEIVE_TIMED }, 02112 { { UW1(3, 0), rt_rpc }, RPCMSG }, 02113 { { UW1(3, 0), rt_rpc_if }, RPC_IF }, 02114 { { UW1(3, 0), rt_rpc_until }, RPC_UNTIL }, 02115 { { UW1(3, 0), rt_rpc_timed }, RPC_TIMED }, 02116 { { UW1(2, 0), rt_evdrp }, EVDRP }, 02117 { { 0, rt_isrpc }, ISRPC }, 02118 { { 1, rt_return }, RETURNMSG }, 02119 { { UR1(2, 4) | UW1(3, 5), rt_rpcx }, RPCX }, 02120 { { UR1(2, 4) | UW1(3, 5), rt_rpcx_if }, RPCX_IF }, 02121 { { UR1(2, 4) | UW1(3, 5), rt_rpcx_until }, RPCX_UNTIL }, 02122 { { UR1(2, 4) | UW1(3, 5), rt_rpcx_timed }, RPCX_TIMED }, 02123 { { UR1(2, 3), rt_sendx }, SENDX }, 02124 { { UR1(2, 3), rt_sendx_if }, SENDX_IF }, 02125 { { UR1(2, 3), rt_sendx_until }, SENDX_UNTIL }, 02126 { { UR1(2, 3), rt_sendx_timed }, SENDX_TIMED }, 02127 { { UR1(2, 3), rt_returnx }, RETURNX }, 02128 { { UW1(2, 3) | UW2(4, 0), rt_receivex }, RECEIVEX }, 02129 { { UW1(2, 3) | UW2(4, 0), rt_receivex_if }, RECEIVEX_IF }, 02130 { { UW1(2, 3) | UW2(4, 0), rt_receivex_until }, RECEIVEX_UNTIL }, 02131 { { UW1(2, 3) | UW2(4, 0), rt_receivex_timed }, RECEIVEX_TIMED }, 02132 { { UW1(2, 3) | UW2(4, 0), rt_evdrpx }, EVDRPX }, 02133 { { UR1(2, 3), rt_proxy_attach }, PROXY_ATTACH }, 02134 { { 1, rt_proxy_detach }, PROXY_DETACH }, 02135 { { 1, rt_trigger }, PROXY_TRIGGER }, 02136 #if 1 //def CONFIG_RTAI_INTERNAL_LXRT_SUPPORT 02137 { { UR1(2, 4) | UW1(3, 5), rt_Send }, RT_SEND }, 02138 { { UW1(2, 3) | UW2(4, 0), rt_Receive }, RT_RECEIVE }, 02139 { { UW1(2, 3) | UW2(4, 0), rt_Creceive }, RT_CRECEIVE }, 02140 { { UR1(2, 3), rt_Reply }, RT_REPLY }, 02141 { { UR1(2, 3), rt_Proxy_attach }, RT_PROXY_ATTACH }, 02142 { { 1, rt_Proxy_detach }, RT_PROXY_DETACH }, 02143 { { 1, rt_Trigger }, RT_TRIGGER }, 02144 { { 1, rt_Name_attach }, RT_NAME_ATTACH }, 02145 { { 1, rt_Name_detach }, RT_NAME_DETACH }, 02146 { { 0, rt_Name_locate }, RT_NAME_LOCATE }, 02147 #endif /* CONFIG_RTAI_INTERNAL_LXRT_SUPPORT */ 02148 { { 0, 0 }, 000 } 02149 }; 02150 02151 int __rtai_msg_init (void) 02152 { 02153 return set_rt_fun_entries(rt_msg_entries); 02154 } 02155 02156 void __rtai_msg_exit (void) 02157 { 02158 reset_rt_fun_entries(rt_msg_entries); 02159 } 02160 02161 #ifndef CONFIG_RTAI_MSG_BUILTIN 02162 module_init(__rtai_msg_init); 02163 module_exit(__rtai_msg_exit); 02164 #endif /* !CONFIG_RTAI_MSG_BUILTIN */ 02165 02166 #ifdef CONFIG_KBUILD 02167 EXPORT_SYMBOL(rt_send); 02168 EXPORT_SYMBOL(rt_send_if); 02169 EXPORT_SYMBOL(rt_send_until); 02170 EXPORT_SYMBOL(rt_send_timed); 02171 EXPORT_SYMBOL(rt_rpc); 02172 EXPORT_SYMBOL(rt_rpc_if); 02173 EXPORT_SYMBOL(rt_rpc_until); 02174 EXPORT_SYMBOL(rt_rpc_timed); 02175 EXPORT_SYMBOL(rt_isrpc); 02176 EXPORT_SYMBOL(rt_return); 02177 EXPORT_SYMBOL(rt_evdrp); 02178 EXPORT_SYMBOL(rt_receive); 02179 EXPORT_SYMBOL(rt_receive_if); 02180 EXPORT_SYMBOL(rt_receive_until); 02181 EXPORT_SYMBOL(rt_receive_timed); 02182 EXPORT_SYMBOL(rt_rpcx); 02183 EXPORT_SYMBOL(rt_rpcx_if); 02184 EXPORT_SYMBOL(rt_rpcx_until); 02185 EXPORT_SYMBOL(rt_rpcx_timed); 02186 EXPORT_SYMBOL(rt_sendx); 02187 EXPORT_SYMBOL(rt_sendx_if); 02188 EXPORT_SYMBOL(rt_sendx_until); 02189 EXPORT_SYMBOL(rt_sendx_timed); 02190 EXPORT_SYMBOL(rt_returnx); 02191 EXPORT_SYMBOL(rt_evdrpx); 02192 EXPORT_SYMBOL(rt_receivex); 02193 EXPORT_SYMBOL(rt_receivex_if); 02194 EXPORT_SYMBOL(rt_receivex_until); 02195 EXPORT_SYMBOL(rt_receivex_timed); 02196 02197 EXPORT_SYMBOL(__rt_proxy_attach); 02198 EXPORT_SYMBOL(rt_proxy_attach); 02199 EXPORT_SYMBOL(rt_proxy_detach); 02200 EXPORT_SYMBOL(rt_trigger); 02201 02202 EXPORT_SYMBOL(rt_Send); 02203 EXPORT_SYMBOL(rt_Receive); 02204 EXPORT_SYMBOL(rt_Creceive); 02205 EXPORT_SYMBOL(rt_Reply); 02206 EXPORT_SYMBOL(rt_Proxy_attach); 02207 EXPORT_SYMBOL(rt_Proxy_detach); 02208 EXPORT_SYMBOL(rt_Trigger); 02209 EXPORT_SYMBOL(rt_Name_attach); 02210 EXPORT_SYMBOL(rt_Name_locate); 02211 EXPORT_SYMBOL(rt_Name_detach); 02212 #endif /* CONFIG_KBUILD */

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