#include "common.h"
#include "plugin.h"
#include "utils_cmd_putval.h"
+#include "utils_deq.h"
#include "utils_format_graphite.h"
#include "utils_format_json.h"
#include "utils_random.h"
-#include "utils_deq.h"
-#include <proton/connection.h>
#include <proton/condition.h>
+#include <proton/connection.h>
#include <proton/delivery.h>
#include <proton/link.h>
#include <proton/message.h>
#include <proton/session.h>
#include <proton/transport.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#define BUFSIZE 8192
#define AMQP1_FORMAT_JSON 0
typedef struct amqp1_config_transport_t {
DEQ_LINKS(struct amqp1_config_transport_t);
- char *name;
- char *host;
- char *port;
- char *user;
- char *password;
- char *address;
+ char *name;
+ char *host;
+ char *port;
+ char *user;
+ char *password;
+ char *address;
} amqp1_config_transport_t;
typedef struct amqp1_config_instance_t {
DEQ_LINKS(struct amqp1_config_instance_t);
- char *name;
- _Bool notify;
- uint8_t format;
- unsigned int graphite_flags;
- _Bool store_rates;
- char *prefix;
- char *postfix;
- char escape_char;
- _Bool pre_settle;
- char send_to[128];
+ char *name;
+ _Bool notify;
+ uint8_t format;
+ unsigned int graphite_flags;
+ _Bool store_rates;
+ char *prefix;
+ char *postfix;
+ char escape_char;
+ _Bool pre_settle;
+ char send_to[128];
} amqp1_config_instance_t;
DEQ_DECLARE(amqp1_config_instance_t, amqp1_config_instance_list_t);
/*
* Globals
*/
-pn_connection_t *conn = NULL;
-pn_session_t *ssn = NULL;
-pn_link_t *sender = NULL;
-pn_proactor_t *proactor = NULL;
-pthread_mutex_t send_lock;
-cd_message_list_t out_messages;
-uint64_t cd_tag = 1;
-uint64_t acknowledged = 0;
+pn_connection_t *conn = NULL;
+pn_session_t *ssn = NULL;
+pn_link_t *sender = NULL;
+pn_proactor_t *proactor = NULL;
+pthread_mutex_t send_lock;
+cd_message_list_t out_messages;
+uint64_t cd_tag = 1;
+uint64_t acknowledged = 0;
amqp1_config_transport_t *transport = NULL;
-bool finished = false;
+bool finished = false;
-static int event_thread_running = 0;
+static int event_thread_running = 0;
static pthread_t event_thread_id;
/*
* Functions
*/
-static void cd_message_free(cd_message_t *cdm)
-{
+static void cd_message_free(cd_message_t *cdm) {
if (cdm->mbuf.start) {
free((void *)cdm->mbuf.start);
}
static int amqp1_send_out_messages(pn_link_t *link) /* {{{ */
{
- uint64_t dtag;
+ uint64_t dtag;
cd_message_list_t to_send;
- cd_message_t *cdm;
- int link_credit = pn_link_credit(link);
- int event_count = 0;
- pn_delivery_t *dlv;
+ cd_message_t *cdm;
+ int link_credit = pn_link_credit(link);
+ int event_count = 0;
+ pn_delivery_t *dlv;
DEQ_INIT(to_send);
while (cdm) {
DEQ_REMOVE_HEAD(to_send);
dtag++;
- dlv = pn_delivery(link, pn_dtag((const char*)&dtag, sizeof(dtag)));
+ dlv = pn_delivery(link, pn_dtag((const char *)&dtag, sizeof(dtag)));
pn_link_send(link, cdm->mbuf.start, cdm->mbuf.size);
pn_link_advance(link);
if (cdm->instance->pre_settle == true) {
static void check_condition(pn_event_t *e, pn_condition_t *cond) /* {{{ */
{
if (pn_condition_is_set(cond)) {
- ERROR("amqp1 plugin: %s: %s: %s",
- pn_event_type_name(pn_event_type(e)),
- pn_condition_get_name(cond),
- pn_condition_get_description(cond));
+ ERROR("amqp1 plugin: %s: %s: %s", pn_event_type_name(pn_event_type(e)),
+ pn_condition_get_name(cond), pn_condition_get_description(cond));
pn_connection_close(pn_event_connection(e));
conn = NULL;
}
switch (pn_event_type(event)) {
- case PN_CONNECTION_INIT:{
+ case PN_CONNECTION_INIT: {
conn = pn_event_connection(event);
pn_connection_set_container(conn, transport->address);
pn_connection_open(conn);
case PN_DELIVERY: {
/* acknowledgement from peer that a message was delivered */
- pn_delivery_t * dlv = pn_event_delivery(event);
+ pn_delivery_t *dlv = pn_event_delivery(event);
if (pn_delivery_remote_state(dlv) == PN_ACCEPTED) {
acknowledged++;
}
}
case PN_CONNECTION_REMOTE_CLOSE: {
- check_condition(event, pn_session_remote_condition(pn_event_session(event)));
+ check_condition(event,
+ pn_session_remote_condition(pn_event_session(event)));
pn_connection_close(pn_event_connection(event));
break;
}
case PN_SESSION_REMOTE_CLOSE: {
- check_condition(event, pn_session_remote_condition(pn_event_session(event)));
+ check_condition(event,
+ pn_session_remote_condition(pn_event_session(event)));
pn_connection_close(pn_event_connection(event));
break;
}
return false;
}
- default: break;
+ default:
+ break;
}
return true;
} /* }}} bool handle */
return NULL;
} /* }}} void event_thread */
-static void encqueue(cd_message_t *cdm, amqp1_config_instance_t *instance ) /* {{{ */
+static void encqueue(cd_message_t *cdm,
+ amqp1_config_instance_t *instance) /* {{{ */
{
- size_t bufsize = BUFSIZE;
- pn_data_t *body;
+ size_t bufsize = BUFSIZE;
+ pn_data_t *body;
pn_message_t *message;
/* encode message */
} /* }}} void encqueue */
-static int amqp1_notify(notification_t const *n, user_data_t *user_data) /* {{{ */
+static int amqp1_notify(notification_t const *n,
+ user_data_t *user_data) /* {{{ */
{
amqp1_config_instance_t *instance;
- int status = 0;
- size_t bfree = BUFSIZE;
- size_t bfill = 0;
+ int status = 0;
+ size_t bfree = BUFSIZE;
+ size_t bfill = 0;
cd_message_t *cdm;
- size_t bufsize = BUFSIZE;
+ size_t bufsize = BUFSIZE;
if ((n == NULL) || (user_data == NULL))
return EINVAL;
cdm = NEW(cd_message_t);
DEQ_ITEM_INIT(cdm);
- cdm->mbuf = pn_bytes(bufsize, (char *) malloc(bufsize));
+ cdm->mbuf = pn_bytes(bufsize, (char *)malloc(bufsize));
cdm->instance = instance;
switch (instance->format) {
} /* }}} int amqp1_notify */
static int amqp1_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
- user_data_t *user_data)
-{
+ user_data_t *user_data) {
amqp1_config_instance_t *instance;
- int status = 0;
- size_t bfree = BUFSIZE;
- size_t bfill = 0;
+ int status = 0;
+ size_t bfree = BUFSIZE;
+ size_t bfill = 0;
cd_message_t *cdm;
- size_t bufsize = BUFSIZE;
+ size_t bufsize = BUFSIZE;
- if ((ds == NULL) || (vl == NULL) || (transport == NULL) || (user_data == NULL))
+ if ((ds == NULL) || (vl == NULL) || (transport == NULL) ||
+ (user_data == NULL))
return EINVAL;
instance = user_data->data;
cdm = NEW(cd_message_t);
DEQ_ITEM_INIT(cdm);
- cdm->mbuf = pn_bytes(bufsize, (char *) malloc(bufsize));
+ cdm->mbuf = pn_bytes(bufsize, (char *)malloc(bufsize));
cdm->instance = instance;
switch (instance->format) {
case AMQP1_FORMAT_JSON:
format_json_initialize((char *)cdm->mbuf.start, &bfill, &bfree);
format_json_value_list((char *)cdm->mbuf.start, &bfill, &bfree, ds, vl,
- instance->store_rates);
+ instance->store_rates);
format_json_finalize((char *)cdm->mbuf.start, &bfill, &bfree);
cdm->mbuf.size = strlen(cdm->mbuf.start);
break;
case AMQP1_FORMAT_GRAPHITE:
- status =
- format_graphite((char *)cdm->mbuf.start, bufsize, ds, vl, instance->prefix,
- instance->postfix, instance->escape_char, instance->graphite_flags);
+ status = format_graphite((char *)cdm->mbuf.start, bufsize, ds, vl,
+ instance->prefix, instance->postfix,
+ instance->escape_char, instance->graphite_flags);
if (status != 0) {
ERROR("amqp1 plugin: format_graphite failed with status %i.", status);
return status;
static int amqp1_config_instance(oconfig_item_t *ci) /* {{{ */
{
- int status=0;
+ int status = 0;
char *key = NULL;
amqp1_config_instance_t *instance;
else if (strcasecmp("Format", child->key) == 0) {
status = cf_util_get_string(child, &key);
if (status != 0)
- return status;
- /* TODO: goto errout */
+ return status;
+ /* TODO: goto errout */
// goto errout;
assert(key != NULL);
if (strcasecmp(key, "Command") == 0) {
WARNING("amqp1 plugin: Invalid format string: %s", key);
}
sfree(key);
- }
- else if (strcasecmp("StoreRates", child->key) == 0)
+ } else if (strcasecmp("StoreRates", child->key) == 0)
status = cf_util_get_boolean(child, &instance->store_rates);
else if (strcasecmp("GraphiteSeparateInstances", child->key) == 0)
status = cf_util_get_flag(child, &instance->graphite_flags,
"only one character. Others will be ignored.");
instance->escape_char = tmp_buff[0];
sfree(tmp_buff);
- }
- else
+ } else
WARNING("amqp1 plugin: Ignoring unknown "
"instance configuration option "
- "\%s\".", child->key);
+ "\%s\".",
+ child->key);
if (status != 0)
break;
}
char tpname[128];
snprintf(tpname, sizeof(tpname), "amqp1/%s", instance->name);
snprintf(instance->send_to, sizeof(instance->send_to), "/%s/%s",
- transport->address,instance->name);
+ transport->address, instance->name);
if (instance->notify == true) {
- status = plugin_register_notification(tpname, amqp1_notify, &(user_data_t) {
- .data = instance, .free_func = amqp1_config_instance_free, });
+ status = plugin_register_notification(
+ tpname, amqp1_notify,
+ &(user_data_t){
+ .data = instance, .free_func = amqp1_config_instance_free,
+ });
} else {
- status = plugin_register_write(tpname, amqp1_write, &(user_data_t) {
- .data = instance, .free_func = amqp1_config_instance_free, });
+ status = plugin_register_write(
+ tpname, amqp1_write,
+ &(user_data_t){
+ .data = instance, .free_func = amqp1_config_instance_free,
+ });
}
if (status != 0) {
static int amqp1_config_transport(oconfig_item_t *ci) /* {{{ */
{
- int status=0;
+ int status = 0;
transport = calloc(1, sizeof(*transport));
if (transport == NULL) {
status = cf_util_get_string(child, &transport->password);
else if (strcasecmp("Address", child->key) == 0)
status = cf_util_get_string(child, &transport->address);
- else if (strcasecmp("Instance",child->key) == 0)
+ else if (strcasecmp("Instance", child->key) == 0)
amqp1_config_instance(child);
else
WARNING("amqp1 plugin: Ignoring unknown "
"transport configuration option "
- "\%s\".", child->key);
+ "\%s\".",
+ child->key);
if (status != 0)
break;
amqp1_config_transport_free(transport);
}
return status;
-} /* }}} int amqp1_config_transport */
+} /* }}} int amqp1_config_transport */
static int amqp1_config(oconfig_item_t *ci) /* {{{ */
{
static int amqp1_init(void) /* {{{ */
{
char addr[PN_MAX_ADDR];
- int status;
+ int status;
char errbuf[1024];
if (transport == NULL) {
if (proactor == NULL) {
pthread_mutex_init(&send_lock, /* attr = */ NULL);
proactor = pn_proactor();
- pn_proactor_addr(addr, sizeof(addr),transport->host,transport->port);
+ pn_proactor_addr(addr, sizeof(addr), transport->host, transport->port);
conn = pn_connection();
if (transport->user != NULL) {
- pn_connection_set_user(conn, transport->user);
- pn_connection_set_password(conn, transport->password);
+ pn_connection_set_user(conn, transport->user);
+ pn_connection_set_password(conn, transport->password);
}
pn_proactor_connect(proactor, conn, addr);
/* start_thread */
- status = plugin_thread_create(&event_thread_id, NULL /* no attributes */,
- event_thread, NULL /* no argument */,
- "handle");
+ status =
+ plugin_thread_create(&event_thread_id, NULL /* no attributes */,
+ event_thread, NULL /* no argument */, "handle");
if (status != 0) {
ERROR("amqp1: pthread_create failed: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
/* Stop the proactor thread */
if (event_thread_running != 0) {
- finished=true;
+ finished = true;
/* activate the event thread */
pn_connection_wake(conn);
pthread_join(event_thread_id, NULL /* no return value */);
return 0;
} /* }}} int amqp1_shutdown */
-void module_register(void)
-{
+void module_register(void) {
plugin_register_complex_config("amqp1", amqp1_config);
plugin_register_init("amqp1", amqp1_init);
- plugin_register_shutdown("amqp1",amqp1_shutdown);
+ plugin_register_shutdown("amqp1", amqp1_shutdown);
} /* void module_register */
#ifndef utils_deq_h
#define utils_deq_h 1
-#include <stdlib.h>
#include <assert.h>
#include <memory.h>
+#include <stdlib.h>
-#define CT_ASSERT(exp) { assert(exp); }
+#define CT_ASSERT(exp) \
+ { assert(exp); }
-#define NEW(t) (t*) malloc(sizeof(t))
-#define NEW_ARRAY(t,n) (t*) malloc(sizeof(t)*(n))
-#define NEW_PTR_ARRAY(t,n) (t**) malloc(sizeof(t*)*(n))
+#define NEW(t) (t *)malloc(sizeof(t))
+#define NEW_ARRAY(t, n) (t *)malloc(sizeof(t) * (n))
+#define NEW_PTR_ARRAY(t, n) (t **)malloc(sizeof(t *) * (n))
//
-// If available, use aligned_alloc for cache-line-aligned allocations. Otherwise
+// If available, use aligned_alloc for cache-line-aligned allocations. Otherwise
// fall back to plain malloc.
//
-#define NEW_CACHE_ALIGNED(t,p) \
-do { \
- if (posix_memalign((void*) &(p), 64, (sizeof(t) + (sizeof(t) % 64 ? 64 - (sizeof(t) % 64) : 0))) != 0) (p) = 0; \
-} while (0)
-
-#define ALLOC_CACHE_ALIGNED(s,p) \
-do { \
- if (posix_memalign((void*) &(p), 64, (s + (s % 64 ? 64 - (s % 64) : 0))) != 0) (p) = 0; \
-} while (0)
+#define NEW_CACHE_ALIGNED(t, p) \
+ do { \
+ if (posix_memalign( \
+ (void *)&(p), 64, \
+ (sizeof(t) + (sizeof(t) % 64 ? 64 - (sizeof(t) % 64) : 0))) != 0) \
+ (p) = 0; \
+ } while (0)
+
+#define ALLOC_CACHE_ALIGNED(s, p) \
+ do { \
+ if (posix_memalign((void *)&(p), 64, \
+ (s + (s % 64 ? 64 - (s % 64) : 0))) != 0) \
+ (p) = 0; \
+ } while (0)
#define ZERO(p) memset(p, 0, sizeof(*p))
-#define DEQ_DECLARE(i,d) typedef struct { \
- i *head; \
- i *tail; \
- i *scratch; \
- size_t size; \
- } d
-
-#define DEQ_LINKS_N(n,t) t *prev##n; t *next##n
-#define DEQ_LINKS(t) DEQ_LINKS_N(,t)
-#define DEQ_EMPTY {0,0,0,0}
-
-#define DEQ_INIT(d) do { (d).head = 0; (d).tail = 0; (d).scratch = 0; (d).size = 0; } while (0)
+#define DEQ_DECLARE(i, d) \
+ typedef struct { \
+ i *head; \
+ i *tail; \
+ i *scratch; \
+ size_t size; \
+ } d
+
+#define DEQ_LINKS_N(n, t) \
+ t *prev##n; \
+ t *next##n
+#define DEQ_LINKS(t) DEQ_LINKS_N(, t)
+#define DEQ_EMPTY \
+ { 0, 0, 0, 0 }
+
+#define DEQ_INIT(d) \
+ do { \
+ (d).head = 0; \
+ (d).tail = 0; \
+ (d).scratch = 0; \
+ (d).size = 0; \
+ } while (0)
#define DEQ_IS_EMPTY(d) ((d).head == 0)
-#define DEQ_ITEM_INIT_N(n,i) do { (i)->next##n = 0; (i)->prev##n = 0; } while(0)
-#define DEQ_ITEM_INIT(i) DEQ_ITEM_INIT_N(,i)
+#define DEQ_ITEM_INIT_N(n, i) \
+ do { \
+ (i)->next##n = 0; \
+ (i)->prev##n = 0; \
+ } while (0)
+#define DEQ_ITEM_INIT(i) DEQ_ITEM_INIT_N(, i)
#define DEQ_HEAD(d) ((d).head)
#define DEQ_TAIL(d) ((d).tail)
#define DEQ_SIZE(d) ((d).size)
-#define DEQ_NEXT_N(n,i) (i)->next##n
-#define DEQ_NEXT(i) DEQ_NEXT_N(,i)
-#define DEQ_PREV_N(n,i) (i)->prev##n
-#define DEQ_PREV(i) DEQ_PREV_N(,i)
-#define DEQ_MOVE(d1,d2) do {d2 = d1; DEQ_INIT(d1);} while (0)
+#define DEQ_NEXT_N(n, i) (i)->next##n
+#define DEQ_NEXT(i) DEQ_NEXT_N(, i)
+#define DEQ_PREV_N(n, i) (i)->prev##n
+#define DEQ_PREV(i) DEQ_PREV_N(, i)
+#define DEQ_MOVE(d1, d2) \
+ do { \
+ d2 = d1; \
+ DEQ_INIT(d1); \
+ } while (0)
/**
*@pre ptr points to first element of deq
- *@post ptr points to first element of deq that passes test, or 0. Test should involve ptr.
+ *@post ptr points to first element of deq that passes test, or 0. Test should
+ *involve ptr.
*/
-#define DEQ_FIND_N(n,ptr,test) while((ptr) && !(test)) ptr = DEQ_NEXT_N(n,ptr);
-#define DEQ_FIND(ptr,test) DEQ_FIND_N(,ptr,test)
-
-#define DEQ_INSERT_HEAD_N(n,d,i) \
-do { \
- CT_ASSERT((i)->next##n == 0); \
- CT_ASSERT((i)->prev##n == 0); \
- if ((d).head) { \
- (i)->next##n = (d).head; \
- (d).head->prev##n = i; \
- } else { \
- (d).tail = i; \
- (i)->next##n = 0; \
- CT_ASSERT((d).size == 0); \
- } \
- (i)->prev##n = 0; \
- (d).head = i; \
- (d).size++; \
-} while (0)
-#define DEQ_INSERT_HEAD(d,i) DEQ_INSERT_HEAD_N(,d,i)
-
-#define DEQ_INSERT_TAIL_N(n,d,i) \
-do { \
- CT_ASSERT((i)->next##n == 0); \
- CT_ASSERT((i)->prev##n == 0); \
- if ((d).tail) { \
- (i)->prev##n = (d).tail; \
- (d).tail->next##n = i; \
- } else { \
- (d).head = i; \
- (i)->prev##n = 0; \
- CT_ASSERT((d).size == 0); \
- } \
- (i)->next##n = 0; \
- (d).tail = i; \
- (d).size++; \
-} while (0)
-#define DEQ_INSERT_TAIL(d,i) DEQ_INSERT_TAIL_N(,d,i)
-
-#define DEQ_REMOVE_HEAD_N(n,d) \
-do { \
- CT_ASSERT((d).head); \
- if ((d).head) { \
- (d).scratch = (d).head; \
- (d).head = (d).head->next##n; \
- if ((d).head == 0) { \
- (d).tail = 0; \
- CT_ASSERT((d).size == 1); \
- } else \
- (d).head->prev##n = 0; \
- (d).size--; \
- (d).scratch->next##n = 0; \
- (d).scratch->prev##n = 0; \
- } \
-} while (0)
-#define DEQ_REMOVE_HEAD(d) DEQ_REMOVE_HEAD_N(,d)
-
-#define DEQ_REMOVE_TAIL_N(n,d) \
-do { \
- CT_ASSERT((d).tail); \
- if ((d).tail) { \
- (d).scratch = (d).tail; \
- (d).tail = (d).tail->prev##n; \
- if ((d).tail == 0) { \
- (d).head = 0; \
- CT_ASSERT((d).size == 1); \
- } else \
- (d).tail->next##n = 0; \
- (d).size--; \
- (d).scratch->next##n = 0; \
- (d).scratch->prev##n = 0; \
- } \
-} while (0)
-#define DEQ_REMOVE_TAIL(d) DEQ_REMOVE_TAIL_N(,d)
-
-#define DEQ_INSERT_AFTER_N(n,d,i,a) \
-do { \
- CT_ASSERT((i)->next##n == 0); \
- CT_ASSERT((i)->prev##n == 0); \
- CT_ASSERT(a); \
- if ((a)->next##n) \
- (a)->next##n->prev##n = (i); \
- else \
- (d).tail = (i); \
- (i)->next##n = (a)->next##n; \
- (i)->prev##n = (a); \
- (a)->next##n = (i); \
- (d).size++; \
-} while (0)
-#define DEQ_INSERT_AFTER(d,i,a) DEQ_INSERT_AFTER_N(,d,i,a)
-
-#define DEQ_REMOVE_N(n,d,i) \
-do { \
- if ((i)->next##n) \
- (i)->next##n->prev##n = (i)->prev##n; \
- else \
- (d).tail = (i)->prev##n; \
- if ((i)->prev##n) \
- (i)->prev##n->next##n = (i)->next##n; \
- else \
- (d).head = (i)->next##n; \
- CT_ASSERT((d).size > 0); \
- (d).size--; \
- (i)->next##n = 0; \
- (i)->prev##n = 0; \
- CT_ASSERT((d).size || (!(d).head && !(d).tail)); \
-} while (0)
-#define DEQ_REMOVE(d,i) DEQ_REMOVE_N(,d,i)
-
-#define DEQ_APPEND_N(n,d1,d2) \
-do { \
- if (!(d1).head) \
- (d1) = (d2); \
- else if ((d2).head) { \
- (d1).tail->next##n = (d2).head; \
- (d2).head->prev##n = (d1).tail; \
- (d1).tail = (d2).tail; \
- (d1).size += (d2).size; \
- } \
- DEQ_INIT(d2); \
-} while (0)
-#define DEQ_APPEND(d1,d2) DEQ_APPEND_N(,d1,d2)
+#define DEQ_FIND_N(n, ptr, test) \
+ while ((ptr) && !(test)) \
+ ptr = DEQ_NEXT_N(n, ptr);
+#define DEQ_FIND(ptr, test) DEQ_FIND_N(, ptr, test)
+
+#define DEQ_INSERT_HEAD_N(n, d, i) \
+ do { \
+ CT_ASSERT((i)->next##n == 0); \
+ CT_ASSERT((i)->prev##n == 0); \
+ if ((d).head) { \
+ (i)->next##n = (d).head; \
+ (d).head->prev##n = i; \
+ } else { \
+ (d).tail = i; \
+ (i)->next##n = 0; \
+ CT_ASSERT((d).size == 0); \
+ } \
+ (i)->prev##n = 0; \
+ (d).head = i; \
+ (d).size++; \
+ } while (0)
+#define DEQ_INSERT_HEAD(d, i) DEQ_INSERT_HEAD_N(, d, i)
+
+#define DEQ_INSERT_TAIL_N(n, d, i) \
+ do { \
+ CT_ASSERT((i)->next##n == 0); \
+ CT_ASSERT((i)->prev##n == 0); \
+ if ((d).tail) { \
+ (i)->prev##n = (d).tail; \
+ (d).tail->next##n = i; \
+ } else { \
+ (d).head = i; \
+ (i)->prev##n = 0; \
+ CT_ASSERT((d).size == 0); \
+ } \
+ (i)->next##n = 0; \
+ (d).tail = i; \
+ (d).size++; \
+ } while (0)
+#define DEQ_INSERT_TAIL(d, i) DEQ_INSERT_TAIL_N(, d, i)
+
+#define DEQ_REMOVE_HEAD_N(n, d) \
+ do { \
+ CT_ASSERT((d).head); \
+ if ((d).head) { \
+ (d).scratch = (d).head; \
+ (d).head = (d).head->next##n; \
+ if ((d).head == 0) { \
+ (d).tail = 0; \
+ CT_ASSERT((d).size == 1); \
+ } else \
+ (d).head->prev##n = 0; \
+ (d).size--; \
+ (d).scratch->next##n = 0; \
+ (d).scratch->prev##n = 0; \
+ } \
+ } while (0)
+#define DEQ_REMOVE_HEAD(d) DEQ_REMOVE_HEAD_N(, d)
+
+#define DEQ_REMOVE_TAIL_N(n, d) \
+ do { \
+ CT_ASSERT((d).tail); \
+ if ((d).tail) { \
+ (d).scratch = (d).tail; \
+ (d).tail = (d).tail->prev##n; \
+ if ((d).tail == 0) { \
+ (d).head = 0; \
+ CT_ASSERT((d).size == 1); \
+ } else \
+ (d).tail->next##n = 0; \
+ (d).size--; \
+ (d).scratch->next##n = 0; \
+ (d).scratch->prev##n = 0; \
+ } \
+ } while (0)
+#define DEQ_REMOVE_TAIL(d) DEQ_REMOVE_TAIL_N(, d)
+
+#define DEQ_INSERT_AFTER_N(n, d, i, a) \
+ do { \
+ CT_ASSERT((i)->next##n == 0); \
+ CT_ASSERT((i)->prev##n == 0); \
+ CT_ASSERT(a); \
+ if ((a)->next##n) \
+ (a)->next##n->prev##n = (i); \
+ else \
+ (d).tail = (i); \
+ (i)->next##n = (a)->next##n; \
+ (i)->prev##n = (a); \
+ (a)->next##n = (i); \
+ (d).size++; \
+ } while (0)
+#define DEQ_INSERT_AFTER(d, i, a) DEQ_INSERT_AFTER_N(, d, i, a)
+
+#define DEQ_REMOVE_N(n, d, i) \
+ do { \
+ if ((i)->next##n) \
+ (i)->next##n->prev##n = (i)->prev##n; \
+ else \
+ (d).tail = (i)->prev##n; \
+ if ((i)->prev##n) \
+ (i)->prev##n->next##n = (i)->next##n; \
+ else \
+ (d).head = (i)->next##n; \
+ CT_ASSERT((d).size > 0); \
+ (d).size--; \
+ (i)->next##n = 0; \
+ (i)->prev##n = 0; \
+ CT_ASSERT((d).size || (!(d).head && !(d).tail)); \
+ } while (0)
+#define DEQ_REMOVE(d, i) DEQ_REMOVE_N(, d, i)
+
+#define DEQ_APPEND_N(n, d1, d2) \
+ do { \
+ if (!(d1).head) \
+ (d1) = (d2); \
+ else if ((d2).head) { \
+ (d1).tail->next##n = (d2).head; \
+ (d2).head->prev##n = (d1).tail; \
+ (d1).tail = (d2).tail; \
+ (d1).size += (d2).size; \
+ } \
+ DEQ_INIT(d2); \
+ } while (0)
+#define DEQ_APPEND(d1, d2) DEQ_APPEND_N(, d1, d2)
#endif