RTS API Documentation  1.10.11
Data Structures | Macros | Typedefs | Functions
switch_apr_queue.c File Reference
#include <switch.h>
#include <fspr.h>
#include <fspr_thread_mutex.h>
#include <fspr_thread_cond.h>
+ Include dependency graph for switch_apr_queue.c:

Go to the source code of this file.

Data Structures

struct  switch_apr_queue_t
 

Macros

#define Q_DBG(x, y)
 
#define apr_queue_full(queue)   ((queue)->nelts == (queue)->bounds)
 
#define apr_queue_empty(queue)   ((queue)->nelts == 0)
 

Typedefs

typedef struct switch_apr_queue_t switch_apr_queue_t
 

Functions

static fspr_status_t queue_destroy (void *data)
 
fspr_status_t switch_apr_queue_create (switch_apr_queue_t **q, unsigned int queue_capacity, fspr_pool_t *a)
 
fspr_status_t switch_apr_queue_push (switch_apr_queue_t *queue, void *data)
 
fspr_status_t switch_apr_queue_trypush (switch_apr_queue_t *queue, void *data)
 
unsigned int switch_apr_queue_size (switch_apr_queue_t *queue)
 
fspr_status_t switch_apr_queue_pop (switch_apr_queue_t *queue, void **data)
 
fspr_status_t switch_apr_queue_pop_timeout (switch_apr_queue_t *queue, void **data, fspr_interval_time_t timeout)
 
fspr_status_t switch_apr_queue_trypop (switch_apr_queue_t *queue, void **data)
 
fspr_status_t switch_apr_queue_interrupt_all (switch_apr_queue_t *queue)
 
fspr_status_t switch_apr_queue_term (switch_apr_queue_t *queue)
 

Macro Definition Documentation

◆ apr_queue_empty

#define apr_queue_empty (   queue)    ((queue)->nelts == 0)

Detects when the switch_apr_queue_t is empty. This utility function is expected to be called from within critical sections, and is not threadsafe.

Definition at line 66 of file switch_apr_queue.c.

Referenced by switch_apr_queue_pop(), switch_apr_queue_pop_timeout(), and switch_apr_queue_trypop().

◆ apr_queue_full

#define apr_queue_full (   queue)    ((queue)->nelts == (queue)->bounds)

Detects when the switch_apr_queue_t is full. This utility function is expected to be called from within critical sections, and is not threadsafe.

Definition at line 60 of file switch_apr_queue.c.

Referenced by switch_apr_queue_push(), and switch_apr_queue_trypush().

◆ Q_DBG

#define Q_DBG (   x,
 
)

Typedef Documentation

◆ switch_apr_queue_t

Definition at line 42 of file switch_apr_queue.c.

Function Documentation

◆ queue_destroy()

static fspr_status_t queue_destroy ( void *  data)
static

Callback routine that is called to destroy this switch_apr_queue_t when its pool is destroyed.

Definition at line 72 of file switch_apr_queue.c.

References switch_apr_queue_t::data, switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, and switch_apr_queue_t::one_big_mutex.

Referenced by switch_apr_queue_create().

73 {
74  switch_apr_queue_t *queue = data;
75 
76  /* Ignore errors here, we can't do anything about them anyway. */
77 
78  fspr_thread_cond_destroy(queue->not_empty);
79  fspr_thread_cond_destroy(queue->not_full);
80  fspr_thread_mutex_destroy(queue->one_big_mutex);
81 
82  return APR_SUCCESS;
83 }
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
fspr_thread_mutex_t * one_big_mutex

◆ switch_apr_queue_create()

fspr_status_t switch_apr_queue_create ( switch_apr_queue_t **  q,
unsigned int  queue_capacity,
fspr_pool_t *  a 
)

Initialize the switch_apr_queue_t.

Definition at line 88 of file switch_apr_queue.c.

References switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::empty_waiters, switch_apr_queue_t::full_waiters, switch_apr_queue_t::in, memset(), switch_apr_queue_t::nelts, switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, switch_apr_queue_t::out, queue_destroy(), and switch_apr_queue_t::terminated.

Referenced by switch_queue_create().

89 {
90  fspr_status_t rv;
91  switch_apr_queue_t *queue;
92  queue = fspr_palloc(a, sizeof(switch_apr_queue_t));
93  *q = queue;
94 
95  /* nested doesn't work ;( */
96  rv = fspr_thread_mutex_create(&queue->one_big_mutex,
97  APR_THREAD_MUTEX_UNNESTED,
98  a);
99  if (rv != APR_SUCCESS) {
100  return rv;
101  }
102 
103  rv = fspr_thread_cond_create(&queue->not_empty, a);
104  if (rv != APR_SUCCESS) {
105  return rv;
106  }
107 
108  rv = fspr_thread_cond_create(&queue->not_full, a);
109  if (rv != APR_SUCCESS) {
110  return rv;
111  }
112 
113  /* Set all the data in the queue to NULL */
114  queue->data = fspr_palloc(a, queue_capacity * sizeof(void*));
115  if (!queue->data) return APR_ENOMEM;
116  memset(queue->data, 0, queue_capacity * sizeof(void*));
117  queue->bounds = queue_capacity;
118  queue->nelts = 0;
119  queue->in = 0;
120  queue->out = 0;
121  queue->terminated = 0;
122  queue->full_waiters = 0;
123  queue->empty_waiters = 0;
124 
125  fspr_pool_cleanup_register(a, queue, queue_destroy, fspr_pool_cleanup_null);
126 
127  return APR_SUCCESS;
128 }
static fspr_status_t queue_destroy(void *data)
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
fspr_thread_mutex_t * one_big_mutex
unsigned int full_waiters
memset(buf, 0, buflen)
unsigned int empty_waiters

◆ switch_apr_queue_interrupt_all()

fspr_status_t switch_apr_queue_interrupt_all ( switch_apr_queue_t queue)

Definition at line 406 of file switch_apr_queue.c.

References switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, and Q_DBG.

Referenced by switch_apr_queue_term(), and switch_queue_interrupt_all().

