--- /dev/null
+#include <sched.h> // for sched_yield
+#include "bits/callback.h" // for Transformer
+#include "queue.h"
+
+void queue_ini(Queue *queue)
+{
+ list_ini(&queue->lst);
+ queue->cnl = queue->fin = 0;
+ pthread_cond_init(&queue->cnd, NULL);
+ pthread_mutex_init(&queue->mtx, NULL);
+}
+
+void queue_dst(Queue *queue)
+{
+ pthread_cond_destroy(&queue->cnd);
+ pthread_mutex_destroy(&queue->mtx);
+}
+
+void queue_clr(Queue *queue, void *iter, void *arg, void *trans)
+{
+ list_clr(&queue->lst, iter, arg, trans);
+}
+
+#define ENQUEUE(queue_fun, list_fun) \
+ bool queue_fun(Queue *queue, void *dat) \
+ { \
+ bool success = false; \
+ \
+ pthread_mutex_lock(&queue->mtx); \
+ if (!queue->fin) { \
+ success = true; \
+ list_fun(&queue->lst, dat); \
+ pthread_cond_signal(&queue->cnd); \
+ } \
+ pthread_mutex_unlock(&queue->mtx); \
+ \
+ return success; \
+ }
+
+ENQUEUE(queue_enq, list_apd)
+ENQUEUE(queue_ppd, list_ppd)
+
+#undef ENQUEUE
+
+void *queue_deq(Queue *queue, void *trans)
+{
+ void *dat = NULL;
+
+ pthread_mutex_lock(&queue->mtx);
+ while (!queue->cnl && !dat) {
+ ListNode **node = &queue->lst.fst;
+ if (*node) {
+ dat = (*node)->dat;
+ list_nrm(&queue->lst, node);
+
+ if (trans)
+ dat = ((Transformer) trans)(dat);
+ } else {
+ pthread_cond_wait(&queue->cnd, &queue->mtx);
+ }
+ }
+ pthread_mutex_unlock(&queue->mtx);
+
+ return dat;
+}
+
+void queue_cnl(Queue *queue)
+{
+ pthread_mutex_lock(&queue->mtx);
+ queue->cnl = 1;
+ pthread_cond_broadcast(&queue->cnd);
+ pthread_mutex_unlock(&queue->mtx);
+}
+
+void queue_fin(Queue *queue)
+{
+ pthread_mutex_lock(&queue->mtx);
+ queue->fin = 1;
+ pthread_mutex_unlock(&queue->mtx);
+
+ for (;;) {
+ pthread_mutex_lock(&queue->mtx);
+ ListNode *node = queue->lst.fst;
+ pthread_mutex_unlock(&queue->mtx);
+
+ if (node)
+ sched_yield();
+ else
+ break;
+ }
+}