这是一个简单的C程序,它将在管道输入和输出之间保持循环缓冲区.在|中使用buffer_program |出.错误检查省略.坚固性不保证.给出了一般的想法.

测试脚本(但实际上,因为它的循环缓冲区需要管道中的数据,以便它只需要流中的任何块.或者只是使缓冲区大于数据):

cat some.wav | ./circular_buffer 100000 | (sleep 1 && aplay)

circular_buffer.c:

/**

* This program simply maintains a circular buffer of a given size indefinitely.

*/

#include

#include

#include

#include

#include /* C99 only */

#include

#include

#include

int c_read(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in);

int c_write(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in);

bool empty_buf(unsigned int head, unsigned int tail);

bool setblock(int fd, bool block);

#define FD_SET_SET(set, fd, max) FD_SET(fd, &set); max = ((fd > max) ? fd : max);

#define FD_SET_UNSET(set, fd, max) FD_CLR(fd, &set); max = ((fd == max) ? max - 1 : max); //not ideal. Do while ISFDSET...

int main(int argc, char **argv)

{

char * buf;

unsigned int buf_size = 0;

unsigned int buf_head = 0;

unsigned int buf_tail = 0;

// Check args.

if(argc != 2) {

fprintf(stderr, "Usage: %s \n", __FILE__);

exit(EXIT_FAILURE);

}

sscanf(argv[1], "%d", &buf_size);

buf_size = ( buf_size < 2 ) ? 2 : buf_size;

// Note the usable buffer space is buf_size-1.

fprintf(stderr, "Allocating %d\n", buf_size);

buf = (char*)malloc(buf_size);

bool done_reading = false;

int maxfd = 0;

fd_set r_set, w_set, r_tempset, w_tempset;

setblock(STDIN_FILENO, false);

setblock(STDOUT_FILENO, false);

FD_ZERO(&r_set);

FD_ZERO(&w_set);

FD_ZERO(&r_tempset);

FD_ZERO(&w_tempset);

FD_SET_SET(r_tempset, STDIN_FILENO, maxfd);

FD_SET_SET(w_tempset, STDOUT_FILENO, maxfd);

r_set = r_tempset;

while(true) {

select((maxfd + 1), &r_set, &w_set, NULL, NULL);

if(FD_ISSET(STDIN_FILENO, &r_set)) {

int c = c_read(STDIN_FILENO, buf, buf_size, &buf_head, &buf_tail);

if(c == -1) { // EOF, disable select on the input.

fprintf(stderr, "No more bytes to read\n");

done_reading = true;

FD_ZERO(&r_set);

}

}

if(!done_reading) {

r_set = r_tempset;

}

if(FD_ISSET(STDOUT_FILENO, &w_set)) {

c_write(STDOUT_FILENO, buf, buf_size, &buf_head, &buf_tail);

}

if(!empty_buf(buf_head, buf_tail)) { // Enable select on write whenever there is bytes.

w_set = w_tempset;

}

else {

FD_ZERO(&w_set);

if(done_reading) { // Finish.

fprintf(stderr, "No more bytes to write\n");

break;

}

}

}

fflush(stderr);

return 0;

}

bool empty_buf(unsigned int head, unsigned int tail) {

return head == tail;

}

/**

* Keep reading until we can read no more. Keep on pushing the tail forward as we overflow.

* Expects fd to be non blocking.

* @returns number of byte read, 0 on non stopping error, or -1 on error or EOF.

*/

int c_read(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in) {

fprintf(stderr, "In c_read()\n");

unsigned int head = *head_in;

unsigned int tail = *tail_in;

bool more_bytes = true;

int n = 0;

int c = 0;

while(more_bytes) {

bool in_front = tail > head;

fprintf(stderr, "Read %d %d %d\n", size, head, tail);

n = read(fd, buf+head, size - head);

if(n == -1) {

more_bytes = false;

if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // Not EOF but the read would block.

c = 0;

}

else {

c = -1;

}

}

else if(n == 0) { // EOF. No more bytes possible.

more_bytes = false;

c = -1;

}

else if(n != (size - head)) { // if not full read adjust pointers and break.

more_bytes = false;

c += n;

head = (head+n)%size;

if(in_front && (head >= tail || head == 0)) {

tail = (head+1)%size;

}

}

else {

c = 0;

head = 0;

tail = (tail == 0) ? 1 : tail;

}

}

*head_in = head;

*tail_in = tail;

return c;

}

/**

* Try flush the buffer to fd. fd should be non blocking.

*/

int c_write(int fd, char * buf, unsigned int size, unsigned int * head_in, unsigned int * tail_in) {

fprintf(stderr, "In c_write()\n");

unsigned int head = *head_in;

unsigned int tail = *tail_in;

int n = 0;

fprintf(stderr, "Write %d %d %d\n", size, head, tail);

if(tail < head) {

n = write(fd, buf+tail, head-tail);

tail += n;

}

else if(head < tail) {

n = write(fd, buf+tail, size-tail);

if(n == size-tail) {

n = write(fd, buf, head);

tail = n;

}

}

*head_in = head;

*tail_in = tail;

return n;

}

bool setblock(int fd, bool block)

{

int flags;

flags = fcntl(fd, F_GETFL);

if (block)

flags &= ~O_NONBLOCK;

else

flags |= O_NONBLOCK;

fcntl(fd, F_SETFL, flags);

return true;

}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