static inline int __flush_send_buffer(struct send_buffer *s, struct connection_pair *cp){ register int j, l; lock_send_buffer(s); l= (s->end_ptr - s->start_ptr); if(l <= 0){ unlock_send_buffer(s); return l; } for (j = 0; j < cp->n_remote; ++j) { if (!cp->remote[j].socketfd) continue; if (write (cp->remote[j].socketfd, s->start_ptr, l) < 0) { close(cp->remote[j].socketfd); fclose(cp->remote[j].socketfp); memset(&cp->remote[j], 0, sizeof(struct connection)); continue; } } s->end_ptr = s->start_ptr; unlock_send_buffer(s); return l; }
int get_chunk_from_buffer(struct sb_config *sb, void **ptr, unsigned int chunk_size, struct send_buffer **s){ unsigned int unoccupied; /* first try */ lock_whole_buffer(sb); *s= &(sb->buffers[sb->current_buffer]); unlock_whole_buffer(sb); lock_send_buffer(*s); unoccupied= (sb->buffer_size - ((*s)->end_ptr - (*s)->start_ptr)); if (unoccupied >= chunk_size) { (*ptr)= (*s)->end_ptr; (*s)->end_ptr += chunk_size; unlock_send_buffer(*s); return 0; } unlock_send_buffer(*s); /* move to next buffer and try */ lock_whole_buffer(sb); ++(sb->current_buffer); sb->current_buffer %= sb->n_buffers; *s = &(sb->buffers[sb->current_buffer]); unlock_whole_buffer(sb); lock_send_buffer(*s); unoccupied = (sb->buffer_size - ((*s)->end_ptr - (*s)->start_ptr)); if (unoccupied >= chunk_size) { (*ptr)= (*s)->end_ptr; (*s)->end_ptr += chunk_size; unlock_send_buffer(*s); return 0; } unlock_send_buffer(*s); /* no memory left in buffer to fit chunk_size */ *s=NULL; return -1; }
int copy_to_send_buffer(struct sb_config *sb, void *p, unsigned int len) { struct send_buffer *tmp = &(sb->buffers[sb->current_buffer]); unsigned int unoccupied; lock_send_buffer(tmp); unoccupied = (sb->buffer_size - (tmp->end_ptr - tmp->start_ptr)); if (unoccupied >= len) { memcpy(tmp->end_ptr, p, len); tmp->end_ptr += len; unlock_send_buffer(tmp); return 0; } unlock_send_buffer(tmp); pthread_mutex_lock(&sb->lock); ++(sb->current_buffer); sb->current_buffer %= sb->n_buffers; pthread_mutex_unlock(&sb->lock); tmp = &(sb->buffers[sb->current_buffer]); lock_send_buffer(tmp); unoccupied = (sb->buffer_size - (tmp->end_ptr - tmp->start_ptr)); if (unoccupied >= len) { /* used to be (unoccupied < len) WHY?? */ memcpy(tmp->end_ptr, p, len); tmp->end_ptr += len; unlock_send_buffer(tmp); return 0; } unlock_send_buffer(tmp); return -1; }
static inline int flush_send_buffer(struct sb_config *sb, struct send_buffer *s, struct connection_pair *cp){ register int j, l; int fs, fc; void *ptr; lock_send_buffer(s); /* find first flushable chunk */ bit_ffs(s->bitmap, sb->chunks_in_a_buffer, &fs); if(fs == -1){ /* nothing flushable */ unlock_send_buffer(s); return 0; } /* find first non-flushable chunk */ bit_ffc(s->bitmap, sb->chunks_in_a_buffer, &fc); if(fc == -1){ /* everything is flushable */ l= (s->end_ptr - s->start_ptr); fprintf(stderr, "flushing everything (%d bytes).", l); for (j = 0; j < cp->n_remote; ++j) { if (!cp->remote[j].socketfd) continue; if (write (cp->remote[j].socketfd, s->start_ptr, l) < 0) { close(cp->remote[j].socketfd); fclose(cp->remote[j].socketfp); memset(&cp->remote[j], 0, sizeof(struct connection)); continue; } } s->end_ptr = s->start_ptr; bit_nclear(s->bitmap, 0, (sb->chunks_in_a_buffer - 1)); unlock_send_buffer(s); return l; } /* some chunks flushable, some not. flush the first available window and * only that. this keeps the flush-window moving in only forward direction */ ptr= (fs == 0)? (s->start_ptr): ((s->start_ptr) + (fs * sb->chunk_size)); l= ((fc - fs) * sb->chunk_size); fprintf(stderr, "flushing a range (%d bytes).", l); for (j = 0; j < cp->n_remote; ++j) { if (!cp->remote[j].socketfd) continue; if (write (cp->remote[j].socketfd, ptr, l) < 0) { close(cp->remote[j].socketfd); fclose(cp->remote[j].socketfp); memset(&cp->remote[j], 0, sizeof(struct connection)); continue; } } /* when and only when the last chunk is flushed, reset the buffer */ if(s->end_ptr == (ptr + l)){ s->end_ptr= s->start_ptr; bit_nclear(s->bitmap, 0, (sb->chunks_in_a_buffer - 1)); } unlock_send_buffer(s); return l; }