[3998] | 1 | /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
---|
| 2 | /* |
---|
| 3 | * Copyright (C) 2004-2013 HUBzero Foundation, LLC |
---|
| 4 | * |
---|
| 5 | * Author: George A. Howlett <gah@purdue.edu> |
---|
| 6 | */ |
---|
| 7 | |
---|
| 8 | #include <pthread.h> |
---|
| 9 | #include <semaphore.h> |
---|
| 10 | #include <cerrno> |
---|
| 11 | #include <cstring> |
---|
| 12 | #include <cstdlib> |
---|
| 13 | #include <list> |
---|
| 14 | |
---|
| 15 | #include "Trace.h" |
---|
| 16 | #include "ResponseQueue.h" |
---|
| 17 | |
---|
| 18 | using namespace GeoVis; |
---|
| 19 | |
---|
| 20 | ResponseQueue::ResponseQueue() |
---|
| 21 | { |
---|
| 22 | pthread_mutex_init(&_idle, NULL); |
---|
| 23 | if (sem_init(&_ready, 0, 0) < 0) { |
---|
| 24 | ERROR("can't initialize semaphore: %s", strerror(errno)); |
---|
| 25 | } |
---|
| 26 | } |
---|
| 27 | |
---|
[4629] | 28 | ResponseQueue::~ResponseQueue() |
---|
[3998] | 29 | { |
---|
| 30 | TRACE("Deleting ResponseQueue"); |
---|
| 31 | pthread_mutex_destroy(&_idle); |
---|
| 32 | if (sem_destroy(&_ready) < 0) { |
---|
| 33 | ERROR("can't destroy semaphore: %s", strerror(errno)); |
---|
| 34 | } |
---|
| 35 | for (std::list<Response *>::iterator itr = _list.begin(); |
---|
| 36 | itr != _list.end(); ++itr) { |
---|
| 37 | delete *itr; |
---|
| 38 | } |
---|
| 39 | _list.clear(); |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | void |
---|
| 43 | ResponseQueue::enqueue(Response *response) |
---|
| 44 | { |
---|
| 45 | if (pthread_mutex_lock(&_idle) != 0) { |
---|
| 46 | ERROR("can't lock mutex: %s", strerror(errno)); |
---|
[4629] | 47 | } |
---|
| 48 | #ifdef QUEUE_ONLY_ONE_FRAME |
---|
[3998] | 49 | /* Examine the list and remove any queued responses of the same type. */ |
---|
[5915] | 50 | #ifdef TRACE_RESPONSE_QUEUE |
---|
[3998] | 51 | TRACE("Before # of elements is %d", _list.size()); |
---|
[5915] | 52 | #endif |
---|
[3998] | 53 | for (std::list<Response *>::iterator itr = _list.begin(); |
---|
| 54 | itr != _list.end();) { |
---|
[4629] | 55 | /* Remove any duplicate image or legend responses. There should be no |
---|
| 56 | * more than one. Note that if the client starts using multiple legends |
---|
[3998] | 57 | * for different fields, this optimization should be disabled for legends. |
---|
| 58 | * We may also need to differentiate between screen images and "hardcopy" |
---|
| 59 | * images. |
---|
| 60 | */ |
---|
| 61 | if ((response->type() == Response::IMAGE || |
---|
| 62 | response->type() == Response::LEGEND) && |
---|
| 63 | (*itr)->type() == response->type()) { |
---|
| 64 | TRACE("Removing duplicate response of type: %d", (*itr)->type()); |
---|
| 65 | delete *itr; |
---|
| 66 | itr = _list.erase(itr); |
---|
| 67 | } else { |
---|
[5930] | 68 | #ifdef TRACE_RESPONSE_QUEUE |
---|
[3998] | 69 | TRACE("Found queued response of type %d", (*itr)->type()); |
---|
[5930] | 70 | #endif |
---|
[3998] | 71 | ++itr; |
---|
| 72 | } |
---|
| 73 | } |
---|
[4629] | 74 | #endif |
---|
[3998] | 75 | /* Add the new response to the end of the list. */ |
---|
| 76 | _list.push_back(response); |
---|
[5915] | 77 | #ifdef TRACE_RESPONSE_QUEUE |
---|
[3998] | 78 | TRACE("After # of elements is %d", _list.size()); |
---|
[5915] | 79 | #endif |
---|
[3998] | 80 | if (sem_post(&_ready) < 0) { |
---|
| 81 | ERROR("can't post semaphore: %s", strerror(errno)); |
---|
| 82 | } |
---|
| 83 | if (pthread_mutex_unlock(&_idle) != 0) { |
---|
| 84 | ERROR("can't unlock mutex: %s", strerror(errno)); |
---|
[4629] | 85 | } |
---|
[3998] | 86 | } |
---|
| 87 | |
---|
| 88 | Response * |
---|
| 89 | ResponseQueue::dequeue() |
---|
| 90 | { |
---|
| 91 | Response *response = NULL; |
---|
| 92 | |
---|
| 93 | int ret; |
---|
| 94 | while ((ret = sem_wait(&_ready)) < 0 && errno == EINTR) |
---|
| 95 | continue; |
---|
| 96 | if (ret < 0) { |
---|
| 97 | ERROR("can't wait on semaphore: %s", strerror(errno)); |
---|
| 98 | } |
---|
| 99 | if (pthread_mutex_lock(&_idle) != 0) { |
---|
| 100 | ERROR("can't lock mutex: %s", strerror(errno)); |
---|
| 101 | } |
---|
| 102 | /* List may be empty if semaphore value was incremented beyond list |
---|
| 103 | * size in the case of an enqueue operation deleting from the queue |
---|
| 104 | * This is not an error, so just unlock and return to wait loop |
---|
| 105 | */ |
---|
| 106 | if (_list.empty()) { |
---|
| 107 | TRACE("Empty queue"); |
---|
| 108 | } else { |
---|
| 109 | response = _list.front(); |
---|
| 110 | _list.pop_front(); |
---|
[5915] | 111 | #ifdef TRACE_RESPONSE_QUEUE |
---|
[3998] | 112 | TRACE("Dequeued response of type %d", response->type()); |
---|
[5915] | 113 | #endif |
---|
[3998] | 114 | } |
---|
| 115 | if (pthread_mutex_unlock(&_idle) != 0) { |
---|
| 116 | ERROR("can't unlock mutex: %s", strerror(errno)); |
---|
[4629] | 117 | } |
---|
[3998] | 118 | return response; |
---|
| 119 | } |
---|