/* * return 0: keep going (to write path) * return -1: busted */ int fq_buffered_msg_read(buffered_msg_reader *f, void (*f_msg_handler)(void *, fq_msg *), void *closure) { int rv; if(f->into_body < f->msg.payload_len) { assert(f->copy); /* we need to be reading a largish payload */ while((rv = read(f->fd, f->copy->payload + f->into_body, f->copy->payload_len - f->into_body)) == -1 && errno == EINTR); if(rv < 0 && errno == EAGAIN) return 0; if(rv <= 0) { fq_debug(FQ_DEBUG_IO, "read error: %s\n", rv < 0 ? strerror(errno) : "end-of-line"); return -1; } fq_debug(FQ_DEBUG_MSG, "%p <-- %d bytes for payload\n", (void *)f, rv); f->into_body += rv; if(f->into_body == f->copy->payload_len) { f->into_body = 0; goto message_done; } } while((rv = read(f->fd, f->scratch+f->nread, sizeof(f->scratch)-f->nread)) == -1 && errno == EINTR); fq_debug(FQ_DEBUG_IO, "%p <-- %d bytes @ %d (%d)\n", (void *)f, rv, (int)f->nread, (int)f->nread + (rv > 0) ? rv : 0); if(rv == -1 && errno == EAGAIN) return 0; if(rv <= 0) return -1; f->nread += rv; while(f->nread>0) { uint32_t body_available; int body_start; body_start = parse_message_headers(f->peermode, f->scratch+f->off, f->nread-f->off, &f->msg); f->into_body = 0; fq_debug(FQ_DEBUG_MSG, "%d = parse(+%d, %d) -> %d\n", body_start, f->off, (int)f->nread-f->off, body_start ? (int)f->msg.payload_len : 0); if(body_start < 0) return -1; if(!body_start) { fq_debug(FQ_DEBUG_MSG, "incomplete message header...\n"); memmove(f->scratch, f->scratch + f->off, f->nread - f->off); f->nread -= f->off; f->off = 0; return 0; } /* We have a message... or the formal beginnings of one */ f->copy = fq_msg_alloc_BLANK(f->msg.payload_len); memcpy(f->copy, &f->msg, sizeof(f->msg)); f->off += body_start; body_available = f->nread - f->off; if(f->copy->payload_len < body_available) body_available = f->copy->payload_len; memcpy(f->copy->payload, f->scratch+f->off, body_available); if(body_available == f->copy->payload_len) { f->off += body_available; message_done: f->copy->refcnt = 1; fq_debug(FQ_DEBUG_MSG, "message read... injecting\n"); f_msg_handler(closure, f->copy); f->copy = NULL; memset(&f->msg, 0, sizeof(f->msg)); } else { f->nread = 0; f->off = 0; f->into_body = body_available; fq_debug(FQ_DEBUG_MSG, "incomplete message... (%d needed)\n", (int)f->msg.payload_len - (int)f->into_body); return 0; } } return 0; }
/* * return 0: keep going (to write path) * return -1: busted * * Read into one of N buffers so the processing thread * can do the work separate from the read */ int fq_buffered_msg_read(buffered_msg_reader *f, void (*f_msg_handler)(void *, fq_msg *), void *closure) { int rv; static char scratch_buf[IN_READ_BUFFER_SIZE]; while(f->into_body < f->msg->payload_len) { fq_assert(f->copy); /* we need to be reading a largish payload */ if(f->into_body >= MAX_MESSAGE_SIZE) { /* read into a scratch buffer */ size_t readsize = f->copy->payload_len - f->into_body; if(readsize > sizeof(scratch_buf)) readsize = sizeof(scratch_buf); while((rv = read(f->fd, scratch_buf, readsize)) == -1 && errno == EINTR); } else { while((rv = read(f->fd, f->copy->payload + f->into_body, CAPPED(f->copy->payload_len) - f->into_body)) == -1 && errno == EINTR); } if(rv < 0 && errno == EAGAIN) return 0; if(rv <= 0) { fq_debug(FQ_DEBUG_IO, "read error: %s\n", rv < 0 ? strerror(errno) : "end-of-line"); return -1; } fq_debug(FQ_DEBUG_MSG, "%p <-- %d bytes for payload\n", (void *)f, rv); f->into_body += rv; if(f->into_body == f->copy->payload_len) { f->into_body = 0; goto message_done; } } while((rv = read(f->fd, f->scratch+f->nread, sizeof(f->scratch)-f->nread)) == -1 && errno == EINTR); fq_debug(FQ_DEBUG_IO, "%p <-- %d bytes @ %d (%d)\n", (void *)f, rv, (int)f->nread, (int)f->nread + ((rv > 0) ? rv : 0)); if(rv == -1 && errno == EAGAIN) return 0; if(rv <= 0) return -1; f->nread += rv; while(f->nread>0) { uint32_t body_available; int body_start; body_start = parse_message_headers(f->peermode, f->scratch+f->off, f->nread-f->off, f->msg); f->into_body = 0; fq_debug(FQ_DEBUG_MSG, "%d = parse(+%d, %d) -> %d\n", body_start, f->off, (int)f->nread-f->off, body_start ? (int)f->msg->payload_len : 0); if(body_start < 0) return -1; if(!body_start) { fq_debug(FQ_DEBUG_MSG, "incomplete message header...\n"); memmove(f->scratch, f->scratch + f->off, f->nread - f->off); f->nread -= f->off; f->off = 0; return 0; } free_message_stack *tls_free_message_stack = NULL; int msg_stack_idx = msg_free_stack_select(f->msg->payload_len); if(msg_stack_idx >= 0) { if(tls_free_message_handle == NULL) tls_free_message_handle = free_message_handle_acquire(); if(tls_free_message_handle->stacks[msg_stack_idx] == NULL) { /* lazy create/init the cleanup stack */ tls_free_message_handle->stacks[msg_stack_idx] = malloc(sizeof(free_message_stack)); fq_init_free_message_stack(tls_free_message_handle->stacks[msg_stack_idx], FREE_MSG_LIST_SIZE/(1 << (msg_stack_idx + MSG_FREE_BASE)), (1 << (msg_stack_idx + MSG_FREE_BASE))); } tls_free_message_stack = tls_free_message_handle->stacks[msg_stack_idx]; } if(tls_free_message_stack) { /* We have a message... or the formal beginnings of one */ f->copy = fq_pop_free_message_stack(tls_free_message_stack); if (f->copy == NULL) { /* ran out of entries in free list */ f->copy = fq_msg_alloc_BLANK(tls_free_message_stack->alloc_size); if (f->copy == NULL) { /* this is bad, we can't alloc */ fq_debug(FQ_DEBUG_MSG, "unable to malloc, OOM?\n"); return -1; } } /* always 1 as this msg only lives until it's copied by a worker thread */ memcpy(f->copy, f->msg, sizeof(fq_msg)); f->copy->refcnt = 1; f->copy->free_fn = fq_free_msg_fn; } else { f->copy = fq_msg_alloc_BLANK(CAPPED(f->msg->payload_len)); if (f->copy == NULL) { /* this is bad, we can't alloc */ fq_debug(FQ_DEBUG_MSG, "unable to malloc, OOM?\n"); return -1; } memcpy(f->copy, f->msg, sizeof(fq_msg)); f->copy->refcnt = 1; f->copy->free_fn = NULL; } /* assign the cleanup stack for this message */ f->copy->cleanup_handle = tls_free_message_stack ? tls_free_message_handle : NULL; memset(&f->copy->cleanup_stack_entry, 0, sizeof(ck_stack_entry_t)); f->off += body_start; body_available = f->nread - f->off; if(f->copy->payload_len < body_available) body_available = f->copy->payload_len; memcpy(f->copy->payload, f->scratch+f->off, CAPPED(body_available)); if(body_available == f->copy->payload_len) { f->off += body_available; message_done: f->copy->refcnt = 1; f->copy->payload_len = CAPPED(f->copy->payload_len); fq_debug(FQ_DEBUG_MSG, "message read... injecting\n"); f->copy->arrival_time = fq_gethrtime(); f_msg_handler(closure, f->copy); f->copy = NULL; memset(f->msg, 0, sizeof(fq_msg)); /* It is still allocated and we are the sole owner, refcnt must be 1 */ f->msg->refcnt = 1; } else { f->nread = 0; f->off = 0; f->into_body = body_available; fq_debug(FQ_DEBUG_MSG, "incomplete message... (%d needed)\n", (int)f->msg->payload_len - (int)f->into_body); return 0; } } return 0; }