Home | History | Annotate | Download | only in nacl_io
      1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include "queue.h"
      7 
      8 #include <pthread.h>
      9 #include <stdlib.h>
     10 
     11 #define MAX_QUEUE_SIZE 16
     12 
     13 /** A mutex that guards |g_queue|. */
     14 static pthread_mutex_t g_queue_mutex;
     15 
     16 /** A condition variable that is signalled when |g_queue| is not empty. */
     17 static pthread_cond_t g_queue_not_empty_cond;
     18 
     19 /** A circular queue of messages from JavaScript to be handled.
     20  *
     21  * If g_queue_start < g_queue_end:
     22  *   all elements in the range [g_queue_start, g_queue_end) are valid.
     23  * If g_queue_start > g_queue_end:
     24  *   all elements in the ranges [0, g_queue_end) and
     25  *   [g_queue_start, MAX_QUEUE_SIZE) are valid.
     26  * If g_queue_start == g_queue_end, and g_queue_size > 0:
     27  *   all elements in the g_queue are valid.
     28  * If g_queue_start == g_queue_end, and g_queue_size == 0:
     29  *   No elements are valid. */
     30 static char* g_queue[MAX_QUEUE_SIZE];
     31 
     32 /** The index of the head of the queue. */
     33 static int g_queue_start = 0;
     34 
     35 /** The index of the tail of the queue, non-inclusive. */
     36 static int g_queue_end = 0;
     37 
     38 /** The size of the queue. */
     39 static int g_queue_size = 0;
     40 
     41 /** Return whether the queue is empty.
     42  *
     43  * NOTE: this function assumes g_queue_mutex lock is held.
     44  * @return non-zero if the queue is empty. */
     45 static int IsQueueEmpty() { return g_queue_size == 0; }
     46 
     47 /** Return whether the queue is full.
     48  *
     49  * NOTE: this function assumes g_queue_mutex lock is held.
     50  * @return non-zero if the queue is full. */
     51 static int IsQueueFull() { return g_queue_size == MAX_QUEUE_SIZE; }
     52 
     53 /** Initialize the message queue. */
     54 void InitializeMessageQueue() {
     55   pthread_mutex_init(&g_queue_mutex, NULL);
     56   pthread_cond_init(&g_queue_not_empty_cond, NULL);
     57 }
     58 
     59 /** Enqueue a message (i.e. add to the end)
     60  *
     61  * If the queue is full, the message will be dropped.
     62  *
     63  * NOTE: this function assumes g_queue_mutex is _NOT_ held.
     64  * @param[in] message The message to enqueue.
     65  * @return non-zero if the message was added to the queue. */
     66 int EnqueueMessage(char* message) {
     67   pthread_mutex_lock(&g_queue_mutex);
     68 
     69   /* We shouldn't block the main thread waiting for the queue to not be full,
     70    * so just drop the message. */
     71   if (IsQueueFull()) {
     72     pthread_mutex_unlock(&g_queue_mutex);
     73     free(message);
     74     return 0;
     75   }
     76 
     77   g_queue[g_queue_end] = message;
     78   g_queue_end = (g_queue_end + 1) % MAX_QUEUE_SIZE;
     79   g_queue_size++;
     80 
     81   pthread_cond_signal(&g_queue_not_empty_cond);
     82 
     83   pthread_mutex_unlock(&g_queue_mutex);
     84 
     85   return 1;
     86 }
     87 
     88 /** Dequeue a message and return it.
     89  *
     90  * This function blocks until a message is available. It should not be called
     91  * on the main thread.
     92  *
     93  * NOTE: this function assumes g_queue_mutex is _NOT_ held.
     94  * @return The message at the head of the queue. */
     95 char* DequeueMessage() {
     96   char* message = NULL;
     97 
     98   pthread_mutex_lock(&g_queue_mutex);
     99 
    100   while (IsQueueEmpty()) {
    101     pthread_cond_wait(&g_queue_not_empty_cond, &g_queue_mutex);
    102   }
    103 
    104   message = g_queue[g_queue_start];
    105   g_queue_start = (g_queue_start + 1) % MAX_QUEUE_SIZE;
    106   g_queue_size--;
    107 
    108   pthread_mutex_unlock(&g_queue_mutex);
    109 
    110   return message;
    111 }
    112