+ /* A wrapper to launch the Nit main on a new thread. */
+ void* WrapperNitMain(void* arg) {
+ nit_main(0, NULL);
+ return NULL;
+ }
+
+ /** Return whether the queues are empty.
+ *
+ * NOTE: this function assumes g_queue_mutex lock is held.
+ * @return non-zero if the queue is empty. */
+ static int IsDictionaryQueueEmpty() { return g_dictionary_queue_size == 0; }
+ static int IsMessageQueueEmpty() { return g_message_queue_size == 0; }
+
+ /** Return whether the queues are full.
+ *
+ * NOTE: this function assumes g_queue_mutex lock is held.
+ * @return non-zero if the queue is full. */
+ static int IsDictionaryQueueFull() { return g_dictionary_queue_size == MAX_DICTIONARY_QUEUE_SIZE; }
+ static int IsMessageQueueFull() { return g_message_queue_size == MAX_MESSAGE_QUEUE_SIZE; }
+
+ /* Initialize the queues. */
+ void InitializeQueues() {
+ pthread_mutex_init(&g_dictionary_queue_mutex, NULL);
+ pthread_cond_init(&g_dictionary_queue_not_empty_cond, NULL);
+ pthread_mutex_init(&g_message_queue_mutex, NULL);
+ pthread_cond_init(&g_message_queue_not_empty_cond, NULL);
+ }
+
+ /** Enqueue a dictionary (i.e. add to the end)
+ *
+ * If the queue is full, the dictionary will be dropped.
+ *
+ * NOTE: this function assumes g_dictionary_queue_mutex is _NOT_ held.
+ * @param[in] dictionary, the dictionary to enqueue.
+ * @return non-zero if the dictionary was added to the queue. */
+ int EnqueueDictionary(struct PP_Var dictionary) {
+ pthread_mutex_lock(&g_dictionary_queue_mutex);
+
+ /* We shouldn't block the main thread waiting for the queue to not be full,
+ * so just drop the dictionary. */
+ if (IsDictionaryQueueFull()) {
+ pthread_mutex_unlock(&g_dictionary_queue_mutex);
+ return 0;
+ }
+
+ g_dictionary_queue[g_dictionary_queue_end] = dictionary;
+ g_dictionary_queue_end = (g_dictionary_queue_end + 1) % MAX_DICTIONARY_QUEUE_SIZE;
+ g_dictionary_queue_size++;
+
+ pthread_cond_signal(&g_dictionary_queue_not_empty_cond);
+
+ pthread_mutex_unlock(&g_dictionary_queue_mutex);
+
+ return 1;
+ }
+
+ /** Enqueue a message (i.e. add to the end)
+ *
+ * If the queue is full, the message will be dropped.
+ *
+ * NOTE: this function assumes g_message_queue_mutex is _NOT_ held.
+ * @param[in] message The message to enqueue.
+ * @return non-zero if the message was added to the queue. */
+ int EnqueueMessage(char* message) {
+ pthread_mutex_lock(&g_message_queue_mutex);
+
+ /* We shouldn't block the main thread waiting for the queue to not be full,
+ * so just drop the message. */
+ if (IsMessageQueueFull()) {
+ pthread_mutex_unlock(&g_message_queue_mutex);
+ return 0;
+ }
+
+ g_message_queue[g_message_queue_end] = message;
+ g_message_queue_end = (g_message_queue_end + 1) % MAX_MESSAGE_QUEUE_SIZE;
+ g_message_queue_size++;
+
+ pthread_cond_signal(&g_message_queue_not_empty_cond);
+
+ pthread_mutex_unlock(&g_message_queue_mutex);
+
+ return 1;
+ }
+
+ /** Dequeue a dictionary and return it.
+ *
+ * This function blocks until a dictionary is available. It should not be called
+ * on the main thread.
+ *
+ * NOTE: this function assumes g_dictionary_queue_mutex is _NOT_ held.
+ * @return The dictionary at the head of the queue. */
+ struct PP_Var DequeueDictionary() {
+ struct PP_Var dictionary = g_varDictionaryInterface->Create();
+
+ pthread_mutex_lock(&g_dictionary_queue_mutex);
+
+ while (IsDictionaryQueueEmpty()) {
+ pthread_cond_wait(&g_dictionary_queue_not_empty_cond, &g_dictionary_queue_mutex);
+ }
+
+ dictionary = g_dictionary_queue[g_dictionary_queue_start];
+ g_dictionary_queue_start = (g_dictionary_queue_start + 1) % MAX_DICTIONARY_QUEUE_SIZE;
+ g_dictionary_queue_size--;
+
+ pthread_mutex_unlock(&g_dictionary_queue_mutex);
+
+ return dictionary;
+ }
+
+ /** Dequeue a message and return it.
+ *
+ * This function blocks until a message is available. It should not be called
+ * on the main thread.
+ *
+ * NOTE: this function assumes g_queue_mutex is _NOT_ held.
+ * @return The message at the head of the queue. */
+ char* DequeueMessage() {
+ char* message = NULL;
+
+ pthread_mutex_lock(&g_message_queue_mutex);
+
+ while (IsMessageQueueEmpty()) {
+ pthread_cond_wait(&g_message_queue_not_empty_cond, &g_message_queue_mutex);
+ }
+
+ message = g_message_queue[g_message_queue_start];
+ g_message_queue_start = (g_message_queue_start + 1) % MAX_MESSAGE_QUEUE_SIZE;
+ g_message_queue_size--;
+
+ pthread_mutex_unlock(&g_message_queue_mutex);
+
+ return message;
+ }
+