static void * test(void *c) { #ifdef CK_F_FIFO_MPMC struct context *context = c; struct entry *entry; ck_fifo_mpmc_entry_t *fifo_entry, *garbage; int i, j; if (aff_iterate(&a)) { perror("ERROR: Could not affine thread"); exit(EXIT_FAILURE); } ck_pr_inc_uint(&barrier); while (ck_pr_load_uint(&barrier) < (unsigned int)nthr); for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_fifo_mpmc_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; ck_fifo_mpmc_enqueue(&fifo, fifo_entry, entry); if (ck_fifo_mpmc_dequeue(&fifo, &entry, &garbage) == false) { fprintf(stderr, "ERROR [%u] Queue should never be empty.\n", context->tid); exit(EXIT_FAILURE); } if (entry->tid < 0 || entry->tid >= nthr) { fprintf(stderr, "ERROR [%u] Incorrect value in entry.\n", entry->tid); exit(EXIT_FAILURE); } } } for (i = 0; i < ITERATIONS; i++) { for (j = 0; j < size; j++) { fifo_entry = malloc(sizeof(ck_fifo_mpmc_entry_t)); entry = malloc(sizeof(struct entry)); entry->tid = context->tid; while (ck_fifo_mpmc_tryenqueue(&fifo, fifo_entry, entry) == false) ck_pr_stall(); while (ck_fifo_mpmc_trydequeue(&fifo, &entry, &garbage) == false) ck_pr_stall(); if (entry->tid < 0 || entry->tid >= nthr) { fprintf(stderr, "ERROR [%u] Incorrect value in entry when using try interface.\n", entry->tid); exit(EXIT_FAILURE); } } } #endif return (NULL); }
fq_msg *fq_client_receive(fq_client conn) { fq_conn_s *conn_s = conn; fq_msg *m = NULL; ck_fifo_mpmc_entry_t *garbage; if(ck_fifo_mpmc_dequeue(&conn_s->backq, &m, &garbage) == true) { free(garbage); } return m; }
int main(void) { ck_spinlock_fas_t mutex = CK_SPINLOCK_FAS_INITIALIZER; void *r; uint64_t s, e, a; unsigned int i; unsigned int j; #if defined(CK_F_FIFO_SPSC) ck_fifo_spsc_t spsc_fifo; ck_fifo_spsc_entry_t spsc_entry[ENTRIES]; ck_fifo_spsc_entry_t spsc_stub; #endif #if defined(CK_F_FIFO_MPMC) ck_fifo_mpmc_t mpmc_fifo; ck_fifo_mpmc_entry_t mpmc_entry[ENTRIES]; ck_fifo_mpmc_entry_t mpmc_stub; ck_fifo_mpmc_entry_t *garbage; #endif #ifdef CK_F_FIFO_SPSC a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) { ck_spinlock_fas_lock(&mutex); ck_fifo_spsc_dequeue(&spsc_fifo, &r); ck_spinlock_fas_unlock(&mutex); } e = rdtsc(); a += e - s; } printf(" spinlock_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); e = rdtsc(); a += e - s; } printf("ck_fifo_spsc_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_spsc_init(&spsc_fifo, &spsc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_enqueue(&spsc_fifo, spsc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_spsc_dequeue(&spsc_fifo, &r); e = rdtsc(); a += e - s; } printf("ck_fifo_spsc_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(spsc_entry) / sizeof(*spsc_entry))); #endif #ifdef CK_F_FIFO_MPMC a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_mpmc_init(&mpmc_fifo, &mpmc_stub); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_enqueue(&mpmc_fifo, mpmc_entry + j, NULL); e = rdtsc(); a += e - s; } printf("ck_fifo_mpmc_enqueue: %16" PRIu64 "\n", a / STEPS / (sizeof(mpmc_entry) / sizeof(*mpmc_entry))); a = 0; for (i = 0; i < STEPS; i++) { ck_fifo_mpmc_init(&mpmc_fifo, &mpmc_stub); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_enqueue(&mpmc_fifo, mpmc_entry + j, NULL); s = rdtsc(); for (j = 0; j < ENTRIES; j++) ck_fifo_mpmc_dequeue(&mpmc_fifo, &r, &garbage); e = rdtsc(); a += e - s; } printf("ck_fifo_mpmc_dequeue: %16" PRIu64 "\n", a / STEPS / (sizeof(mpmc_entry) / sizeof(*mpmc_entry))); #endif return 0; }
static void * fq_conn_worker(void *u) { int backoff = 0; fq_conn_s *conn_s = (fq_conn_s *)u; cmd_instr *last_entry = NULL; uint16_t expect; while(conn_s->stop == 0) { restart: expect = 0; if(fq_client_connect_internal(conn_s) == 0) { backoff = 0; /* we're good, restart our backoff */ } while(conn_s->data_ready) { hrtime_t t; unsigned long long hb_us; struct timeval tv; int rv; cmd_instr *entry; ck_fifo_mpmc_entry_t *garbage; while(ck_fifo_mpmc_dequeue(&conn_s->cmdq, &entry, &garbage) == true) { free(garbage); #ifdef DEBUG fq_debug(FQ_DEBUG_CONN, "client acting on user req 0x%04x\n", entry->cmd); #endif switch(entry->cmd) { case FQ_PROTO_STATUSREQ: if(expect != 0) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } fq_debug(FQ_DEBUG_CONN, "sending status request\n"); if(fq_write_uint16(conn_s->cmd_fd, entry->cmd)) { free(entry); goto restart; } expect = FQ_PROTO_STATUS; last_entry = entry; break; case FQ_PROTO_HBREQ: fq_debug(FQ_DEBUG_CONN, "sending heartbeat request\n"); if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) || fq_write_uint16(conn_s->cmd_fd, entry->data.heartbeat.ms)) { free(entry); goto restart; } conn_s->cmd_hb_ms = entry->data.heartbeat.ms; tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000; tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000); if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) CONNERR(conn_s, strerror(errno)); tv.tv_sec = (unsigned long)entry->data.heartbeat.ms / 1000; tv.tv_usec = 1000UL * (entry->data.heartbeat.ms % 1000); if(setsockopt(conn_s->cmd_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))) CONNERR(conn_s, strerror(errno)); conn_s->cmd_hb_last = fq_gethrtime(); free(entry); break; case FQ_PROTO_BINDREQ: { unsigned short peermode = entry->data.bind->peermode ? 1 : 0; if(expect != 0) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) || fq_write_uint16(conn_s->cmd_fd, peermode) || fq_write_short_cmd(conn_s->cmd_fd, entry->data.bind->exchange.len, entry->data.bind->exchange.name) < 0 || fq_write_short_cmd(conn_s->cmd_fd, strlen(entry->data.bind->program), entry->data.bind->program) < 0) { goto restart; } expect = FQ_PROTO_BIND; last_entry = entry; } break; case FQ_PROTO_UNBINDREQ: { if(expect != 0) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } if(fq_write_uint16(conn_s->cmd_fd, entry->cmd) || fq_write_uint32(conn_s->cmd_fd, entry->data.unbind->route_id) || fq_write_short_cmd(conn_s->cmd_fd, entry->data.unbind->exchange.len, entry->data.unbind->exchange.name) < 0) { goto restart; } expect = FQ_PROTO_UNBIND; last_entry = entry; } break; default: if(conn_s->errorlog) conn_s->errorlog("unknown user-side cmd"); free(entry); } } if(conn_s->cmd_hb_needed) { #ifdef DEBUG fq_debug(FQ_DEBUG_CONN, "-> heartbeat\n"); #endif if(fq_write_uint16(conn_s->cmd_fd, FQ_PROTO_HB)) break; conn_s->cmd_hb_needed = 0; } rv = fq_client_wfrw_internal(conn_s->cmd_fd, 1, 0, 50, NULL); t = fq_gethrtime(); hb_us = (unsigned long long)conn_s->cmd_hb_ms * 3 * 1000000ULL; if(conn_s->cmd_hb_last && hb_us && conn_s->cmd_hb_last < (unsigned int) (t - hb_us)) { char errbuf[256]; snprintf(errbuf, sizeof(errbuf), "heartbeat failed [%llu - %llu = %llu]", (unsigned long long)t, (unsigned long long)conn_s->cmd_hb_last, (unsigned long long)(t - conn_s->cmd_hb_last)); CONNERR(conn_s, errbuf); break; } if(rv < 0) { CONNERR(conn_s, strerror(errno)); break; } if(rv > 0) { uint16_t hb; if(fq_read_uint16(conn_s->cmd_fd, &hb)) break; switch(hb) { case FQ_PROTO_HB: #ifdef DEBUG fq_debug(FQ_DEBUG_CONN, "<- heartbeat\n"); #endif conn_s->cmd_hb_last = fq_gethrtime(); conn_s->cmd_hb_needed = 1; break; case FQ_PROTO_STATUS: if(expect != FQ_PROTO_STATUS) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } if(fq_read_status(conn_s->cmd_fd, last_entry->data.status.callback, last_entry->data.status.closure)) goto restart; expect = 0; break; case FQ_PROTO_BIND: if(expect != FQ_PROTO_BIND) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } if(fq_read_uint32(conn_s->cmd_fd, &last_entry->data.bind->out__route_id)) goto restart; expect = 0; break; case FQ_PROTO_UNBIND: if(expect != FQ_PROTO_UNBIND) { if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; } if(fq_read_uint32(conn_s->cmd_fd, &last_entry->data.unbind->out__success)) goto restart; expect = 0; break; default: if(conn_s->errorlog) conn_s->errorlog("protocol violation"); goto restart; break; } } } #ifdef DEBUG fq_debug(FQ_DEBUG_CONN, "[cmd] connection failed: %s\n", conn_s->error); #endif usleep(backoff); backoff += 10000; } fq_client_disconnect_internal(conn_s); return (void *)NULL; }
static void fq_data_worker_loop(fq_conn_s *conn_s) { buffered_msg_reader *ctx = NULL; ctx = fq_buffered_msg_reader_alloc(conn_s->data_fd, 1); while(conn_s->cmd_fd >= 0 && conn_s->stop == 0) { int rv; int wait_ms = 500, needs_write = 0, mask, write_rv; ck_fifo_mpmc_entry_t *garbage; if(conn_s->tosend) goto the_thick_of_it; while(ck_fifo_mpmc_dequeue(&conn_s->q, &conn_s->tosend, &garbage) == true) { conn_s->tosend_offset = 0; ck_pr_dec_uint(&conn_s->qlen); free(garbage); the_thick_of_it: #ifdef DEBUG fq_debug(FQ_DEBUG_MSG, "dequeue message to submit to server\n"); #endif write_rv = fq_client_write_msg(conn_s->data_fd, conn_s->peermode, conn_s->tosend, conn_s->tosend_offset); if(write_rv > 0) { conn_s->tosend_offset += write_rv; break; } if(write_rv < 0) { if(errno == EAGAIN) { needs_write = 1; break; } if(conn_s->errorlog) { char errbuf[128]; snprintf(errbuf, sizeof(errbuf), "data write error: %s\n", strerror(errno)); conn_s->errorlog(errbuf); } goto finish; } fq_msg_deref(conn_s->tosend); conn_s->tosend = NULL; conn_s->tosend_offset = 0; wait_ms = 0; } rv = fq_client_wfrw_internal(conn_s->data_fd, 1, needs_write, wait_ms, &mask); if(rv < 0) { if(conn_s->errorlog) { char errbuf[128]; snprintf(errbuf, sizeof(errbuf), "data read error: %s\n", strerror(errno)); conn_s->errorlog(errbuf); } goto finish; } if(rv > 0 && (mask & POLLIN)) { if(fq_buffered_msg_read(ctx, fq_client_read_complete, conn_s) < 0) { if(conn_s->errorlog) conn_s->errorlog("data read: end-of-line\n"); goto finish; } } } finish: if(ctx) fq_buffered_msg_reader_free(ctx); #ifdef DEBUG fq_debug(FQ_DEBUG_CONN, "cmd_fd -> %d, stop -> %d\n", conn_s->cmd_fd, conn_s->stop); #endif }