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