dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_queue.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  */
25 
26 #include <pthread.h>
27 #include <stdlib.h>
28 
29 #include <circqueue.h>
30 
31 #include <pios_queue.h>
32 #include <pios_thread.h>
33 
34 struct pios_queue {
35 #define QUEUE_MAGIC 75657551 /* 'Queu' */
36  uint32_t magic;
37 
38  pthread_mutex_t mutex;
39  pthread_cond_t cond;
40 
41  uint16_t item_size;
42  uint16_t q_len;
43 
45 };
46 
47 struct pios_queue *PIOS_Queue_Create(size_t queue_length, size_t item_size)
48 {
49  struct pios_queue *q = PIOS_malloc(sizeof(*q));
50 
51  if (!q) {
52  return NULL;
53  }
54 
55  pthread_mutexattr_t attr;
56 
57  if (pthread_mutexattr_init(&attr)) {
58  abort();
59  }
60 
61  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
62 
63  if (pthread_mutex_init(&q->mutex, &attr)) {
64  abort();
65  }
66 
67  if (pthread_cond_init(&q->cond, NULL)) {
68  abort();
69  }
70 
71  q->item_size = item_size;
72  q->q_len = queue_length;
73 
74  q->queue = circ_queue_new(item_size, queue_length+1);
75 
76  if (!q->queue) {
77  pthread_mutex_destroy(&q->mutex);
78  pthread_cond_destroy(&q->cond);
79 
80  PIOS_free(q);
81  return NULL;
82  }
83 
84  q->magic = QUEUE_MAGIC;
85 
86  return q;
87 }
88 
89 void PIOS_Queue_Delete(struct pios_queue *queuep)
90 {
91  PIOS_Assert(queuep->magic == QUEUE_MAGIC);
92 
93  pthread_mutex_destroy(&queuep->mutex);
94  pthread_cond_destroy(&queuep->cond);
95 
96  /* XXX free up the queue buf */
97 
98  free(queuep);
99 }
100 
101 static bool PIOS_Queue_Send_Impl(struct pios_queue *queuep,
102  const void *itemp, uint32_t timeout_ms)
103 {
104  PIOS_Assert(queuep->magic == QUEUE_MAGIC);
105 
106  struct timespec abstime;
107 
108  if (timeout_ms != PIOS_QUEUE_TIMEOUT_MAX) {
109  clock_gettime(CLOCK_REALTIME, &abstime);
110 
111  abstime.tv_nsec += (timeout_ms % 1000) * 1000000;
112  abstime.tv_sec += timeout_ms / 1000;
113 
114  if (abstime.tv_nsec > 1000000000) {
115  abstime.tv_nsec -= 1000000000;
116  abstime.tv_sec += 1;
117  }
118  }
119 
120  pthread_mutex_lock(&queuep->mutex);
121 
122  while (!circ_queue_write_data(queuep->queue, itemp, 1)) {
123  if (timeout_ms != PIOS_QUEUE_TIMEOUT_MAX) {
124  if (pthread_cond_timedwait(&queuep->cond,
125  &queuep->mutex, &abstime)) {
126  pthread_mutex_unlock(&queuep->mutex);
127  return false;
128  }
129  } else {
130  pthread_cond_wait(&queuep->cond, &queuep->mutex);
131  }
132  }
133 
134  pthread_cond_broadcast(&queuep->cond);
135 
136  pthread_mutex_unlock(&queuep->mutex);
137 
138  return true;
139 }
140 
141 bool PIOS_Queue_Send(struct pios_queue *queuep,
142  const void *itemp, uint32_t timeout_ms)
143 {
144  PIOS_Assert(queuep->magic == QUEUE_MAGIC);
145 
147  uint32_t start = PIOS_Thread_Systime();
148 
149  do {
150  if (PIOS_Queue_Send_Impl(queuep, itemp, 1)) {
151  return true;
152  }
153  } while ((timeout_ms == PIOS_QUEUE_TIMEOUT_MAX) ||
155  timeout_ms)));
156 
157  return false;
158  }
159 
160  return PIOS_Queue_Send_Impl(queuep, itemp, timeout_ms);
161 }
162 
164  const void *itemp, bool *wokenp)
165 {
166  bool ret = PIOS_Queue_Send(queuep, itemp, 0);
167 
168  if (ret && (wokenp)) {
169  *wokenp = true;
170  }
171 
172  return ret;
173 }
174 
175 static bool PIOS_Queue_Receive_Impl(struct pios_queue *queuep,
176  void *itemp, uint32_t timeout_ms)
177 {
178  struct timespec abstime;
179 
180  if (timeout_ms != PIOS_QUEUE_TIMEOUT_MAX) {
181  clock_gettime(CLOCK_REALTIME, &abstime);
182 
183  abstime.tv_nsec += (timeout_ms % 1000) * 1000000;
184  abstime.tv_sec += timeout_ms / 1000;
185 
186  if (abstime.tv_nsec > 1000000000) {
187  abstime.tv_nsec -= 1000000000;
188  abstime.tv_sec += 1;
189  }
190  }
191 
192  pthread_mutex_lock(&queuep->mutex);
193 
194  while (!circ_queue_read_data(queuep->queue, itemp, 1)) {
195  if (timeout_ms != PIOS_QUEUE_TIMEOUT_MAX) {
196  if (pthread_cond_timedwait(&queuep->cond,
197  &queuep->mutex, &abstime)) {
198  pthread_mutex_unlock(&queuep->mutex);
199  return false;
200  }
201  } else {
202  pthread_cond_wait(&queuep->cond, &queuep->mutex);
203  }
204  }
205 
206  pthread_cond_broadcast(&queuep->cond);
207 
208  pthread_mutex_unlock(&queuep->mutex);
209 
210  return true;
211 }
212 
213 bool PIOS_Queue_Receive(struct pios_queue *queuep,
214  void *itemp, uint32_t timeout_ms)
215 {
216  PIOS_Assert(queuep->magic == QUEUE_MAGIC);
217 
219  uint32_t start = PIOS_Thread_Systime();
220 
221  do {
222  if (PIOS_Queue_Receive_Impl(queuep, itemp, 1)) {
223  return true;
224  }
225  } while ((timeout_ms == PIOS_QUEUE_TIMEOUT_MAX) ||
227  timeout_ms)));
228 
229  return false;
230  }
231 
232  return PIOS_Queue_Receive_Impl(queuep, itemp, timeout_ms);
233 }
234 
235 size_t PIOS_Queue_GetItemSize(struct pios_queue *queuep)
236 {
237  PIOS_Assert(queuep);
238  return queuep->item_size;
239 }
240 
Definition: common.h:35
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
static bool PIOS_Queue_Send_Impl(struct pios_queue *queuep, const void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:101
int clock_gettime(clockid_t clk_id, struct timespec *t)
uint16_t circ_queue_read_data(circ_queue_t q, void *buf, uint16_t num)
Definition: circqueue.c:331
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
bool PIOS_Queue_Send_FromISR(struct pios_queue *queuep, const void *itemp, bool *wokenp)
Definition: pios_queue.c:163
static bool PIOS_Queue_Receive_Impl(struct pios_queue *queuep, void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:175
uint16_t circ_queue_write_data(circ_queue_t q, const void *buf, uint16_t num)
Definition: circqueue.c:302
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_Queue_Send(struct pios_queue *queuep, const void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:141
bool PIOS_Queue_Receive(struct pios_queue *queuep, void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:213
void PIOS_Queue_Delete(struct pios_queue *queuep)
Definition: pios_queue.c:89
circ_queue_t circ_queue_new(uint16_t elem_size, uint16_t num_elem)
Definition: circqueue.c:48
circ_queue_t queue
Definition: pios_queue.c:44
pthread_mutex_t mutex
Definition: pios_queue.c:38
uint16_t item_size
Definition: pios_queue.c:41
#define PIOS_QUEUE_TIMEOUT_MAX
Definition: pios_queue.h:30
size_t PIOS_Queue_GetItemSize(struct pios_queue *queuep)
Definition: pios_queue.c:235
bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
Determine if a period has elapsed since a datum.
Definition: pios_thread.c:281
Public header for 1 reader, 1 writer circular queue.
pthread_cond_t cond
Definition: pios_queue.c:39
void PIOS_free(void *buf)
Definition: pios_heap.c:174
uint32_t magic
Definition: pios_queue.c:36
#define CLOCK_REALTIME
Definition: pios_posix.h:63
#define PIOS_Assert(test)
Definition: pios_debug.h:52
uint16_t q_len
Definition: pios_queue.c:42
#define QUEUE_MAGIC
Definition: pios_queue.c:35
bool PIOS_Thread_FakeClock_IsActive(void)
Definition: pios_thread.c:207