base/ipc/tbx/tbx.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005 Paolo Mantegazza <mantegazza@aero.polimi.it>
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  *
00018  */
00019 
00020 
00021 #include <linux/module.h>
00022 #include <linux/kernel.h>
00023 #include <linux/errno.h>
00024 #include <asm/uaccess.h>
00025 
00026 #include <rtai_registry.h>
00027 #include <rtai_schedcore.h>
00028 #include <rtai_tbx.h>
00029 
00030 MODULE_LICENSE("GPL");
00031 
00032 static inline void enq_msg(RT_MSGQ *q, RT_MSGH *msg)
00033 {
00034     RT_MSGH *prev, *next;
00035 
00036     for (prev = next = q->firstmsg; msg->priority >= next->priority; prev = next, next = next->next);
00037     if (next == prev) {
00038         msg->next = next;
00039         q->firstmsg = msg;
00040     } else {
00041         msg->next = prev->next;
00042         prev->next = msg;
00043     }
00044 }
00045 
00046 RTAI_SYSCALL_MODE int rt_msgq_init(RT_MSGQ *mq, int nmsg, int msg_size)
00047 {
00048     int i;
00049         void *p;
00050 
00051     if (!(mq->slots = rt_malloc((msg_size + RT_MSGH_SIZE + sizeof(void *))*nmsg + RT_MSGH_SIZE))) {
00052         return -ENOMEM;
00053     }
00054     mq->nmsg  = nmsg;
00055     mq->fastsize = msg_size;
00056     mq->slot = 0;
00057     p = mq->slots + nmsg;
00058     for (i = 0; i < nmsg; i++) {
00059                 mq->slots[i] = p;
00060         ((RT_MSGH *)p)->priority = 0;
00061         p += (msg_size + RT_MSGH_SIZE);
00062     }
00063         ((RT_MSGH *)(mq->firstmsg = p))->priority = (0xFFFFFFFF/2);
00064     rt_typed_sem_init(&mq->receivers, 1, RES_SEM);
00065     rt_typed_sem_init(&mq->senders, 1, RES_SEM);
00066     rt_typed_sem_init(&mq->received, 0, CNT_SEM);
00067     rt_typed_sem_init(&mq->freslots, nmsg, CNT_SEM);
00068     spin_lock_init(&mq->lock);
00069     return 0;
00070 }
00071 
00072 RTAI_SYSCALL_MODE int rt_msgq_delete(RT_MSGQ *mq)
00073 {
00074         if (rt_sem_delete(&mq->receivers) | rt_sem_delete(&mq->senders) | rt_sem_delete(&mq->received) | rt_sem_delete(&mq->freslots) | rt_sem_delete(&mq->broadcast)) {
00075                 return -EFAULT;
00076         }
00077         rt_free(mq->slots);
00078         return 0;
00079 }
00080 
00081 RTAI_SYSCALL_MODE RT_MSGQ *_rt_named_msgq_init(unsigned long msgq_name, int nmsg, int msg_size)
00082 {
00083     RT_MSGQ *msgq;
00084 
00085     if ((msgq = rt_get_adr_cnt(msgq_name))) {
00086         return msgq;
00087     }
00088     if ((msgq = rt_malloc(sizeof(RT_MSGQ)))) {
00089         rt_msgq_init(msgq, nmsg, msg_size);
00090         if (rt_register(msgq_name, msgq, IS_MBX, 0)) {
00091             return msgq;
00092         }
00093         rt_msgq_delete(msgq);
00094     }
00095     rt_free(msgq);
00096     return NULL;
00097 }
00098 
00099 RTAI_SYSCALL_MODE int rt_named_msgq_delete(RT_MSGQ *msgq)
00100 {
00101     int ret;
00102     if (!(ret = rt_drg_on_adr_cnt(msgq))) {
00103         if (!rt_msgq_delete(msgq)) {
00104             rt_free(msgq);
00105             return 0;
00106         } else {
00107             return -EFAULT;
00108         }
00109     }
00110     return ret;
00111 }
00112 
00113 static int _send(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int space)
00114 {
00115     unsigned long flags;
00116     RT_MSG *msg_ptr;
00117     void *p;
00118 
00119     if (msg_size > mq->fastsize) {
00120         if (!(p = rt_malloc(msg_size))) {
00121             rt_sem_signal(&mq->freslots);
00122             rt_sem_signal(&mq->senders);
00123             return -ENOMEM;
00124         }
00125     } else {
00126         p = NULL;
00127     }
00128     flags = rt_spin_lock_irqsave(&mq->lock);
00129     msg_ptr = mq->slots[mq->slot++];
00130     rt_spin_unlock_irqrestore(flags, &mq->lock);
00131     msg_ptr->hdr.size = msg_size;
00132     msg_ptr->hdr.priority = msgpri;
00133     msg_ptr->hdr.malloc = p;
00134     msg_ptr->hdr.broadcast = 0;
00135     if (space) {
00136         memcpy(p ? p : msg_ptr->msg, msg, msg_size);
00137     } else {
00138         rt_copy_from_user(p ? p : msg_ptr->msg, msg, msg_size);
00139     }
00140     flags = rt_spin_lock_irqsave(&mq->lock);
00141     enq_msg(mq, &msg_ptr->hdr);
00142     rt_spin_unlock_irqrestore(flags, &mq->lock);
00143     rt_sem_signal(&mq->received);
00144     rt_sem_signal(&mq->senders);
00145     return 0;
00146 }
00147 
00148 #define TBX_RET(msg_size, retval) \
00149         (CONFIG_RTAI_USE_NEWERR ? retval : msg_size)
00150 
00151 RTAI_SYSCALL_MODE int _rt_msg_send(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int space)
00152 {
00153     int retval;
00154 
00155     if ((retval = rt_sem_wait(&mq->senders)) >= RTE_LOWERR) {
00156         return TBX_RET(msg_size, retval);
00157         }
00158     if (rt_sem_wait(&mq->freslots) >= RTE_LOWERR) {
00159         rt_sem_signal(&mq->senders);
00160         return TBX_RET(msg_size, retval);
00161     }
00162     return _send(mq, msg, msg_size, msgpri, space);
00163 }
00164 
00165 RTAI_SYSCALL_MODE int _rt_msg_send_if(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int space)
00166 {
00167     if (rt_sem_wait_if(&mq->senders) <= 0) {
00168                 return msg_size;
00169         }
00170     if (rt_sem_wait_if(&mq->freslots) <= 0) {
00171         rt_sem_signal(&mq->senders);
00172         return msg_size;
00173     }
00174     return _send(mq, msg, msg_size, msgpri, space);
00175 }
00176 
00177 RTAI_SYSCALL_MODE int _rt_msg_send_until(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, RTIME until, int space)
00178 {
00179     int retval;
00180     if ((retval = rt_sem_wait_until(&mq->senders, until)) >= RTE_LOWERR) {
00181         return TBX_RET(msg_size, retval);
00182         }
00183     if ((retval = rt_sem_wait_until(&mq->freslots, until)) >= RTE_LOWERR) {
00184         rt_sem_signal(&mq->senders);
00185         return TBX_RET(msg_size, retval);
00186     }
00187     return _send(mq, msg, msg_size, msgpri, space);
00188 }
00189 
00190 RTAI_SYSCALL_MODE int _rt_msg_send_timed(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, RTIME delay, int space)
00191 {
00192     return _rt_msg_send_until(mq, msg, msg_size, msgpri, get_time() + delay, space);
00193 }
00194 
00195 static int _receive(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, int space)
00196 {
00197     int size;
00198     RT_MSG *msg_ptr;
00199     void *p;
00200 
00201     size = min((msg_ptr = mq->firstmsg)->hdr.size, msg_size);
00202     if (space) {
00203         memcpy(msg, (p = msg_ptr->hdr.malloc) ? p : msg_ptr->msg, size);
00204         if (msgpri) {
00205             *msgpri = msg_ptr->hdr.priority;
00206         }
00207     } else {
00208         rt_copy_to_user(msg, (p = msg_ptr->hdr.malloc) ? p : msg_ptr->msg, size);
00209         if (msgpri) {
00210             rt_put_user(msg_ptr->hdr.priority, msgpri);
00211         }
00212     }
00213 
00214     if (msg_ptr->hdr.broadcast) {
00215         if (!--msg_ptr->hdr.broadcast) {
00216             rt_sem_wait_barrier(&mq->broadcast);
00217             goto relslot;
00218         } else {
00219             rt_sem_signal(&mq->received);
00220             rt_sem_signal(&mq->receivers);
00221             rt_sem_wait_barrier(&mq->broadcast);
00222         }
00223     } else {
00224         unsigned long flags;
00225 relslot:    flags = rt_spin_lock_irqsave(&mq->lock);
00226         mq->firstmsg = msg_ptr->hdr.next;
00227         mq->slots[--mq->slot] = msg_ptr;
00228         rt_spin_unlock_irqrestore(flags, &mq->lock);
00229         rt_sem_signal(&mq->freslots);
00230         rt_sem_signal(&mq->receivers);
00231         if (p) {
00232             rt_free(p);
00233         }
00234     }
00235     return msg_size - size;
00236 }
00237 
00238 RTAI_SYSCALL_MODE int _rt_msg_receive(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, int space)
00239 {
00240     int retval;
00241     if ((retval = rt_sem_wait(&mq->receivers)) >= RTE_LOWERR) {
00242         return TBX_RET(msg_size, retval);
00243     }
00244     if ((retval = rt_sem_wait(&mq->received)) >= RTE_LOWERR) { ;
00245         rt_sem_signal(&mq->receivers);
00246         return TBX_RET(msg_size, retval);
00247     }
00248     return _receive(mq, msg, msg_size, msgpri, space);
00249 }
00250 
00251 RTAI_SYSCALL_MODE int _rt_msg_receive_if(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, int space)
00252 {
00253     if (rt_sem_wait_if(&mq->receivers) <= 0) {
00254         return msg_size;
00255     }
00256     if (rt_sem_wait_if(&mq->received) <= 0) { ;
00257         rt_sem_signal(&mq->receivers);
00258         return msg_size;
00259     }
00260     return _receive(mq, msg, msg_size, msgpri, space);
00261 }
00262 
00263 RTAI_SYSCALL_MODE int _rt_msg_receive_until(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, RTIME until, int space)
00264 {
00265     int retval;
00266     if ((retval = rt_sem_wait_until(&mq->receivers, until)) >= RTE_LOWERR) {
00267         return TBX_RET(msg_size, retval);
00268     }
00269     if ((retval = rt_sem_wait_until(&mq->received, until)) >= RTE_LOWERR) {
00270         rt_sem_signal(&mq->receivers);
00271         return TBX_RET(msg_size, retval);
00272     }
00273     return _receive(mq, msg, msg_size, msgpri, space);
00274 }
00275 
00276 RTAI_SYSCALL_MODE int _rt_msg_receive_timed(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, RTIME delay, int space)
00277 {
00278     return _rt_msg_receive_until(mq, msg, msg_size, msgpri, get_time() + delay, space);
00279 }
00280 
00281 RTAI_SYSCALL_MODE int _rt_msg_evdrp(RT_MSGQ *mq, void *msg, int msg_size, int *msgpri, int space)
00282 {
00283     int size;
00284     RT_MSG *msg_ptr;
00285     void *p;
00286 
00287     size = min((msg_ptr = mq->firstmsg)->hdr.size, msg_size);
00288     if (space) {
00289         memcpy(msg, (p = msg_ptr->hdr.malloc) ? p : msg_ptr->msg, size);
00290         if (msgpri) {
00291             *msgpri = msg_ptr->hdr.priority;
00292         }
00293     } else {
00294         rt_copy_to_user(msg, (p = msg_ptr->hdr.malloc) ? p : msg_ptr->msg, size);
00295         if (msgpri) {
00296             rt_put_user(msg_ptr->hdr.priority, msgpri);
00297         }
00298     }
00299     return 0;
00300 }
00301 
00302 static int _broadcast(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int broadcast, int space)
00303 {
00304     unsigned long flags;
00305     RT_MSG *msg_ptr;
00306     void *p;
00307 
00308     if (msg_size > mq->fastsize) {
00309         if (!(p = rt_malloc(msg_size))) {
00310             rt_sem_signal(&mq->freslots);
00311             rt_sem_signal(&mq->senders);
00312             return -ENOMEM;
00313         }
00314     } else {
00315         p = NULL;
00316     }
00317     flags = rt_spin_lock_irqsave(&mq->lock);
00318     msg_ptr = mq->slots[mq->slot++];
00319     rt_spin_unlock_irqrestore(flags, &mq->lock);
00320     msg_ptr->hdr.size = msg_size;
00321     msg_ptr->hdr.priority = msgpri;
00322     msg_ptr->hdr.malloc = p;
00323     if (space) {
00324         memcpy(p ? p : msg_ptr->msg, msg, msg_size);
00325     } else {
00326         rt_copy_from_user(p ? p : msg_ptr->msg, msg, msg_size);
00327     }
00328     rt_typed_sem_init(&mq->broadcast, broadcast + 1, CNT_SEM | PRIO_Q);
00329     msg_ptr->hdr.broadcast = broadcast; 
00330     flags = rt_spin_lock_irqsave(&mq->lock);
00331     enq_msg(mq, &msg_ptr->hdr);
00332     rt_spin_unlock_irqrestore(flags, &mq->lock);
00333     rt_sem_signal(&mq->received);
00334     rt_sem_wait_barrier(&mq->broadcast);
00335     rt_sem_signal(&mq->senders);
00336     return broadcast;
00337 }
00338 
00339 RTAI_SYSCALL_MODE int _rt_msg_broadcast(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int space)
00340 {
00341     int retval;
00342 
00343     if ((retval = rt_sem_wait(&mq->senders)) >= RTE_LOWERR) {
00344         return TBX_RET(0, retval);
00345         }
00346     if (mq->received.count >= 0) {
00347         rt_sem_signal(&mq->senders);
00348         return 0;
00349     }
00350     if ((retval = rt_sem_wait(&mq->freslots)) >= RTE_LOWERR) {
00351         rt_sem_signal(&mq->senders);
00352         return TBX_RET(0, retval);
00353     }
00354     return _broadcast(mq, msg, msg_size, msgpri, -(mq->received.count + mq->receivers.count), space);
00355 }
00356 
00357 RTAI_SYSCALL_MODE int _rt_msg_broadcast_if(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, int space)
00358 {
00359     if (rt_sem_wait_if(&mq->senders) <= 0) {
00360                 return 0;
00361         }
00362     if (mq->received.count >= 0) {
00363         rt_sem_signal(&mq->senders);
00364         return 0;
00365     }
00366     if (rt_sem_wait_if(&mq->freslots) <= 0) {
00367         rt_sem_signal(&mq->senders);
00368                 return 0;
00369     }
00370     return _broadcast(mq, msg, msg_size, msgpri, -(mq->received.count + mq->receivers.count), space);
00371 }
00372 
00373 RTAI_SYSCALL_MODE int _rt_msg_broadcast_until(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, RTIME until, int space)
00374 {
00375     int retval;
00376 
00377     if ((retval = rt_sem_wait_until(&mq->senders, until)) >= RTE_LOWERR) {
00378         return TBX_RET(0, retval);
00379         }
00380     if (mq->received.count >= 0) {
00381         rt_sem_signal(&mq->senders);
00382         return 0;
00383     }
00384     if ((retval = rt_sem_wait_until(&mq->freslots, until)) >= RTE_LOWERR) {
00385         rt_sem_signal(&mq->senders);
00386         return TBX_RET(0, retval);
00387     }
00388     return _broadcast(mq, msg, msg_size, msgpri, -(mq->received.count + mq->receivers.count), space);
00389 }
00390 
00391 RTAI_SYSCALL_MODE int _rt_msg_broadcast_timed(RT_MSGQ *mq, void *msg, int msg_size, int msgpri, RTIME delay, int space)
00392 {
00393     return _rt_msg_broadcast_until(mq, msg, msg_size, msgpri, get_time() + delay, space);
00394 }
00395 
00396 struct rt_native_fun_entry rt_msg_queue_entries[] = {
00397     { { 0, rt_msgq_init },              MSGQ_INIT },
00398         { { 1, rt_msgq_delete },        MSGQ_DELETE },
00399     { { 0, _rt_named_msgq_init },           NAMED_MSGQ_INIT },
00400         { { 1, rt_named_msgq_delete },      NAMED_MSGQ_DELETE },
00401         { { 1, _rt_msg_send },              MSG_SEND },
00402         { { 1, _rt_msg_send_if },           MSG_SEND_IF },
00403         { { 1, _rt_msg_send_until },        MSG_SEND_UNTIL },
00404         { { 1, _rt_msg_send_timed },        MSG_SEND_TIMED },
00405         { { 1, _rt_msg_receive },           MSG_RECEIVE },
00406         { { 1, _rt_msg_receive_if },        MSG_RECEIVE_IF },
00407         { { 1, _rt_msg_receive_until },     MSG_RECEIVE_UNTIL },
00408         { { 1, _rt_msg_receive_timed },     MSG_RECEIVE_TIMED },
00409         { { 1, _rt_msg_broadcast },             MSG_BROADCAST },
00410         { { 1, _rt_msg_broadcast_if },          MSG_BROADCAST_IF },
00411         { { 1, _rt_msg_broadcast_until },   MSG_BROADCAST_UNTIL },
00412         { { 1, _rt_msg_broadcast_timed },   MSG_BROADCAST_TIMED },
00413         { { 1, _rt_msg_evdrp },         MSG_EVDRP },
00414     { { 0, 0 },                     000 }
00415 };
00416 
00417 extern int set_rt_fun_entries(struct rt_native_fun_entry *entry);
00418 extern void reset_rt_fun_entries(struct rt_native_fun_entry *entry);
00419 
00420 int __rtai_msg_queue_init(void) 
00421 {
00422     printk(KERN_INFO "RTAI[rtai_msgq]: loaded.\n");
00423     return set_rt_fun_entries(rt_msg_queue_entries);
00424 }
00425 
00426 void __rtai_msg_queue_exit(void) 
00427 {
00428     reset_rt_fun_entries(rt_msg_queue_entries);
00429     printk(KERN_INFO "RTAI[rtai_msgq]: unloaded.\n");
00430 }
00431 
00432 #ifndef CONFIG_RTAI_TBX_BUILTIN
00433 module_init(__rtai_msg_queue_init);
00434 module_exit(__rtai_msg_queue_exit);
00435 #endif /* !CONFIG_RTAI_TBX_BUILTIN */
00436 
00437 #ifdef CONFIG_KBUILD
00438 EXPORT_SYMBOL(rt_msgq_init);
00439 EXPORT_SYMBOL(rt_msgq_delete);
00440 EXPORT_SYMBOL(_rt_named_msgq_init);
00441 EXPORT_SYMBOL(rt_named_msgq_delete);
00442 EXPORT_SYMBOL(_rt_msg_send);
00443 EXPORT_SYMBOL(_rt_msg_send_if);
00444 EXPORT_SYMBOL(_rt_msg_send_until);
00445 EXPORT_SYMBOL(_rt_msg_send_timed);
00446 EXPORT_SYMBOL(_rt_msg_receive);
00447 EXPORT_SYMBOL(_rt_msg_receive_if);
00448 EXPORT_SYMBOL(_rt_msg_receive_until);
00449 EXPORT_SYMBOL(_rt_msg_receive_timed);
00450 EXPORT_SYMBOL(_rt_msg_broadcast);
00451 EXPORT_SYMBOL(_rt_msg_broadcast_if);
00452 EXPORT_SYMBOL(_rt_msg_broadcast_until);
00453 EXPORT_SYMBOL(_rt_msg_broadcast_timed);
00454 EXPORT_SYMBOL(_rt_msg_evdrp);
00455 #endif /* CONFIG_KBUILD */

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