base/ipc/mbx/mbx.c

Go to the documentation of this file.
00001 /** 
00002  * @file
00003  * Mailbox functions.
00004  * @author Paolo Mantegazza
00005  *
00006  * @note Copyright (C) 1999-2006 Paolo Mantegazza
00007  * <mantegazza@aero.polimi.it> 
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of the
00012  * License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00022  *
00023  * @ingroup mbx
00024  */
00025 
00026 /**
00027  * @ingroup sched
00028  * @defgroup mbx Mailbox functions
00029  *@{*/
00030 
00031 #include <linux/kernel.h>
00032 #include <linux/module.h>
00033 
00034 #include <asm/uaccess.h>
00035 
00036 #include <rtai_schedcore.h>
00037 #include <rtai_prinher.h>
00038 
00039 MODULE_LICENSE("GPL");
00040 
00041 /* +++++++++++++++++++++++++++++ MAIL BOXES ++++++++++++++++++++++++++++++++ */
00042 
00043 #define _mbx_signal(mbx, blckdon) \
00044 do { \
00045     unsigned long flags; \
00046     RT_TASK *task; \
00047     flags = rt_global_save_flags_and_cli(); \
00048     if ((task = mbx->waiting_task)) { \
00049         rem_timed_task(task); \
00050         task->blocked_on  = blckdon; \
00051         mbx->waiting_task = NULL; \
00052         if (task->state != RT_SCHED_READY && (task->state &= ~(RT_SCHED_MBXSUSP | RT_SCHED_DELAYED)) == RT_SCHED_READY) { \
00053             enq_ready_task(task); \
00054             RT_SCHEDULE(task, rtai_cpuid()); \
00055         } \
00056     } \
00057     rt_global_restore_flags(flags); \
00058 } while (0)
00059 
00060 static void mbx_delete_signal(MBX *mbx)
00061 {
00062     _mbx_signal(mbx, RTP_OBJREM);
00063 }
00064 
00065 static void mbx_signal(MBX *mbx)
00066 {
00067     _mbx_signal(mbx, NULL);
00068 }
00069 
00070 static int mbx_wait(MBX *mbx, int *fravbs, RT_TASK *rt_current)
00071 {
00072     unsigned long flags;
00073 
00074     flags = rt_global_save_flags_and_cli();
00075     if (!(*fravbs)) {
00076         unsigned long retval;
00077         rt_current->state |= RT_SCHED_MBXSUSP;
00078         rem_ready_current(rt_current);
00079         rt_current->blocked_on = (void *)mbx;
00080         mbx->waiting_task = rt_current;
00081         rt_schedule();
00082         if (unlikely(retval = (unsigned long)rt_current->blocked_on)) {
00083             mbx->waiting_task = NULL;
00084             rt_global_restore_flags(flags);
00085             return retval;
00086         }
00087     }
00088     rt_global_restore_flags(flags);
00089     return 0;
00090 }
00091 
00092 static int mbx_wait_until(MBX *mbx, int *fravbs, RTIME time, RT_TASK *rt_current)
00093 {
00094     unsigned long flags;
00095 
00096     flags = rt_global_save_flags_and_cli();
00097     if (!(*fravbs)) {
00098         void *retp;
00099         rt_current->blocked_on = (void *)mbx;
00100         mbx->waiting_task = rt_current;
00101         if ((rt_current->resume_time = time) > rt_smp_time_h[rtai_cpuid()]) {
00102             rt_current->state |= (RT_SCHED_MBXSUSP | RT_SCHED_DELAYED);
00103             rem_ready_current(rt_current);
00104             enq_timed_task(rt_current);
00105             rt_schedule();
00106         }
00107         if (unlikely((retp = rt_current->blocked_on) != NULL)) {
00108             mbx->waiting_task = NULL;
00109             rt_global_restore_flags(flags);
00110             return likely(retp > RTP_HIGERR) ? RTE_TIMOUT : (retp == RTP_UNBLKD ? RTE_UNBLKD : RTE_OBJREM);
00111         }
00112     }
00113     rt_global_restore_flags(flags);
00114     return 0;
00115 }
00116 
00117 #define MOD_SIZE(indx) ((indx) < mbx->size ? (indx) : (indx) - mbx->size)
00118 
00119 static int mbxput(MBX *mbx, char **msg, int msg_size, int space)
00120 {
00121     unsigned long flags;
00122     int tocpy;
00123 
00124     while (msg_size > 0 && mbx->frbs) {
00125         if ((tocpy = mbx->size - mbx->lbyte) > msg_size) {
00126             tocpy = msg_size;
00127         }
00128         if (tocpy > mbx->frbs) {
00129             tocpy = mbx->frbs;
00130         }
00131         if (space) {
00132             memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00133         } else {
00134             rt_copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00135         }
00136         flags = rt_spin_lock_irqsave(&(mbx->lock));
00137         mbx->frbs -= tocpy;
00138         mbx->avbs += tocpy;
00139         rt_spin_unlock_irqrestore(flags, &(mbx->lock));
00140         msg_size -= tocpy;
00141         *msg     += tocpy;
00142         mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy);
00143     }
00144     return msg_size;
00145 }
00146 
00147 static int mbxovrwrput(MBX *mbx, char **msg, int msg_size, int space)
00148 {
00149     unsigned long flags;
00150     int tocpy,n;
00151 
00152     if ((n = msg_size - mbx->size) > 0) {
00153         *msg += n;
00154         msg_size -= n;
00155     }       
00156     while (msg_size > 0) {
00157         if (mbx->frbs) {    
00158             if ((tocpy = mbx->size - mbx->lbyte) > msg_size) {
00159                 tocpy = msg_size;
00160             }
00161             if (tocpy > mbx->frbs) {
00162                 tocpy = mbx->frbs;
00163             }
00164             if (space) {
00165                 memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00166             } else {
00167                 rt_copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00168             }
00169             flags = rt_spin_lock_irqsave(&(mbx->lock));
00170             mbx->frbs -= tocpy;
00171             mbx->avbs += tocpy;
00172                 rt_spin_unlock_irqrestore(flags, &(mbx->lock));
00173             msg_size -= tocpy;
00174             *msg     += tocpy;
00175             mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy);
00176         }   
00177         if (msg_size) {
00178             while ((n = msg_size - mbx->frbs) > 0) {
00179                 if ((tocpy = mbx->size - mbx->fbyte) > n) {
00180                     tocpy = n;
00181                 }
00182                 if (tocpy > mbx->avbs) {
00183                     tocpy = mbx->avbs;
00184                 }
00185                     flags = rt_spin_lock_irqsave(&(mbx->lock));
00186                 mbx->frbs  += tocpy;
00187                 mbx->avbs  -= tocpy;
00188                     rt_spin_unlock_irqrestore(flags, &(mbx->lock));
00189                 mbx->fbyte = MOD_SIZE(mbx->fbyte + tocpy);
00190             }
00191         }       
00192     }
00193     return 0;
00194 }
00195 
00196 static int mbxget(MBX *mbx, char **msg, int msg_size, int space)
00197 {
00198     unsigned long flags;
00199     int tocpy;
00200 
00201     while (msg_size > 0 && mbx->avbs) {
00202         if ((tocpy = mbx->size - mbx->fbyte) > msg_size) {
00203             tocpy = msg_size;
00204         }
00205         if (tocpy > mbx->avbs) {
00206             tocpy = mbx->avbs;
00207         }
00208         if (space) {
00209             memcpy(*msg, mbx->bufadr + mbx->fbyte, tocpy);
00210         } else {
00211             rt_copy_to_user(*msg, mbx->bufadr + mbx->fbyte, tocpy);
00212         }
00213         flags = rt_spin_lock_irqsave(&(mbx->lock));
00214         mbx->frbs  += tocpy;
00215         mbx->avbs  -= tocpy;
00216         rt_spin_unlock_irqrestore(flags, &(mbx->lock));
00217         msg_size -= tocpy;
00218         *msg     += tocpy;
00219         mbx->fbyte = MOD_SIZE(mbx->fbyte + tocpy);
00220     }
00221     return msg_size;
00222 }
00223 
00224 static int mbxevdrp(MBX *mbx, char **msg, int msg_size, int space)
00225 {
00226     int tocpy, fbyte, avbs;
00227 
00228     fbyte = mbx->fbyte;
00229     avbs  = mbx->avbs;
00230     while (msg_size > 0 && avbs) {
00231         if ((tocpy = mbx->size - fbyte) > msg_size) {
00232             tocpy = msg_size;
00233         }
00234         if (tocpy > avbs) {
00235             tocpy = avbs;
00236         }
00237         if (space) {
00238             memcpy(*msg, mbx->bufadr + fbyte, tocpy);
00239         } else {
00240             rt_copy_to_user(*msg, mbx->bufadr + mbx->fbyte, tocpy);
00241         }
00242         avbs     -= tocpy;
00243         msg_size -= tocpy;
00244         *msg     += tocpy;
00245         fbyte = MOD_SIZE(fbyte + tocpy);
00246     }
00247     return msg_size;
00248 }
00249 
00250 
00251 /**
00252  * @brief Receives bytes as many as possible leaving the message
00253  * available for another receive.
00254  *
00255  * rt_mbx_evdrp receives at most @e msg_size of bytes of message
00256  * from the mailbox @e mbx and then returns immediately.
00257  * Does what rt_mbx_receive_wp does while keeping the message in the mailbox buffer.
00258  * Useful if one needs to just preview the mailbox content, without actually
00259  * receiving it.
00260  *
00261  * @param mbx is a pointer to a user allocated mailbox structure.
00262  *
00263  * @param msg points to a buffer provided by the caller.
00264  *
00265  * @param msg_size corresponds to the size of the message to be received.
00266  *
00267  * @return The number of bytes not received is returned.
00268  */
00269 RTAI_SYSCALL_MODE int _rt_mbx_evdrp(MBX *mbx, void *msg, int msg_size, int space)
00270 {
00271     return mbxevdrp(mbx, (char **)(&msg), msg_size, space);
00272 }
00273 
00274 
00275 #define CHK_MBX_MAGIC \
00276 do { if (!mbx || mbx->magic != RT_MBX_MAGIC) return (CONFIG_RTAI_USE_NEWERR ? RTE_OBJINV : -EINVAL); } while (0)
00277 
00278 #define MBX_RET(msg_size, retval) \
00279     (CONFIG_RTAI_USE_NEWERR ? retval : msg_size)
00280 
00281 /**
00282  * @brief Initializes a fully typed mailbox queueing tasks
00283  * according to the specified type.
00284  *
00285  * rt_typed_mbx_init initializes a mailbox of size @e size. @e mbx must
00286  * point to a user allocated MBX structure. Tasks are queued in FIFO
00287  * order (FIFO_Q), priority order (PRIO_Q) or resource order (RES_Q).
00288  *
00289  * @param mbx is a pointer to a user allocated mailbox structure.
00290  *
00291  * @param size corresponds to the size of the mailbox.
00292  *
00293  * @param type corresponds to the queueing policy: FIFO_Q, PRIO_Q or RES_Q.
00294  *
00295  * @return On success 0 is returned. On failure, a special value is
00296  * returned as indicated below:
00297  * - @b ENOMEM: Space could not be allocated for the mailbox buffer.
00298  *
00299  * See also: notes under rt_mbx_init().
00300  */
00301 RTAI_SYSCALL_MODE int rt_typed_mbx_init(MBX *mbx, int size, int type)
00302 {
00303     if (!(mbx->bufadr = rt_malloc(size))) { 
00304         return -ENOMEM;
00305     }
00306     rt_typed_sem_init(&(mbx->sndsem), 1, type & 3 ? type : BIN_SEM | type);
00307     rt_typed_sem_init(&(mbx->rcvsem), 1, type & 3 ? type : BIN_SEM | type);
00308     mbx->magic = RT_MBX_MAGIC;
00309     mbx->size = mbx->frbs = size;
00310     mbx->owndby = mbx->waiting_task = NULL;
00311     mbx->fbyte = mbx->lbyte = mbx->avbs = 0;
00312         spin_lock_init(&(mbx->lock));
00313 #ifdef CONFIG_RTAI_RT_POLL
00314     mbx->poll_recv.pollq.prev = mbx->poll_recv.pollq.next = &(mbx->poll_recv.pollq);
00315     mbx->poll_send.pollq.prev = mbx->poll_send.pollq.next = &(mbx->poll_send.pollq);
00316     mbx->poll_recv.pollq.task = mbx->poll_send.pollq.task = NULL;
00317         spin_lock_init(&(mbx->poll_recv.pollock));
00318         spin_lock_init(&(mbx->poll_send.pollock));
00319 #endif
00320     return 0;
00321 }
00322 
00323 
00324 /**
00325  * @brief Initializes a mailbox.
00326  *
00327  * rt_mbx_init initializes a mailbox of size @e size. @e mbx must
00328  * point to a user allocated MBX structure.
00329  * Using mailboxes is a flexible method for inter task
00330  * communications. Tasks are allowed to send arbitrarily sized
00331  * messages by using any mailbox buffer size. There is even no need to
00332  * use a buffer sized at least as the largest message you envisage,
00333  * even if efficiency is likely to suffer from such a
00334  * decision. However if you expect a message larger than the average
00335  * message size very rarely you can use a smaller buffer without much
00336  * loss of efficiency. In such a way you can set up your own mailbox
00337  * usage protocol, e.g. using fix sized messages with a buffer that is
00338  * an integer multiple of such a size guarantees maximum efficiency by
00339  * having each message sent/received atomically to/from the
00340  * mailbox. Multiple senders and receivers are allowed and each will
00341  * get the service it requires in turn, according to its priority. 
00342  * Thus mailboxes provide a flexible mechanism to allow you to freely
00343  * implement your own policy.
00344  *
00345  * rt_mbx_init is equivalent to rt_typed_mbx_init(mbx, size, PRIO_Q).
00346  *
00347  * @param mbx is a pointer to a user allocated mailbox structure.
00348  *
00349  * @param size corresponds to the size of the mailbox.
00350  *
00351  * @return On success 0 is returned. On failure, a special value is
00352  * returned as indicated below:
00353  * - @b ENOMEM: Space could not be allocated for the mailbox buffer.
00354  *
00355  * See also: notes under rt_typed_mbx_init().
00356  */
00357 int rt_mbx_init(MBX *mbx, int size)
00358 {
00359     return rt_typed_mbx_init(mbx, size, PRIO_Q);
00360 }
00361 
00362 
00363 /**
00364  *
00365  * @brief Deletes a mailbox.
00366  * 
00367  * rt_mbx_delete removes a mailbox previously created with rt_mbx_init().
00368  *
00369  * @param mbx is the pointer to the structure used in the corresponding call
00370  * to rt_mbx_init.
00371  *
00372  * @return 0 is returned on success. On failure, a negative value is
00373  * returned as described below:
00374  * - @b EINVAL: @e mbx points to an invalid mailbox.
00375  * - @b EFAULT: mailbox data were found in an invalid state.
00376  */
00377 RTAI_SYSCALL_MODE int rt_mbx_delete(MBX *mbx)
00378 {
00379     CHK_MBX_MAGIC;
00380     mbx->magic = 0;
00381     rt_wakeup_pollers(&mbx->poll_recv, RTE_OBJREM);
00382     rt_wakeup_pollers(&mbx->poll_send, RTE_OBJREM);
00383     if (rt_sem_delete(&mbx->sndsem) || rt_sem_delete(&mbx->rcvsem)) {
00384         return -EFAULT;
00385     }
00386     while (mbx->waiting_task) {
00387         mbx_delete_signal(mbx);
00388     }
00389     rt_free(mbx->bufadr); 
00390     return 0;
00391 }
00392 
00393 
00394 /**
00395  * @brief Sends a message unconditionally.
00396  *
00397  * rt_mbx_send sends a message @e msg of @e msg_size bytes to the
00398  * mailbox @e mbx. The caller will be blocked until the whole message
00399  * is copied into the mailbox or an error occurs. Even if the message
00400  * can be sent in a single shot, the sending task can be blocked if
00401  * there is a task of higher priority waiting to receive from the
00402  * mailbox.
00403  *
00404  * @param mbx is a pointer to a user allocated mailbox structure.
00405  *
00406  * @param msg corresponds to the message to be sent.
00407  *
00408  * @param msg_size is the size of the message.
00409  *
00410  * @return On success, 0 is returned.
00411  * On failure a value is returned as described below:
00412  * - the number of bytes not received: an error is occured 
00413  *   in the queueing of all sending tasks.
00414  * - @b EINVAL: mbx points to an invalid mailbox.
00415  */
00416 RTAI_SYSCALL_MODE int _rt_mbx_send(MBX *mbx, void *msg, int msg_size, int space)
00417 {
00418     RT_TASK *rt_current = RT_CURRENT;
00419     int retval;
00420 
00421     CHK_MBX_MAGIC;
00422     if ((retval = rt_sem_wait(&mbx->sndsem)) > 1) {
00423         return MBX_RET(msg_size, retval);
00424     }
00425     while (msg_size) {
00426         if ((retval = mbx_wait(mbx, &mbx->frbs, rt_current))) {
00427             rt_sem_signal(&mbx->sndsem);
00428             retval = MBX_RET(msg_size, retval);
00429             rt_wakeup_pollers(&mbx->poll_recv, retval);
00430             return retval;
00431         }
00432         msg_size = mbxput(mbx, (char **)(&msg), msg_size, space);
00433         mbx_signal(mbx);
00434     }
00435     rt_sem_signal(&mbx->sndsem);
00436     rt_wakeup_pollers(&mbx->poll_recv, 0);
00437     return 0;
00438 }
00439 
00440 
00441 /**
00442  * @brief Sends as many bytes as possible without blocking the calling task.
00443  *
00444  * rt_mbx_send_wp atomically sends as many bytes of message @e msg as
00445  * possible to the mailbox @e mbx then returns immediately.
00446  *
00447  * @param mbx is a pointer to a user allocated mailbox structure.
00448  *
00449  * @param msg corresponds to the message to be sent.
00450  * 
00451  * @param msg_size is the size of the message.
00452  *
00453  * @return On success, the number of unsent bytes is returned. On
00454  * failure a negative value is returned as described below:
00455  * - @b EINVAL: @e mbx points to an invalid mailbox.
00456  */
00457 RTAI_SYSCALL_MODE int _rt_mbx_send_wp(MBX *mbx, void *msg, int msg_size, int space)
00458 {
00459     unsigned long flags;
00460     RT_TASK *rt_current = RT_CURRENT;
00461     int size = msg_size;
00462 
00463     CHK_MBX_MAGIC;
00464     flags = rt_global_save_flags_and_cli();
00465     if (mbx->sndsem.count > 0 && mbx->frbs) {
00466         mbx->sndsem.count = 0;
00467         if (mbx->sndsem.type > 0) {
00468             mbx->sndsem.owndby = rt_current;
00469             enqueue_resqel(&mbx->sndsem.resq, rt_current);
00470         }
00471         rt_global_restore_flags(flags);
00472         msg_size = mbxput(mbx, (char **)(&msg), msg_size, space);
00473         mbx_signal(mbx);
00474         rt_sem_signal(&mbx->sndsem);
00475     } else {
00476         rt_global_restore_flags(flags);
00477     }
00478     if (msg_size < size) {
00479         rt_wakeup_pollers(&mbx->poll_recv, 0);
00480     }
00481     return msg_size;
00482 }
00483 
00484 
00485 /**
00486  * @brief Sends a message, only if the whole message can be passed
00487  * without blocking the calling task.
00488  *
00489  * rt_mbx_send_if tries to atomically send the message @e msg of @e
00490  * msg_size bytes to the mailbox @e mbx. It returns immediately and
00491  * the caller is never blocked.
00492  *
00493  * @return On success, the number of unsent bytes (0 or @e msg_size)
00494  * is returned. On failure a negative value is returned as described
00495  * below:
00496  * - @b EINVAL: @e mbx points to an invalid mailbox.
00497  */
00498 RTAI_SYSCALL_MODE int _rt_mbx_send_if(MBX *mbx, void *msg, int msg_size, int space)
00499 {
00500     unsigned long flags;
00501     RT_TASK *rt_current = RT_CURRENT;
00502 
00503     CHK_MBX_MAGIC;
00504     flags = rt_global_save_flags_and_cli();
00505     if (mbx->sndsem.count > 0 && msg_size <= mbx->frbs) {
00506         mbx->sndsem.count = 0;
00507         if (mbx->sndsem.type > 0) {
00508             mbx->sndsem.owndby = rt_current;
00509             enqueue_resqel(&mbx->sndsem.resq, rt_current);
00510         }
00511         rt_global_restore_flags(flags);
00512         mbxput(mbx, (char **)(&msg), msg_size, space);
00513         mbx_signal(mbx);
00514         rt_sem_signal(&mbx->sndsem);
00515         rt_wakeup_pollers(&mbx->poll_recv, 0);
00516         return 0;
00517     }
00518     rt_global_restore_flags(flags);
00519     return msg_size;
00520 }
00521 
00522 
00523 /**
00524  * @brief Sends a message with absolute timeout.
00525  *
00526  * rt_mbx_send_until sends a message @e msg of @e msg_size bytes to
00527  * the mailbox @e mbx. The caller will be blocked until all bytes of
00528  * message is enqueued, timeout expires or an error occurs.
00529  *
00530  * @param mbx is a pointer to a user allocated mailbox structure.
00531  *
00532  * @param msg is the message to be sent.
00533  *
00534  * @param msg_size corresponds to the size of the message.
00535  *
00536  * @param time is an absolute value for the timeout.
00537  *
00538  * @return On success, 0 is returned.
00539  * On failure a value is returned as described below:
00540  * - the number of bytes not received: an error is occured 
00541  *   in the queueing of all sending tasks or the timeout has expired.
00542  * - @b EINVAL: mbx points to an invalid mailbox.
00543  *
00544  * See also: notes under @ref _rt_mbx_send_timed().
00545  */
00546 RTAI_SYSCALL_MODE int _rt_mbx_send_until(MBX *mbx, void *msg, int msg_size, RTIME time, int space)
00547 {
00548     RT_TASK *rt_current = RT_CURRENT;
00549     int retval;
00550 
00551     CHK_MBX_MAGIC;
00552     if ((retval = rt_sem_wait_until(&mbx->sndsem, time)) > 1) {
00553         return MBX_RET(msg_size, retval);
00554     }
00555     while (msg_size) {
00556         if ((retval = mbx_wait_until(mbx, &mbx->frbs, time, rt_current))) {
00557             rt_sem_signal(&mbx->sndsem);
00558             retval = MBX_RET(msg_size, retval);
00559             rt_wakeup_pollers(&mbx->poll_recv, retval);
00560             return retval;
00561         }
00562         msg_size = mbxput(mbx, (char **)(&msg), msg_size, space);
00563         mbx_signal(mbx);
00564     }
00565     rt_sem_signal(&mbx->sndsem);
00566     rt_wakeup_pollers(&mbx->poll_recv, 0);
00567     return 0;
00568 }
00569 
00570 
00571 /**
00572  * @brief Sends a message with relative timeout.
00573  *
00574  * rt_mbx_send_timed send a message @e msg of @e msg_size bytes to the
00575  * mailbox @e mbx. The caller will be blocked until all bytes of message 
00576  * is enqueued, timeout expires or an error occurs.
00577  *
00578  * @param mbx is a pointer to a user allocated mailbox structure.
00579  *
00580  * @param msg is the message to be sent.
00581  *
00582  * @param msg_size corresponds to the size of the message.
00583  *
00584  * @param delay is the timeout value relative to the current time.
00585  *
00586  * @return On success, 0 is returned.
00587  * On failure a value is returned as described below:
00588  * - the number of bytes not received: an error is occured 
00589  *   in the queueing of all sending tasks or the timeout has expired.
00590  * - @b EINVAL: mbx points to an invalid mailbox.
00591  *
00592  * See also: notes under @ref _rt_mbx_send_until().
00593  */
00594 RTAI_SYSCALL_MODE int _rt_mbx_send_timed(MBX *mbx, void *msg, int msg_size, RTIME delay, int space)
00595 {
00596     return _rt_mbx_send_until(mbx, msg, msg_size, get_time() + delay, space);
00597 }
00598 
00599 
00600 /**
00601  * @brief Receives a message unconditionally.
00602  *
00603  * rt_mbx_receive receives a message of @e msg_size bytes from the
00604  * mailbox @e mbx. The caller will be blocked until all bytes of the
00605  * message arrive or an error occurs.
00606  *
00607  * @param mbx is a pointer to a user allocated mailbox structure.
00608  *
00609  * @param msg points to a buffer provided by the caller.
00610  *
00611  * @param msg_size corresponds to the size of the message to be received.
00612  *
00613  * @return On success, 0 is returned.
00614  * On failure a value is returned as described below:
00615  * - the number of bytes not received: an error is occured 
00616  *   in the queueing of all receiving tasks.
00617  * - @b EINVAL: mbx points to an invalid mailbox.
00618  */
00619 RTAI_SYSCALL_MODE int _rt_mbx_receive(MBX *mbx, void *msg, int msg_size, int space)
00620 {
00621     RT_TASK *rt_current = RT_CURRENT;
00622     int retval;
00623 
00624     CHK_MBX_MAGIC;
00625     if ((retval = rt_sem_wait(&mbx->rcvsem)) > 1) {
00626         return msg_size;
00627     }
00628     while (msg_size) {
00629         if ((retval = mbx_wait(mbx, &mbx->avbs, rt_current))) {
00630             rt_sem_signal(&mbx->rcvsem);
00631             retval = MBX_RET(msg_size, retval);
00632             rt_wakeup_pollers(&mbx->poll_recv, retval);
00633             return retval;
00634             return MBX_RET(msg_size, retval);
00635         }
00636         msg_size = mbxget(mbx, (char **)(&msg), msg_size, space);
00637         mbx_signal(mbx);
00638     }
00639     rt_sem_signal(&mbx->rcvsem);
00640     rt_wakeup_pollers(&mbx->poll_send, 0);
00641     return 0;
00642 }
00643 
00644 
00645 /**
00646  * @brief Receives bytes as many as possible, without blocking the
00647  * calling task.
00648  *
00649  * rt_mbx_receive_wp receives at most @e msg_size of bytes of message
00650  * from the mailbox @e mbx then returns immediately.
00651  *
00652  * @param mbx is a pointer to a user allocated mailbox structure.
00653  *
00654  * @param msg points to a buffer provided by the caller.
00655  *
00656  * @param msg_size corresponds to the size of the message to be received.
00657  *
00658  * @return On success, the number of bytes not received is returned. On
00659  * failure a negative value is returned as described below:
00660  * - @b EINVAL: mbx points to not a valid mailbox.
00661  */
00662 RTAI_SYSCALL_MODE int _rt_mbx_receive_wp(MBX *mbx, void *msg, int msg_size, int space)
00663 {
00664     unsigned long flags;
00665     RT_TASK *rt_current = RT_CURRENT;
00666     int size = msg_size;
00667 
00668     CHK_MBX_MAGIC;
00669     flags = rt_global_save_flags_and_cli();
00670     if (mbx->rcvsem.count > 0 && mbx->avbs) {
00671         mbx->rcvsem.count = 0;
00672         if (mbx->rcvsem.type > 0) {
00673             mbx->rcvsem.owndby = rt_current;
00674             enqueue_resqel(&mbx->rcvsem.resq, rt_current);
00675         }
00676         rt_global_restore_flags(flags);
00677         msg_size = mbxget(mbx, (char **)(&msg), msg_size, space);
00678         mbx_signal(mbx);
00679         rt_sem_signal(&mbx->rcvsem);
00680     } else {
00681         rt_global_restore_flags(flags);
00682     }
00683     if (msg_size < size) {
00684         rt_wakeup_pollers(&mbx->poll_send, 0);
00685     }
00686     return msg_size;
00687 }
00688 
00689 
00690 /**
00691  * @brief Receives a message only if the whole message can be passed
00692  * without blocking the calling task.
00693  *
00694  * rt_mbx_receive_if receives a message from the mailbox @e mbx if the
00695  * whole message of @e msg_size bytes is available immediately.
00696  *
00697  * @param mbx is a pointer to a user allocated mailbox structure.
00698  *
00699  * @param msg points to a buffer provided by the caller.
00700  *
00701  * @param msg_size corresponds to the size of the message to be received.
00702  *
00703  * @return On success, the number of bytes not received (0 or @e msg_size)
00704  * is returned. On failure a negative value is returned as described
00705  * below:
00706  * - @b EINVAL: mbx points to an invalid mailbox.
00707  */
00708 RTAI_SYSCALL_MODE int _rt_mbx_receive_if(MBX *mbx, void *msg, int msg_size, int space)
00709 {
00710     unsigned long flags;
00711     RT_TASK *rt_current = RT_CURRENT;
00712 
00713     CHK_MBX_MAGIC;
00714     flags = rt_global_save_flags_and_cli();
00715     if (mbx->rcvsem.count > 0 && msg_size <= mbx->avbs) {
00716         mbx->rcvsem.count = 0;
00717         if (mbx->rcvsem.type > 0) {
00718             mbx->rcvsem.owndby = rt_current;
00719             enqueue_resqel(&mbx->rcvsem.resq, rt_current);
00720         }
00721         rt_global_restore_flags(flags);
00722         mbxget(mbx, (char **)(&msg), msg_size, space);
00723         mbx_signal(mbx);
00724         rt_sem_signal(&mbx->rcvsem);
00725         rt_wakeup_pollers(&mbx->poll_send, 0);
00726         return 0;
00727     }
00728     rt_global_restore_flags(flags);
00729     return msg_size;
00730 }
00731 
00732 
00733 /**
00734  * @brief Receives a message with absolute timeout.
00735  *
00736  * rt_mbx_receive_until receives a message of @e msg_size bytes from
00737  * the mailbox @e mbx. The caller will be blocked until all bytes of
00738  * the message arrive, timeout expires or an error occurs.
00739  *
00740  * @param mbx is a pointer to a user allocated mailbox structure.
00741  *
00742  * @param msg points to a buffer provided by the caller.
00743  *
00744  * @param msg_size corresponds to the size of the message received.
00745  *
00746  * @param time is an absolute value of the timeout.
00747  *
00748  * @return On success, 0 is returned.
00749  * On failure a value is returned as described below:
00750  * - the number of bytes not received: an error is occured 
00751  *   in the queueing of all receiving tasks or the timeout has expired.
00752  * - @b EINVAL: mbx points to an invalid mailbox.
00753  *
00754  * See also: notes under rt_mbx_received_timed().
00755  */
00756 RTAI_SYSCALL_MODE int _rt_mbx_receive_until(MBX *mbx, void *msg, int msg_size, RTIME time, int space)
00757 {
00758     RT_TASK *rt_current = RT_CURRENT;
00759     int retval;
00760 
00761     CHK_MBX_MAGIC;
00762     if ((retval = rt_sem_wait_until(&mbx->rcvsem, time)) > 1) {
00763         return MBX_RET(msg_size, retval);
00764     }
00765     while (msg_size) {
00766         if ((retval = mbx_wait_until(mbx, &mbx->avbs, time, rt_current))) {
00767             rt_sem_signal(&mbx->rcvsem);
00768             retval = MBX_RET(msg_size, retval);
00769             rt_wakeup_pollers(&mbx->poll_recv, retval);
00770             return retval;
00771         }
00772         msg_size = mbxget(mbx, (char **)(&msg), msg_size, space);
00773         mbx_signal(mbx);
00774     }
00775     rt_sem_signal(&mbx->rcvsem);
00776     rt_wakeup_pollers(&mbx->poll_send, 0);
00777     return 0;
00778 }
00779 
00780 
00781 /**
00782  * @brief Receives a message with relative timeout.
00783  *
00784  * rt_mbx_receive_timed receives a message of @e msg_size bytes from
00785  * the mailbox @e mbx. The caller will be blocked until all bytes of 
00786  * the message arrive, timeout expires or an error occurs.
00787  *
00788  * @param mbx is a pointer to a user allocated mailbox structure.
00789  *
00790  * @param msg points to a buffer provided by the caller.
00791  *
00792  * @param msg_size corresponds to the size of the message received.
00793  *
00794  * @param delay is the timeout value relative to the current time.
00795  *
00796  * @return On success, 0 is returned.
00797  * On failure a value is returned as described below:
00798  * - the number of bytes not received: an error is occured 
00799  *   in the queueing of all receiving tasks or the timeout has expired.
00800  * - @b EINVAL: mbx points to an invalid mailbox.
00801  *
00802  * See also: notes under rt_mbx_received_until().
00803  */
00804 RTAI_SYSCALL_MODE int _rt_mbx_receive_timed(MBX *mbx, void *msg, int msg_size, RTIME delay, int space)
00805 {
00806     return _rt_mbx_receive_until(mbx, msg, msg_size, get_time() + delay, space);
00807 }
00808 
00809 
00810 /**
00811  * @brief Sends a message overwriting what already in the buffer
00812  * if there is no place for the message.
00813  *
00814  * rt_mbx_ovrwr_send sends the message @e msg of @e msg_size bytes
00815  * to the mailbox @e mbx overwriting what already in the mailbox
00816  * buffer if there is no place for the message. Useful for logging
00817  * purposes. It returns immediately and the caller is never blocked.
00818  *
00819  * @return On success, 0 is returned. On failure a negative value
00820  * is returned as described below:
00821  * - @b EINVAL: @e mbx points to an invalid mailbox.
00822  */
00823 RTAI_SYSCALL_MODE int _rt_mbx_ovrwr_send(MBX *mbx, void *msg, int msg_size, int space)
00824 {
00825     unsigned long flags;
00826     RT_TASK *rt_current = RT_CURRENT;
00827 
00828     CHK_MBX_MAGIC;
00829 
00830     flags = rt_global_save_flags_and_cli();
00831     if (mbx->sndsem.count > 0) {
00832         mbx->sndsem.count = 0;
00833         if (mbx->sndsem.type > 0) {
00834             mbx->sndsem.owndby = rt_current;
00835             enqueue_resqel(&mbx->sndsem.resq, rt_current);
00836         }
00837         rt_global_restore_flags(flags);
00838         msg_size = mbxovrwrput(mbx, (char **)(&msg), msg_size, space);
00839         mbx_signal(mbx);
00840         rt_sem_signal(&mbx->sndsem);
00841     } else {
00842         rt_global_restore_flags(flags);
00843     }
00844     return msg_size;
00845 }
00846 
00847 /* ++++++++++++++++++++++++++ NAMED MAIL BOXES ++++++++++++++++++++++++++++++ */
00848 
00849 #include <rtai_registry.h>
00850 
00851 
00852 /**
00853  * @brief Initializes a specifically typed (fifo queued, priority queued
00854  * or resource queued) mailbox identified by a name.
00855  *
00856  * _rt_typed_named_mbx_init initializes a mailbox of type @e qtype
00857  * and size @e size identified by @e name. Named mailboxed
00858  * are useful for use among different processes, kernel/user space and
00859  * in distributed applications, see netrpc.
00860  *
00861  * @param mbx_name is the mailbox name; since it can be a clumsy identifier,
00862  * services are provided to convert 6 characters identifiers to unsigned long
00863  * (see nam2num()).
00864  *
00865  * @param size corresponds to the size of the mailbox.
00866  *
00867  * @param qtype corresponds to the queueing policy: FIFO_Q, PRIO_Q or RES_Q.
00868  *
00869  * @return On success the pointer to the allocated mbx is returned.
00870  * On failure, NULL is returned.
00871  *
00872  * See also: notes under rt_mbx_init() and rt_typed_mbx_init().
00873  */
00874 RTAI_SYSCALL_MODE MBX *_rt_typed_named_mbx_init(unsigned long mbx_name, int size, int qtype)
00875 {
00876     MBX *mbx;
00877 
00878     if ((mbx = rt_get_adr_cnt(mbx_name))) {
00879         return mbx;
00880     }
00881     if ((mbx = rt_malloc(sizeof(MBX)))) {
00882         rt_typed_mbx_init(mbx, size, qtype);
00883         if (rt_register(mbx_name, mbx, IS_MBX, 0)) {
00884             return mbx;
00885         }
00886         rt_mbx_delete(mbx);
00887     }
00888     rt_free(mbx);
00889     return (MBX *)0;
00890 }
00891 
00892 
00893 /**
00894  *
00895  * @brief Deletes a named mailbox.
00896  * 
00897  * rt_named_mbx_delete removes a mailbox previously created
00898  * with _rt_typed_named_mbx_init().
00899  *
00900  * @param mbx is the pointer to the structure returned by a corresponding
00901  * call to _rt_typed_named_mbx_init.
00902  *
00903  * As it is done by all the named allocation functions delete calls have just
00904  * the effect of decrementing a usage count till the last is done, as that is
00905  * the one that really frees the object.
00906  *
00907  * @return On success, an integer >=0 is returned.
00908  * On failure, a negative value is returned as described below:
00909  * - @b EFAULT: deletion of mailbox failed.
00910  *
00911  * See also: notes under rt_mbx_delete().
00912  */
00913 RTAI_SYSCALL_MODE int rt_named_mbx_delete(MBX *mbx)
00914 {
00915     int ret;
00916     if (!(ret = rt_drg_on_adr_cnt(mbx))) {
00917         if (!rt_mbx_delete(mbx)) {
00918             rt_free(mbx);
00919             return 0;
00920         } else {
00921             return -EFAULT;
00922         }
00923     }
00924     return ret;
00925 }
00926 
00927 /* +++++++++++++++++++++++++ MAIL BOXES ENTRIES +++++++++++++++++++++++++++++ */
00928 
00929 struct rt_native_fun_entry rt_mbx_entries[] = {
00930 
00931     { { 0, rt_typed_mbx_init },             TYPED_MBX_INIT },
00932     { { 0, rt_mbx_delete },             MBX_DELETE },
00933     { { 1, _rt_mbx_send },              MBX_SEND },
00934     { { 1, _rt_mbx_send_wp },           MBX_SEND_WP },
00935     { { 1, _rt_mbx_send_if },           MBX_SEND_IF },
00936     { { 1, _rt_mbx_send_until },        MBX_SEND_UNTIL },
00937     { { 1, _rt_mbx_send_timed },        MBX_SEND_TIMED },
00938     { { 1, _rt_mbx_ovrwr_send },        MBX_OVRWR_SEND },
00939         { { 1, _rt_mbx_evdrp },             MBX_EVDRP },
00940     { { 1, _rt_mbx_receive },           MBX_RECEIVE },
00941     { { 1, _rt_mbx_receive_wp },        MBX_RECEIVE_WP },
00942     { { 1, _rt_mbx_receive_if },        MBX_RECEIVE_IF },
00943     { { 1, _rt_mbx_receive_until },     MBX_RECEIVE_UNTIL },
00944     { { 1, _rt_mbx_receive_timed },     MBX_RECEIVE_TIMED },
00945     { { 0, _rt_typed_named_mbx_init },      NAMED_MBX_INIT },
00946     { { 0, rt_named_mbx_delete },       NAMED_MBX_DELETE },
00947     { { 0, 0 },                         000 }
00948 };
00949 
00950 extern int set_rt_fun_entries(struct rt_native_fun_entry *entry);
00951 extern void reset_rt_fun_entries(struct rt_native_fun_entry *entry);
00952 
00953 static int recv_blocks(void *mbx) { return ((MBX *)mbx)->avbs <= 0; }
00954 static int send_blocks(void *mbx) { return ((MBX *)mbx)->frbs <= 0; }
00955 
00956 int __rtai_mbx_init (void)
00957 {
00958     rt_poll_ofstfun[RT_POLL_MBX_RECV].topoll = recv_blocks;
00959     rt_poll_ofstfun[RT_POLL_MBX_SEND].topoll = send_blocks;
00960     return set_rt_fun_entries(rt_mbx_entries);
00961 }
00962 
00963 void __rtai_mbx_exit (void)
00964 {
00965     rt_poll_ofstfun[RT_POLL_MBX_RECV].topoll = NULL;
00966     rt_poll_ofstfun[RT_POLL_MBX_SEND].topoll = NULL;
00967     reset_rt_fun_entries(rt_mbx_entries);
00968 }
00969 
00970 /*@}*/
00971 
00972 #ifndef CONFIG_RTAI_MBX_BUILTIN
00973 module_init(__rtai_mbx_init);
00974 module_exit(__rtai_mbx_exit);
00975 #endif /* !CONFIG_RTAI_MBX_BUILTIN */
00976 
00977 #ifdef CONFIG_KBUILD
00978 EXPORT_SYMBOL(_rt_mbx_evdrp);
00979 EXPORT_SYMBOL(rt_typed_mbx_init);
00980 EXPORT_SYMBOL(rt_mbx_init);
00981 EXPORT_SYMBOL(rt_mbx_delete);
00982 EXPORT_SYMBOL(_rt_mbx_send);
00983 EXPORT_SYMBOL(_rt_mbx_send_wp);
00984 EXPORT_SYMBOL(_rt_mbx_send_if);
00985 EXPORT_SYMBOL(_rt_mbx_send_until);
00986 EXPORT_SYMBOL(_rt_mbx_send_timed);
00987 EXPORT_SYMBOL(_rt_mbx_receive);
00988 EXPORT_SYMBOL(_rt_mbx_receive_wp);
00989 EXPORT_SYMBOL(_rt_mbx_receive_if);
00990 EXPORT_SYMBOL(_rt_mbx_receive_until);
00991 EXPORT_SYMBOL(_rt_mbx_receive_timed);
00992 EXPORT_SYMBOL(_rt_mbx_ovrwr_send);
00993 EXPORT_SYMBOL(_rt_typed_named_mbx_init);
00994 EXPORT_SYMBOL(rt_named_mbx_delete);
00995 #endif /* CONFIG_KBUILD */

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