407 {
408  fspr_status_t rv;
409  Q_DBG("intr all", queue);
410  if ((rv = fspr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
411  return rv;
412  }
413  fspr_thread_cond_broadcast(queue->not_empty);
414  fspr_thread_cond_broadcast(queue->not_full);
415 
416  if ((rv = fspr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) {
417  return rv;
418  }
419 
420  return APR_SUCCESS;
421 }
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
fspr_thread_mutex_t * one_big_mutex
#define Q_DBG(x, y)

◆ switch_apr_queue_pop()

fspr_status_t switch_apr_queue_pop ( switch_apr_queue_t queue,
void **  data 
)

Retrieves the next item from the queue. If there are no items available, it will block until one becomes available. Once retrieved, the item is placed into the address specified by 'data'.

Definition at line 244 of file switch_apr_queue.c.

References apr_queue_empty, switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::empty_waiters, switch_apr_queue_t::full_waiters, if(), switch_apr_queue_t::nelts, switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, switch_apr_queue_t::out, Q_DBG, and switch_apr_queue_t::terminated.

Referenced by switch_queue_pop().

245 {
246  fspr_status_t rv;
247 
248  if (queue->terminated) {
249  return APR_EOF; /* no more elements ever again */
250  }
251 
252  rv = fspr_thread_mutex_lock(queue->one_big_mutex);
253  if (rv != APR_SUCCESS) {
254  return rv;
255  }
256 
257  /* Keep waiting until we wake up and find that the queue is not empty. */
258  if (apr_queue_empty(queue)) {
259  if (!queue->terminated) {
260  queue->empty_waiters++;
261  rv = fspr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
262  queue->empty_waiters--;
263  if (rv != APR_SUCCESS) {
264  fspr_thread_mutex_unlock(queue->one_big_mutex);
265  return rv;
266  }
267  }
268  /* If we wake up and it's still empty, then we were interrupted */
269  if (apr_queue_empty(queue)) {
270  Q_DBG("queue empty (intr)", queue);
271  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
272  if (rv != APR_SUCCESS) {
273  return rv;
274  }
275  if (queue->terminated) {
276  return APR_EOF; /* no more elements ever again */
277  }
278  else {
279  return APR_EINTR;
280  }
281  }
282  }
283 
284  *data = queue->data[queue->out];
285  queue->nelts--;
286 
287  queue->out = (queue->out + 1) % queue->bounds;
288  if (queue->full_waiters) {
289  Q_DBG("signal !full", queue);
290  rv = fspr_thread_cond_signal(queue->not_full);
291  if (rv != APR_SUCCESS) {
292  fspr_thread_mutex_unlock(queue->one_big_mutex);
293  return rv;
294  }
295  }
296 
297  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
298  return rv;
299 }
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
fspr_thread_mutex_t * one_big_mutex
#define apr_queue_empty(queue)
unsigned int full_waiters
#define Q_DBG(x, y)
unsigned int empty_waiters

◆ switch_apr_queue_pop_timeout()

fspr_status_t switch_apr_queue_pop_timeout ( switch_apr_queue_t queue,
void **  data,
fspr_interval_time_t  timeout 
)

Retrieves the next item from the queue. If there are no items available, it will block until one becomes available, or until timeout is elapsed. Once retrieved, the item is placed into the address specified by'data'.

Definition at line 307 of file switch_apr_queue.c.

References apr_queue_empty, switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::empty_waiters, switch_apr_queue_t::full_waiters, if(), switch_apr_queue_t::nelts, switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, switch_apr_queue_t::out, Q_DBG, and switch_apr_queue_t::terminated.

Referenced by switch_queue_pop_timeout().

308 {
309  fspr_status_t rv;
310 
311  if (queue->terminated) {
312  return APR_EOF; /* no more elements ever again */
313  }
314 
315  rv = fspr_thread_mutex_lock(queue->one_big_mutex);
316  if (rv != APR_SUCCESS) {
317  return rv;
318  }
319 
320  /* Keep waiting until we wake up and find that the queue is not empty. */
321  if (apr_queue_empty(queue)) {
322  if (!queue->terminated) {
323  queue->empty_waiters++;
324  rv = fspr_thread_cond_timedwait(queue->not_empty, queue->one_big_mutex, timeout);
325  queue->empty_waiters--;
326  /* In the event of a timemout, APR_TIMEUP will be returned */
327  if (rv != APR_SUCCESS) {
328  fspr_thread_mutex_unlock(queue->one_big_mutex);
329  return rv;
330  }
331  }
332  /* If we wake up and it's still empty, then we were interrupted */
333  if (apr_queue_empty(queue)) {
334  Q_DBG("queue empty (intr)", queue);
335  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
336  if (rv != APR_SUCCESS) {
337  return rv;
338  }
339  if (queue->terminated) {
340  return APR_EOF; /* no more elements ever again */
341  }
342  else {
343  return APR_EINTR;
344  }
345  }
346  }
347 
348  *data = queue->data[queue->out];
349  queue->nelts--;
350 
351  queue->out = (queue->out + 1) % queue->bounds;
352  if (queue->full_waiters) {
353  Q_DBG("signal !full", queue);
354  rv = fspr_thread_cond_signal(queue->not_full);
355  if (rv != APR_SUCCESS) {
356  fspr_thread_mutex_unlock(queue->one_big_mutex);
357  return rv;
358  }
359  }
360 
361  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
362  return rv;
363 }
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
fspr_thread_mutex_t * one_big_mutex
#define apr_queue_empty(queue)
unsigned int full_waiters
#define Q_DBG(x, y)
unsigned int empty_waiters

◆ switch_apr_queue_push()

fspr_status_t switch_apr_queue_push ( switch_apr_queue_t queue,
void *  data 
)

Push new data onto the queue. Blocks if the queue is full. Once the push operation has completed, it signals other threads waiting in apr_queue_pop() that they may continue consuming sockets.

Definition at line 135 of file switch_apr_queue.c.

References apr_queue_full, switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::empty_waiters, switch_apr_queue_t::full_waiters, if(), switch_apr_queue_t::in, switch_apr_queue_t::nelts, switch_apr_queue_t::not_empty, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, Q_DBG, and switch_apr_queue_t::terminated.

Referenced by switch_queue_push().

136 {
137  fspr_status_t rv;
138 
139  if (queue->terminated) {
140  return APR_EOF; /* no more elements ever again */
141  }
142 
143  rv = fspr_thread_mutex_lock(queue->one_big_mutex);
144  if (rv != APR_SUCCESS) {
145  return rv;
146  }
147 
148  if (apr_queue_full(queue)) {
149  if (!queue->terminated) {
150  queue->full_waiters++;
151  rv = fspr_thread_cond_wait(queue->not_full, queue->one_big_mutex);
152  queue->full_waiters--;
153  if (rv != APR_SUCCESS) {
154  fspr_thread_mutex_unlock(queue->one_big_mutex);
155  return rv;
156  }
157  }
158  /* If we wake up and it's still empty, then we were interrupted */
159  if (apr_queue_full(queue)) {
160  Q_DBG("queue full (intr)", queue);
161  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
162  if (rv != APR_SUCCESS) {
163  return rv;
164  }
165  if (queue->terminated) {
166  return APR_EOF; /* no more elements ever again */
167  }
168  else {
169  return APR_EINTR;
170  }
171  }
172  }
173 
174  queue->data[queue->in] = data;
175  queue->in = (queue->in + 1) % queue->bounds;
176  queue->nelts++;
177 
178  if (queue->empty_waiters) {
179  Q_DBG("sig !empty", queue);
180  rv = fspr_thread_cond_signal(queue->not_empty);
181  if (rv != APR_SUCCESS) {
182  fspr_thread_mutex_unlock(queue->one_big_mutex);
183  return rv;
184  }
185  }
186 
187  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
188  return rv;
189 }
#define apr_queue_full(queue)
fspr_thread_cond_t * not_empty
fspr_thread_cond_t * not_full
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
fspr_thread_mutex_t * one_big_mutex
unsigned int full_waiters
#define Q_DBG(x, y)
unsigned int empty_waiters

◆ switch_apr_queue_size()

unsigned int switch_apr_queue_size ( switch_apr_queue_t queue)

not thread safe

Definition at line 234 of file switch_apr_queue.c.

References switch_apr_queue_t::nelts.

Referenced by switch_queue_size().

234  {
235  return queue->nelts;
236 }

◆ switch_apr_queue_term()

fspr_status_t switch_apr_queue_term ( switch_apr_queue_t queue)

Definition at line 423 of file switch_apr_queue.c.

References switch_apr_queue_t::one_big_mutex, switch_apr_queue_interrupt_all(), and switch_apr_queue_t::terminated.

Referenced by switch_queue_term().

424 {
425  fspr_status_t rv;
426 
427  if ((rv = fspr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
428  return rv;
429  }
430 
431  /* we must hold one_big_mutex when setting this... otherwise,
432  * we could end up setting it and waking everybody up just after a
433  * would-be popper checks it but right before they block
434  */
435  queue->terminated = 1;
436  if ((rv = fspr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) {
437  return rv;
438  }
439  return switch_apr_queue_interrupt_all(queue);
440 }
fspr_status_t switch_apr_queue_interrupt_all(switch_apr_queue_t *queue)
fspr_thread_mutex_t * one_big_mutex

◆ switch_apr_queue_trypop()

fspr_status_t switch_apr_queue_trypop ( switch_apr_queue_t queue,
void **  data 
)

Retrieves the next item from the queue. If there are no items available, return APR_EAGAIN. Once retrieved, the item is placed into the address specified by 'data'.

Definition at line 371 of file switch_apr_queue.c.

References apr_queue_empty, switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::full_waiters, if(), switch_apr_queue_t::nelts, switch_apr_queue_t::not_full, switch_apr_queue_t::one_big_mutex, switch_apr_queue_t::out, Q_DBG, and switch_apr_queue_t::terminated.

Referenced by switch_queue_trypop().

372 {
373  fspr_status_t rv;
374 
375  if (queue->terminated) {
376  return APR_EOF; /* no more elements ever again */
377  }
378 
379  rv = fspr_thread_mutex_lock(queue->one_big_mutex);
380  if (rv != APR_SUCCESS) {
381  return rv;
382  }
383 
384  if (apr_queue_empty(queue)) {
385  fspr_thread_mutex_unlock(queue->one_big_mutex);
386  return APR_EAGAIN;
387  }
388 
389  *data = queue->data[queue->out];
390  queue->nelts--;
391 
392  queue->out = (queue->out + 1) % queue->bounds;
393  if (queue->full_waiters) {
394  Q_DBG("signal !full", queue);
395  rv = fspr_thread_cond_signal(queue->not_full);
396  if (rv != APR_SUCCESS) {
397  fspr_thread_mutex_unlock(queue->one_big_mutex);
398  return rv;
399  }
400  }
401 
402  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
403  return rv;
404 }
fspr_thread_cond_t * not_full
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
fspr_thread_mutex_t * one_big_mutex
#define apr_queue_empty(queue)
unsigned int full_waiters
#define Q_DBG(x, y)

◆ switch_apr_queue_trypush()

fspr_status_t switch_apr_queue_trypush ( switch_apr_queue_t queue,
void *  data 
)

Push new data onto the queue. Blocks if the queue is full. Once the push operation has completed, it signals other threads waiting in apr_queue_pop() that they may continue consuming sockets.

Definition at line 196 of file switch_apr_queue.c.

References apr_queue_full, switch_apr_queue_t::bounds, switch_apr_queue_t::data, switch_apr_queue_t::empty_waiters, if(), switch_apr_queue_t::in, switch_apr_queue_t::nelts, switch_apr_queue_t::not_empty, switch_apr_queue_t::one_big_mutex, Q_DBG, and switch_apr_queue_t::terminated.

Referenced by switch_queue_trypush().

197 {
198  fspr_status_t rv;
199 
200  if (queue->terminated) {
201  return APR_EOF; /* no more elements ever again */
202  }
203 
204  rv = fspr_thread_mutex_lock(queue->one_big_mutex);
205  if (rv != APR_SUCCESS) {
206  return rv;
207  }
208 
209  if (apr_queue_full(queue)) {
210  fspr_thread_mutex_unlock(queue->one_big_mutex);
211  return APR_EAGAIN;
212  }
213 
214  queue->data[queue->in] = data;
215  queue->in = (queue->in + 1) % queue->bounds;
216  queue->nelts++;
217 
218  if (queue->empty_waiters) {
219  Q_DBG("sig !empty", queue);
220  rv = fspr_thread_cond_signal(queue->not_empty);
221  if (rv != APR_SUCCESS) {
222  fspr_thread_mutex_unlock(queue->one_big_mutex);
223  return rv;
224  }
225  }
226 
227  rv = fspr_thread_mutex_unlock(queue->one_big_mutex);
228  return rv;
229 }
#define apr_queue_full(queue)
fspr_thread_cond_t * not_empty
if((uint32_t)(unpack->cur - unpack->buf) > unpack->buflen)
fspr_thread_mutex_t * one_big_mutex
#define Q_DBG(x, y)
unsigned int empty_waiters