Advertisement
rootmese

Simple Circle Buffer Algorithm

May 2nd, 2025
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.77 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <signal.h>
  7. #include <sys/queue.h>
  8.  
  9. #define BUFFER_SIZE 16
  10.  
  11. struct node {
  12.     int value;
  13.     CIRCLEQ_ENTRY(node) circleq;
  14.     TAILQ_ENTRY(node) tailq;
  15. };
  16.  
  17. CIRCLEQ_HEAD(circleq_head, node);
  18. TAILQ_HEAD(tailq_fifo, node);
  19.  
  20. struct circle_buffer {
  21.     struct node* buffer;
  22.     struct node* cursor;
  23.     struct circleq_head head;
  24.     struct tailq_fifo* fifo;
  25.  
  26.     size_t buffer_size;
  27.     size_t count;
  28.     pthread_mutex_t fifo_lock;
  29.     pthread_t fifo_thread;
  30.  
  31.     void (*process)(struct circle_buffer*, struct node*);
  32.     void (*enqueue)(struct circle_buffer*, struct node*);
  33.     struct node* (*get_slot)(struct circle_buffer*, size_t);
  34.     struct node* (*get_current_node)(struct circle_buffer*);
  35.     void (*start_processing)(struct circle_buffer*, void (*)(struct circle_buffer*, struct node*));
  36. };
  37.  
  38. static void setup_signal_handler() {
  39.     struct sigaction sa;
  40.     memset(&sa, 0, sizeof(sa));
  41.     sa.sa_handler = sigusr1_handler;
  42.     sigaction(SIGUSR1, &sa, NULL);
  43. }
  44.  
  45. static void* fifo_worker(void* arg) {
  46.     struct circle_buffer* this = (struct circle_buffer*)arg;
  47.  
  48.     do {
  49.         while (!TAILQ_EMPTY(this->fifo)) {
  50.             pthread_mutex_lock(&this->fifo_lock);
  51.             struct node* n = TAILQ_FIRST(this->fifo);
  52.             if (n)
  53.                 TAILQ_REMOVE(this->fifo, n, tailq);
  54.             pthread_mutex_unlock(&this->fifo_lock);
  55.  
  56.             if (this->process)
  57.                 this->process(this, n);
  58.  
  59.         }
  60.         usleep(200); // leve delay para evitar busy wait
  61.     } while (~0);
  62.     return 0;
  63. }
  64.  
  65. void enqueue(struct circle_buffer* this, struct node* n) {
  66.     if (!n) return;
  67.     pthread_mutex_lock(&this->fifo_lock);
  68.     TAILQ_INSERT_TAIL(this->fifo, n, tailq);
  69.     pthread_mutex_unlock(&this->fifo_lock);
  70. }
  71.  
  72. struct node* get_slot(struct circle_buffer* this, size_t index) {
  73.     if (index >= this->buffer_size)
  74.         return 0;
  75.     return (this->buffer + index);
  76. }
  77.  
  78. struct node* get_current_node(struct circle_buffer* this) {
  79.     if (!this->cursor || this->cursor == CIRCLEQ_END(&this->head))
  80.         return 0;
  81.  
  82.     struct node* current = this->cursor;
  83.     this->cursor = CIRCLEQ_NEXT(current, circleq);
  84.     if (this->cursor == CIRCLEQ_END(&this->head))
  85.         this->cursor = CIRCLEQ_FIRST(&this->head);
  86.  
  87.     return current;
  88. }
  89.  
  90. void start_processing(struct circle_buffer* this, void (*callback)(struct circle_buffer*, struct node*)) {
  91.     this->process = callback;
  92.     pthread_create(&this->fifo_thread, 0, fifo_worker, this);
  93. }
  94.  
  95. void process_node(struct circle_buffer* cb, struct node* n) {
  96.     if (!cb || !n) return;
  97.  
  98.     struct node* slot = cb->get_current_node(cb);
  99.     if (slot) {
  100.         memcpy(slot, n, sizeof(struct node));
  101.         printf("[worker] processou node com valor %d\n", slot->value);
  102.     }
  103. }
  104.  
  105. struct circle_buffer* new_circle_buffer(size_t size, struct tailq_fifo* fifo) {
  106.     int i;
  107.     struct circle_buffer* cb = calloc(1, sizeof(struct circle_buffer));
  108.     if (!cb)
  109.         return 0;
  110.  
  111.     cb->buffer_size = size;
  112.     cb->buffer = calloc(size, sizeof(struct node));
  113.     if (!cb->buffer) {
  114.         free(cb);
  115.         return 0;
  116.     }
  117.  
  118.     CIRCLEQ_INIT(&cb->head);
  119.     cb->fifo = fifo;
  120.  
  121.     i = 0;
  122.     do
  123.     {
  124.         CIRCLEQ_INSERT_TAIL(&cb->head, (cb->buffer + i), circleq);
  125.     } while (++i < size);
  126.  
  127.     cb->cursor = CIRCLEQ_EMPTY(&cb->head) ? 0 : CIRCLEQ_FIRST(&cb->head);
  128.     pthread_mutex_init(&cb->fifo_lock, 0);
  129.  
  130.     cb->enqueue = enqueue;
  131.     cb->get_slot = get_slot;
  132.     cb->get_current_node = get_current_node;
  133.     cb->start_processing = start_processing;
  134.  
  135.     return cb;
  136. }
  137.  
  138. // --- SIGNAL HANDLER ---
  139. struct circle_buffer* global_cb = NULL;
  140.  
  141. void sigusr1_handler(int sig) {
  142.     if (global_cb) {
  143.         printf("\n[SIGNAL] Recebido SIGUSR1. Cancelando thread fifo_worker...\n");
  144.         pthread_cancel(global_cb->fifo_thread);
  145.         pthread_join(global_cb->fifo_thread, NULL);
  146.         printf("[SIGNAL] Thread finalizada com sucesso.\n");
  147.     }
  148.     exit(0);
  149. }
  150.  
  151. int main() {
  152.     signal(SIGUSR1, sigusr1_handler);
  153.  
  154.     struct tailq_fifo fifo;
  155.     TAILQ_INIT(&fifo);
  156.  
  157.     struct circle_buffer* cb = new_circle_buffer(BUFFER_SIZE, &fifo);
  158.     if (!cb) {
  159.         fprintf(stderr, "Erro ao criar circle_buffer\n");
  160.         return 1;
  161.     }
  162.  
  163.     global_cb = cb;
  164.     cb->start_processing(cb, process_node);
  165.  
  166.     // Simula socket_receiver jogando valores
  167.     for (int i = 0; i < 10; ++i) {
  168.         struct node* temp = malloc(sizeof(struct node));
  169.         temp->value = 100 + i;
  170.         cb->enqueue(cb, temp);
  171.         usleep(30000);
  172.     }
  173.  
  174.     printf(">>> Processo principal aguardando sinal SIGUSR1 (kill -USR1 %d)\n", getpid());
  175.     pause();
  176.     return 0;
  177. }
  178.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement