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

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