rtai_pmq.h
1 /* 2 * pqueues interface for Real Time Linux. 3 * 4 * Copyright (�) 1999 Zentropic Computing, All rights reserved 5 * 6 * Authors: Trevor Woolven (trevw@zentropix.com) 7 * 8 * Original date: Thu 15 Jul 1999 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of the 13 * License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23 * 24 * 2005, cleaned and revised Paolo Mantegazza <mantegazza@aero.polimi.it>. 25 * 26 */ 27 28 #ifndef _RTAI_MQ_H 29 #define _RTAI_MQ_H 30 31 #include <linux/version.h> 32 #include <rtai_sem.h> 33 #include <rtai_schedcore.h> 34 35 #define MQ_OPEN_MAX 8 /* Maximum number of message queues per process */ 36 #ifndef MQ_PRIO_MAX 37 #define MQ_PRIO_MAX 32 /* Maximum number of message priorities */ 38 #endif 39 #define MQ_BLOCK 0 /* Flag to set queue into blocking mode */ 40 #define MQ_NONBLOCK 1 /* Flag to set queue into non-blocking mode */ 41 #define MQ_NAME_MAX 80 /* Maximum length of a queue name string */ 42 43 #define MQ_MIN_MSG_PRIORITY 0 /* Lowest priority message */ 44 #define MQ_MAX_MSG_PRIORITY MQ_PRIO_MAX /* Highest priority message */ 45 46 #define MAX_PQUEUES 4 /* Maximum number of message queues in module, 47 remember to update rtai_mq.h too. */ 48 #define MAX_MSGSIZE 50 /* Maximum message size per queue (bytes) */ 49 #define MAX_MSGS 10 /* Maximum number of messages per queue */ 50 51 #define O_NOTIFY_NP 0x1000 52 53 typedef struct mq_attr { 54 long mq_maxmsg; /* Maximum number of messages in queue */ 55 long mq_msgsize; /* Maximum size of a message (in bytes) */ 56 long mq_flags; /* Blocking/Non-blocking behaviour specifier */ 57 long mq_curmsgs; /* Number of messages currently in queue */ 58 } MQ_ATTR; 59 60 #define INVALID_PQUEUE 0 61 62 #ifdef __KERNEL__ 63 64 #include <linux/types.h> 65 66 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) 67 typedef int mqd_t; 68 #endif 69 70 #ifndef __cplusplus 71 72 typedef int mq_bool_t; 73 74 #ifndef TRUE 75 #define TRUE 1 76 #define FALSE 0 77 #endif 78 79 typedef struct msg_hdr { 80 size_t size; /* Actual message size */ 81 uint priority; /* Usage priority (message/task) */ 82 void *next; /* Pointer to next message on queue */ 83 } MSG_HDR; 84 85 #define MSG_HDR_SIZE (sizeof(MSG_HDR)) 86 87 typedef struct queue_control { 88 int nodind; 89 void **nodes; 90 void *base; /* Pointer to the base of the queue in memory */ 91 void *head; /* Pointer to the element at the front of the queue */ 92 void *tail; /* Pointer to the element at the back of the queue */ 93 MQ_ATTR attrs; /* Queue attributes */ 94 } Q_CTRL; 95 96 typedef struct msg { 97 MSG_HDR hdr; 98 char data; /* Anchor point for message data */ 99 } MQMSG; 100 101 struct notify { 102 RT_TASK *task; 103 struct sigevent data; 104 }; 105 106 typedef struct _pqueue_descr_struct { 107 RT_TASK *owner; /* Task that created the queue */ 108 int open_count; /* Count of the number of tasks that have */ 109 /* 'opened' the queue for access */ 110 char q_name[MQ_NAME_MAX]; /* Name supplied for queue */ 111 uint q_id; /* Queue Id (index into static list of queues) */ 112 mq_bool_t marked_for_deletion; /* Queue can be deleted once all tasks have */ 113 /* closed it */ 114 Q_CTRL data; /* Data queue (real messages) */ 115 mode_t permissions; /* Permissions granted by creator (ugo, rwx) */ 116 struct notify notify; /* Notification data (empty -> !empty) */ 117 SEM emp_cond; /* For blocking on empty queue */ 118 SEM full_cond; /* For blocking on full queue */ 119 SEM mutex; /* For synchronisation of queue */ 120 } MSG_QUEUE; 121 122 struct _pqueue_access_data { 123 int q_id; 124 int oflags; /* Queue access permissions & blocking spec */ 125 struct sigevent *usp_notifier; 126 }; 127 128 typedef struct _pqueue_access_struct { 129 RT_TASK *this_task; 130 int n_open_pqueues; 131 struct _pqueue_access_data q_access[MQ_OPEN_MAX]; 132 } *QUEUE_CTRL; 133 134 typedef enum { 135 FOR_READ, 136 FOR_WRITE 137 } Q_ACCESS; 138 139 #else /* __cplusplus */ 140 extern "C" { 141 #endif /* !__cplusplus */ 142 143 int __rtai_mq_init(void); 144 145 void __rtai_mq_exit(void); 146 147 RTAI_SYSCALL_MODE mqd_t _mq_open(char *mq_name, int oflags, mode_t permissions, struct mq_attr *mq_attr, long space); 148 static inline mqd_t mq_open(char *mq_name, int oflags, mode_t permissions, struct mq_attr *mq_attr) 149 { 150 return _mq_open(mq_name, oflags, permissions, mq_attr, 0); 151 } 152 153 RTAI_SYSCALL_MODE size_t _mq_receive(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio, int space); 154 static inline size_t mq_receive(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio) 155 { 156 return _mq_receive(mq, msg_buffer, buflen, msgprio, 1); 157 } 158 159 RTAI_SYSCALL_MODE int _mq_send(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio, int space); 160 static inline int mq_send(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio) 161 { 162 return _mq_send(mq, msg, msglen, msgprio, 1); 163 } 164 165 RTAI_SYSCALL_MODE int mq_close(mqd_t mq); 166 167 RTAI_SYSCALL_MODE int mq_getattr(mqd_t mq, struct mq_attr *attrbuf); 168 169 RTAI_SYSCALL_MODE int mq_setattr(mqd_t mq, const struct mq_attr *new_attrs, struct mq_attr *old_attrs); 170 171 RTAI_SYSCALL_MODE int _mq_notify(mqd_t mq, RT_TASK *task, long space, long rem, const struct sigevent *notification); 172 static inline int mq_notify(mqd_t mq, const struct sigevent *notification) 173 { 174 return _mq_notify(mq, rt_whoami(), 0, (notification ? 0 : 1), notification ); 175 } 176 177 RTAI_SYSCALL_MODE int mq_unlink(char *mq_name); 178 179 RTAI_SYSCALL_MODE size_t _mq_timedreceive(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio, const struct timespec *abstime, int space); 180 static inline size_t mq_timedreceive(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio, const struct timespec *abstime) 181 { 182 return _mq_timedreceive(mq, msg_buffer, buflen, msgprio, abstime, 1); 183 } 184 185 RTAI_SYSCALL_MODE int _mq_timedsend(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio, const struct timespec *abstime, int space); 186 static inline int mq_timedsend(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio, const struct timespec *abstime) 187 { 188 return _mq_timedsend(mq, msg, msglen, msgprio, abstime, 1); 189 } 190 191 #ifdef __cplusplus 192 } 193 #endif /* __cplusplus */ 194 195 #else /* !__KERNEL__ */ 196 197 #include <errno.h> 198 #include <signal.h> 199 #include <rtai_lxrt.h> 200 #include <rtai_signal.h> 201 #include <rtai_posix.h> 202 203 #define MQIDX 0 204 205 typedef int mqd_t; 206 207 #ifdef __cplusplus 208 extern "C" { 209 #endif /* __cplusplus */ 210 211 struct suprt_fun_arg { mqd_t mq; RT_TASK *task; unsigned long cpuid; pthread_t self; }; 212 213 #ifndef __SIGNAL_SUPPORT_FUN_PMQ__ 214 #define __SIGNAL_SUPPORT_FUN_PMQ__ 215 216 static void signal_suprt_fun_mq(struct suprt_fun_arg *fun_arg) 217 { 218 struct sigtsk_t { RT_TASK *sigtask; RT_TASK *task; }; 219 struct suprt_fun_arg arg = *fun_arg; 220 struct sigreq_t { RT_TASK *sigtask; RT_TASK *task; long signal;} sigreq = {NULL, arg.task, (arg.mq + MAXSIGNALS)}; 221 struct sigevent notification; 222 223 if ((sigreq.sigtask = rt_thread_init(rt_get_name(0), SIGNAL_TASK_INIPRIO, 0, SCHED_FIFO, 1 << arg.cpuid))) { 224 if (!rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(struct sigreq_t), RT_SIGNAL_REQUEST, &sigreq).i[LOW]) { 225 struct arg_reg { mqd_t mq; RT_TASK *task; struct sigevent *usp_notification;} arg_reg = {arg.mq, arg.task, ¬ification}; 226 rtai_lxrt(MQIDX, sizeof(struct arg_reg), MQ_REG_USP_NOTIFIER, &arg_reg); 227 mlockall(MCL_CURRENT | MCL_FUTURE); 228 rt_make_hard_real_time(); 229 while (rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(struct sigtsk_t), RT_SIGNAL_WAITSIG, &sigreq).i[LOW]) { 230 if (notification.sigev_notify == SIGEV_THREAD) { 231 notification._sigev_un._sigev_thread._function((sigval_t)notification.sigev_value.sival_int); 232 } else if (notification.sigev_notify == SIGEV_SIGNAL) { 233 pthread_kill((pthread_t)arg.self, notification.sigev_signo); 234 } 235 } 236 rt_make_soft_real_time(); 237 } 238 rt_task_delete(sigreq.sigtask); 239 } 240 } 241 242 #endif 243 244 RTAI_PROTO(int, rt_request_signal_mq, (mqd_t mq)) 245 { 246 struct suprt_fun_arg { mqd_t mq; RT_TASK *task; unsigned long cpuid; pthread_t self;} arg = { mq, NULL, 0, pthread_self() }; 247 arg.cpuid = rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(void *), RT_SIGNAL_HELPER, (void *)&arg.task).i[LOW]; 248 arg.task = rt_buddy(); 249 if (rt_thread_create(signal_suprt_fun_mq, &arg, SIGNAL_TASK_STACK_SIZE)) { 250 int ret; 251 ret = rtai_lxrt(RTAI_SIGNALS_IDX, sizeof(RT_TASK *), RT_SIGNAL_HELPER, &arg.task).i[LOW]; 252 return ret; 253 } 254 return -1; 255 } 256 257 258 RTAI_PROTO(mqd_t, mq_open,(char *mq_name, int oflags, mode_t permissions, struct mq_attr *mq_attr)) 259 { 260 mqd_t ret; 261 struct {char *mq_name; long oflags; long permissions; struct mq_attr *mq_attr; long namesize, attrsize; long space; } arg = { mq_name, oflags, permissions, mq_attr, strlen(mq_name) + 1, sizeof(struct mq_attr), 1 }; 262 if ((ret = (mqd_t)rtai_lxrt(MQIDX, SIZARG, MQ_OPEN, &arg).i[LOW]) >= 0) { 263 // Prepare notify task 264 if (oflags & O_NOTIFY_NP) { 265 rt_request_signal_mq (ret); 266 } 267 return ret; 268 } 269 errno = -ret; 270 return -1; 271 } 272 273 RTAI_PROTO(size_t, mq_receive,(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio)) 274 { 275 int oldtype, ret; 276 struct { long mq; char *msg_buffer; long buflen; unsigned int *msgprio; long space; } arg = { mq, msg_buffer, buflen, msgprio, 0 }; 277 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); 278 pthread_testcancel(); 279 ret = (size_t)rtai_lxrt(MQIDX, SIZARG, MQ_RECEIVE, &arg).i[LOW]; 280 pthread_testcancel(); 281 pthread_setcanceltype(oldtype, NULL); 282 if (ret >= 0) { 283 return ret; 284 } 285 errno = -ret; 286 return -1; 287 } 288 289 RTAI_PROTO(int, mq_send,(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio)) 290 { 291 int oldtype, ret; 292 struct { long mq; const char *msg; long msglen; unsigned long msgprio; long space; } arg = { mq, msg, msglen, msgprio, 0 }; 293 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); 294 pthread_testcancel(); 295 ret = rtai_lxrt(MQIDX, SIZARG, MQ_SEND, &arg).i[LOW]; 296 pthread_testcancel(); 297 pthread_setcanceltype(oldtype, NULL); 298 if (ret >= 0) { 299 return ret; 300 } 301 errno = -ret; 302 return -1; 303 } 304 305 RTAI_PROTO(int, mq_close,(mqd_t mq)) 306 { 307 int ret; 308 struct { long mq; } arg = { mq }; 309 if ((ret = rtai_lxrt(MQIDX, SIZARG, MQ_CLOSE, &arg).i[LOW]) >= 0) { 310 return ret; 311 } 312 errno = -ret; 313 return -1; 314 } 315 316 RTAI_PROTO(int, mq_getattr,(mqd_t mq, struct mq_attr *attrbuf)) 317 { 318 int ret; 319 struct { long mq; struct mq_attr *attrbuf; long attrsize; } arg = { mq, attrbuf, sizeof(struct mq_attr) }; 320 if ((ret = rtai_lxrt(MQIDX, SIZARG, MQ_GETATTR, &arg).i[LOW]) >= 0) { 321 return ret; 322 } 323 errno = -ret; 324 return -1; 325 } 326 327 RTAI_PROTO(int, mq_setattr,(mqd_t mq, const struct mq_attr *new_attrs, struct mq_attr *old_attrs)) 328 { 329 int ret; 330 struct { long mq; const struct mq_attr *new_attrs; struct mq_attr *old_attrs; long attrsize; } arg = { mq, new_attrs, old_attrs, sizeof(struct mq_attr) }; 331 if ((ret = rtai_lxrt(MQIDX, SIZARG, MQ_SETATTR, &arg).i[LOW]) >= 0) { 332 return ret; 333 } 334 errno = -ret; 335 return -1; 336 } 337 338 RTAI_PROTO(int, mq_notify,(mqd_t mq, const struct sigevent *notification)) 339 { 340 int ret; 341 struct { long mq; RT_TASK* task; long space; long rem; const struct sigevent *notification; long size;} arg = { mq, rt_buddy(), 1, (notification ? 0 : 1), notification, sizeof(struct sigevent) }; 342 if ((ret = rtai_lxrt(MQIDX, SIZARG, MQ_NOTIFY, &arg).i[LOW]) >= 0) { 343 if (ret == O_NOTIFY_NP) { 344 rt_request_signal_mq (mq); 345 ret = 0; 346 } 347 return ret; 348 } 349 errno = -ret; 350 return -1; 351 } 352 353 RTAI_PROTO(int, mq_unlink,(char *mq_name)) 354 { 355 int ret; 356 struct { char *mq_name; long size; } arg = { mq_name, strlen(mq_name) + 1}; 357 if ((ret = rtai_lxrt(MQIDX, SIZARG, MQ_UNLINK, &arg).i[LOW]) >= 0) { 358 return ret; 359 } 360 errno = -ret; 361 return -1; 362 } 363 364 RTAI_PROTO(size_t, mq_timedreceive,(mqd_t mq, char *msg_buffer, size_t buflen, unsigned int *msgprio, const struct timespec *abstime)) 365 { 366 int oldtype, ret; 367 struct { long mq; char *msg_buffer; long buflen; unsigned int *msgprio; const struct timespec *abstime; long space; } arg = { mq, msg_buffer, buflen, msgprio, abstime, 0 }; 368 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); 369 pthread_testcancel(); 370 ret = (size_t)rtai_lxrt(MQIDX, SIZARG, MQ_TIMEDRECEIVE, &arg).i[LOW]; 371 pthread_testcancel(); 372 pthread_setcanceltype(oldtype, NULL); 373 if (ret >= 0) { 374 return ret; 375 } 376 errno = -ret; 377 return -1; 378 } 379 380 RTAI_PROTO(int, mq_timedsend,(mqd_t mq, const char *msg, size_t msglen, unsigned int msgprio, const struct timespec *abstime)) 381 { 382 int oldtype, ret; 383 struct { long mq; const char *msg; long msglen; unsigned long msgprio; const struct timespec *abstime; long space; } arg = { mq, msg, msglen, msgprio, abstime, 0 }; 384 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); 385 pthread_testcancel(); 386 ret = rtai_lxrt(MQIDX, SIZARG, MQ_TIMEDSEND, &arg).i[LOW]; 387 pthread_testcancel(); 388 pthread_setcanceltype(oldtype, NULL); 389 if (ret >= 0) { 390 return ret; 391 } 392 errno = -ret; 393 return -1; 394 } 395 396 #ifdef __cplusplus 397 } 398 #endif /* __cplusplus */ 399 400 #endif /* __KERNEL__ */ 401 402 #endif /* !_RTAI_MQ_H */