Advertisement
danielhilst

arrayfifo.c

Oct 20th, 2014
182
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.40 KB | None | 0 0
  1. /**
  2.  * Simple circular event queue using ints with a asynchronous, user
  3.  * provided handler (consumer). All locked by it self. Using pthread.
  4.  *
  5.  * Is intended to work only with positive integers
  6.  *
  7.  * This can be used to delay work on places where you need to return fast.
  8.  *
  9.  * compiling: gcc -o arayfifo arrayfifo.c -lpthread
  10.  */
  11.  
  12. #include <assert.h>
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #include <pthread.h>
  16.  
  17. #define EVQ_MAX 10
  18. #define EVQ_SIZ (EVQ_MAX - 1)
  19.  
  20. struct evqueue {
  21.         int ev[EVQ_MAX];
  22.         int start;
  23.         int end;
  24.         pthread_mutex_t lock;
  25.         pthread_cond_t cond;
  26.         pthread_t task;
  27.         void (*user_handler)(int);
  28. };
  29.  
  30. #define evq_diff(q) (((q)->end + 1) % EVQ_MAX)
  31. #define evq_full(q) ((q)->start == evq_diff(q))
  32. #define evq_empty(q) ((q)->start == (q)->end)
  33.  
  34. /* Signal user's callback that queue has events
  35.  * to be processed
  36.  *
  37.  * q => The queue
  38.  */
  39. void evq_signal(struct evqueue *q)
  40. {
  41.         pthread_cond_signal(&q->cond);
  42. }
  43.  
  44. /* Unqueue event and return to user
  45.  *
  46.  * Returns the event on success and -1 on error.
  47.  */
  48. int evq_get(struct evqueue *q)
  49. {
  50.         int ev;
  51.  
  52.         pthread_mutex_lock(&q->lock);
  53.         if (evq_empty(q)) {
  54.                 ev = -1;
  55.         } else {
  56.                 ev = q->ev[q->start];
  57.                 q->start = (q->start + 1) % EVQ_MAX;
  58.         }
  59.         pthread_mutex_unlock(&q->lock);
  60.         return ev;
  61. }
  62.  
  63. /* this is not part if API :-P */
  64. static void *evq_handler(void *evq)
  65. {
  66.         struct evqueue *evqp = evq;
  67.  
  68.         printf("Starting event handler\n");
  69.         for (;;) {
  70.                 pthread_mutex_lock(&evqp->lock);
  71.                 while (evq_empty(evqp))
  72.                         pthread_cond_wait(&evqp->cond, &evqp->lock);
  73.                 pthread_mutex_unlock(&evqp->lock);
  74.  
  75.                 evqp->user_handler(evq_get(evqp));
  76.         }
  77. }
  78.  
  79. /* Initialize queue, it has to be allocated first
  80.  * Second argument is the user callback handler.
  81.  *
  82.  * Is called asynchronously every time use calls
  83.  * evq_signal() and queue is not empty.
  84.  *
  85.  * The prototype is void handler(int), the event to be
  86.  * processed is passed as only parameter.
  87.  */
  88. void evq_init(struct evqueue *q, void (*handler)(int))
  89. {
  90.         assert(q);
  91.         assert(handler);
  92.  
  93.         q->start = q->end = 0;
  94.         q->user_handler = handler;
  95.         pthread_mutex_init(&q->lock, NULL);
  96.         pthread_cond_init(&q->cond, NULL);
  97.         pthread_create(&q->task, NULL, evq_handler, q);
  98. }
  99.  
  100. /* Enqueue and event to the queue
  101.  *
  102.  * Returns 0 on success and -1 on error
  103.  */
  104. int evq_put(struct evqueue *q, int ev)
  105. {
  106.         int rc = 0;
  107.  
  108.         pthread_mutex_lock(&q->lock);
  109.         if (evq_full(q)) {
  110.                 rc = -1;
  111.         } else {
  112.                 q->ev[q->end] = ev;
  113.                 q->end = (q->end + 1) % EVQ_MAX;
  114.         }
  115.         pthread_mutex_unlock(&q->lock);
  116.         return rc;
  117. }
  118.  
  119.  
  120. /* --------- User stuff ------------- */
  121.  
  122. /* Declare a queue */
  123. static struct evqueue evq;
  124.  
  125. /* Declare a hanlder */
  126. void my_handler(int ev)
  127. {
  128.         printf("Handling event on user handler %d\n", ev);
  129. }
  130.                
  131.  
  132. int main(void)
  133. {
  134.         int i;
  135.  
  136.         /* Initialize the queue */
  137.         evq_init(&evq, my_handler);
  138.        
  139.         for (i = 0; i < 2000000 ; i++) {
  140.                 if (evq_put(&evq, i)) { /* Enqueue events */
  141.                         puts("Full");
  142.                         usleep(20 * 1000);
  143.                 }
  144.                 evq_signal(&evq); /* Ask for their processing */
  145.         }
  146.  
  147.         return 0;
  148. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement