int main(int argc, const char *argv[]) { t_ring_buffer *r = NULL; int elem1 = 4; int elem2 = 6; int elem3 = 2; int elem4 = 3; gpointer oldelem = NULL; gpointer popelem = NULL; g_message("Test RingBuffer"); r = ring_buffer_new(2); g_assert(NULL != r); oldelem = ring_buffer_push(r, &elem1); g_assert(NULL == oldelem); g_assert(1 == ring_buffer_stored_elements(r)); oldelem = ring_buffer_push(r, &elem2); g_assert(NULL == oldelem); g_assert(2 == ring_buffer_stored_elements(r)); oldelem = ring_buffer_push(r, &elem3); g_assert(NULL != oldelem && *((int *)oldelem) == elem1); g_assert(2 == ring_buffer_stored_elements(r)); oldelem = ring_buffer_push(r, &elem4); g_assert(NULL != oldelem && *((int *)oldelem) == elem2); popelem = ring_buffer_pop(r); g_assert(NULL != popelem && *((int *)popelem) == elem4); popelem = ring_buffer_pop(r); g_assert(NULL != popelem && *((int *)popelem) == elem3); popelem = ring_buffer_pop(r); g_assert(NULL == popelem); g_assert(0 == ring_buffer_stored_elements(r)); r = ring_buffer_free(r); g_assert(NULL == r); g_message("Test RingBuffer complete"); return 0; }
/*----------------------------------------------------------------------------*/ static void shf_ipi_receive_handler(int id, void* data, uint size) { if (id == IPI_SHF) { //shf_print_bytes(data, size); SHF_LOG("IPI_SHF\n"); ring_buffer_push(&trigger_buffer, data, size); notify(); } }
static void test_push_to_full_buffer() { RingBuffer rb; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); assert_true(ring_buffer_push(&rb) == NULL, "cannot push to a full buffer"); ring_buffer_free(&rb); }
static void _ringbuffer_fill(RingBuffer *rb, size_t n, int start_idx, gboolean ack) { TestData *td; int i; for (i = 0; i < n; i++) { td = ring_buffer_push(rb); td->idx = start_idx + i; td->ack = ack; } }
static void _ringbuffer_fill2(RingBuffer *rb, size_t n, int start_idx, gboolean ack) { TestData *td; int i; for (i = 0; i < n; i++) { td = ring_buffer_tail(rb); td->idx = start_idx + i; td->ack = ack; assert_true(ring_buffer_push(rb) == td, "Push should return last tail."); } }
static void test_tail() { RingBuffer rb; TestData *td_tail; ring_buffer_alloc(&rb, sizeof(TestData), 103); _ringbuffer_fill2(&rb, 103, 0, TRUE); ring_buffer_pop(&rb); td_tail = ring_buffer_tail(&rb); td_tail->idx = 103; assert_true(ring_buffer_push(&rb) == td_tail, "Push should return last tail."); assert_test_data_idx_range_in(&rb, 1, 103); ring_buffer_free(&rb); }
int main (int argc, const char* argv[]) { ring_buffer_t ring; ring_buffer_init(&ring, buf, sizeof(buf)); while (1) { printf("av: %d/%d\nhead=%ld, tail=%ld\n\n> ", ring_buffer_av_data(&ring), ring_buffer_av_space(&ring), ring.head - ring.buffer, ring.tail - ring.buffer ); size_t sz = 128; char* str = malloc(sz); int bytes = getline(&str, &sz, stdin); bytes--; // remove '\n' if (bytes > 0) { uint32_t pushed = ring_buffer_push(&ring, str, bytes); printf("push(%d) %d\n", bytes, pushed); } else if (bytes == 0) { uint32_t to_pop = 10; uint32_t popped = ring_buffer_pop(&ring, str, to_pop); printf("pop(%d) %d\n", to_pop, popped); if (popped > 0) { for (int i = 0; i < popped; i++) { printf("%c", str[i]); } printf("\n"); } } else if (bytes < 0) { return -1; } } return 0; }
static void test_ring_buffer_is_full() { RingBuffer rb; int i; TestData *last = NULL; _ringbuffer_init(&rb); for (i = 1; !ring_buffer_is_full(&rb); i++) { TestData *td = ring_buffer_push(&rb); assert_true(td != NULL, "ring_buffer_push failed"); td->idx = i; last = td; } assert_true(ring_buffer_count(&rb) == capacity, "buffer count(%d) is not equal to capacity(%d)", ring_buffer_count(&rb), capacity); assert_true(last->idx == capacity, "buffer is not full, number of inserted items: %d, capacity: %d", last->idx, capacity); ring_buffer_free(&rb); }
static void late_ack_tracker_track_msg(AckTracker *s, LogMessage *msg) { LateAckTracker *self = (LateAckTracker *)s; LogSource *source = self->super.source; g_assert(self->pending_ack_record != NULL); log_pipe_ref((LogPipe *)source); msg->ack_record = (AckRecord *)self->pending_ack_record; _late_tracker_lock(self); { LateAckRecord *ack_rec; ack_rec = (LateAckRecord *)ring_buffer_push(&self->ack_record_storage); g_assert(ack_rec == self->pending_ack_record); } _late_tracker_unlock(self); self->pending_ack_record = NULL; }
/** add to end of queue */ void push(struct buffer *buffer, int x) /*@ requires [?f]buffer(buffer, ?id_text, ?id_progress_read, ?id_progress_write) &*& token(id_progress_write, ?t1) &*& op(id_text, id_progress_write, t1, x, ?t2); @*/ /*@ ensures [f]buffer(buffer, id_text, id_progress_read, id_progress_write) &*& token(id_progress_write, t2); @*/ { //@ open buffer(buffer, _, _, _); //@ assert [f]buffer->mutex |-> ?mutex; mutex_acquire(buffer->mutex); //@ open buffer_protected(buffer, id_text, id_progress_read, id_progress_write)(); //@ open token(id_progress_write, ?n_write); //@ assert [_]ghost_cell<list<int> >(id_text, ?alltext); while (ring_buffer_is_full(buffer->ring_buffer)) /*@ invariant buffer->ring_buffer |-> ?ring_buffer &*& [f]buffer->mutex |-> mutex &*& ring_buffer(ring_buffer, ?size, ?contents) &*& [f]buffer->cond_can_push |-> ?cond_can_push &*& [f]mutex_cond(cond_can_push, mutex) &*& mutex_held(mutex, (buffer_protected)(buffer, id_text, id_progress_read, id_progress_write), currentThread, f) &*& [_]ghost_cell<list<int> >(id_text, alltext) &*& [1/2]ghost_cell<int>(id_progress_read, ?n_read) &*& [1/2]ghost_cell<int>(id_progress_write, n_write) &*& [1/2]ghost_cell<int>(id_progress_write, n_write) &*& take(n_write - n_read, drop(n_read, alltext)) == contents ; @*/ { //@ close buffer_protected(buffer, id_text, id_progress_read, id_progress_write)(); mutex_cond_wait(buffer->cond_can_push, buffer->mutex); //@ open buffer_protected(buffer, id_text, id_progress_read, id_progress_write)(); } bool was_empty = ring_buffer_is_empty(buffer->ring_buffer); ring_buffer_push(buffer->ring_buffer, x); if (was_empty){ mutex_cond_signal(buffer->cond_can_pop); } //@ ghost_cell_mutate(id_progress_write, n_write + 1); //@ open op(_, _, _, _, _); //@ assert t2 == n_write + 1; //@ close token(id_progress_write, n_write + 1); //@ assert take(n_write - n_read, drop(n_read, alltext)) == contents; //@ assume (take(n_write+1 - n_read, drop(n_read, alltext)) == append(contents, cons(nth(n_write, alltext), nil))); //@ close buffer_protected(buffer, id_text, id_progress_read, id_progress_write)(); mutex_release(buffer->mutex); //@ close [f]buffer(buffer, id_text, id_progress_read, id_progress_write); }
/* PUSH PUMP * * This is used to push data out to a blocking file descriptor. It pulls * data from a non-blocking pipe (pullfd) and pushes to STDOUT_FILENO * (pushfd). * When the pipe is closed, then the rest of the data is pushed out and then * STDOUT_FILENO is closed. * * The algorithm looks roughly like this: * * while (true) { * r = read(pipe) // nonblocking * * while (!ring.empty) { * write(STDOUT_FILENO) // blocking * } * * select(pipe, readable); * } */ static void push_pump (int pullfd, int pushfd) { int r; ring_buffer ring; fd_set readfds, exceptfds; FD_ZERO(&exceptfds); FD_ZERO(&readfds); FD_SET(pullfd, &exceptfds); FD_SET(pullfd, &readfds); ring_buffer_init(&ring); /* The pipe is open or there is data left to be pushed out * NOTE: if pushfd (STDOUT_FILENO) ever errors out, then we just exit the * loop. */ while (pullfd >= 0 || !ring_buffer_empty_p(&ring)) { /* Pull from the non-blocking pipe */ r = ring_buffer_pull(&ring, pullfd); if (r == 0) { /* eof */ close(pullfd); pullfd = -1; } else if (r < 0 && errno != EINTR && errno != EAGAIN) { perror("push_pump read()"); close(pullfd); pullfd = -1; return; } /* Push everything out to STDOUT */ while (!ring_buffer_empty_p(&ring)) { /* Blocking write() to pushfd (STDOUT_FILENO) */ r = ring_buffer_push(&ring, pushfd); /* If there was a problem, just exit the entire function */ if (r < 0 && errno != EINTR) { close(pushfd); close(pullfd); pushfd = pullfd = -1; return; } } if (pullfd >= 0) { /* select for readability on the pullfd */ r = select(pullfd+1, &readfds, NULL, &exceptfds, NULL); if (r < 0 || FD_ISSET(pullfd, &exceptfds)) { close(pushfd); close(pullfd); pushfd = pullfd = -1; return; } } } /* If we got here then we got eof on pullfd and pushed all the data out. * so now just close pushfd */ assert(pullfd < 0); assert(ring_buffer_empty_p(&ring)); close(pushfd); }
/* PULL PUMP * * This is used to read data from a blocking file descriptor and pump it into * a non-blocking pipe (or other non-blocking fd). The algorithm is this: * * while (true) { * read(STDIN_FILENO) // blocking * * while (!ring.empty) { * write(pipe) // non-blocking * select(pipe, writable) * } * } * */ static void pull_pump (int pullfd, int pushfd) { int r; ring_buffer ring; fd_set writefds, exceptfds; FD_ZERO(&exceptfds); FD_ZERO(&writefds); FD_SET(pushfd, &exceptfds); FD_SET(pushfd, &writefds); ring_buffer_init(&ring); while (pullfd >= 0) { /* Blocking read from STDIN_FILENO */ r = ring_buffer_pull(&ring, pullfd); if (r == 0) { /* eof */ close(pullfd); pullfd = -1; } else if (r < 0 && errno != EINTR && errno != EAGAIN) { /* error */ perror("pull_pump read()"); close(pullfd); pullfd = -1; } /* Push all of the data in the ring buffer out. */ while (!ring_buffer_empty_p(&ring)) { /* non-blocking write() to the pipe */ r = ring_buffer_push(&ring, pushfd); if (r < 0 && errno != EAGAIN && errno != EINTR) { if (errno == EPIPE) { /* This happens if someone closes the other end of the pipe. This * is a normal forced close of STDIN. Hopefully there wasn't data * in the ring buffer. Just close both ends and exit. */ close(pushfd); close(pullfd); pushfd = pullfd = -1; } else { perror("pull_pump write()"); close(pushfd); close(pullfd); } return; } /* Select for writablity on the pipe end. * Very rarely will this stick. */ r = select(pushfd+1, NULL, &writefds, &exceptfds, NULL); if (r < 0 || FD_ISSET(pushfd, &exceptfds)) { close(pushfd); close(pullfd); pushfd = pullfd = -1; return; } } } assert(pullfd < 0); assert(ring_buffer_empty_p(&ring)); close(pushfd); }