00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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