/ base / include / rtai_pmq.h
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, &notification};
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 */