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

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