1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #ifndef MessageQueue_h 31 #define MessageQueue_h 32 33 #include <limits> 34 #include "wtf/Assertions.h" 35 #include "wtf/Deque.h" 36 #include "wtf/Noncopyable.h" 37 #include "wtf/OwnPtr.h" 38 #include "wtf/PassOwnPtr.h" 39 #include "wtf/ThreadingPrimitives.h" 40 41 namespace WTF { 42 43 enum MessageQueueWaitResult { 44 MessageQueueTerminated, // Queue was destroyed while waiting for message. 45 MessageQueueTimeout, // Timeout was specified and it expired. 46 MessageQueueMessageReceived // A message was successfully received and returned. 47 }; 48 49 // The queue takes ownership of messages and transfer it to the new owner 50 // when messages are fetched from the queue. 51 // Essentially, MessageQueue acts as a queue of OwnPtr<DataType>. 52 template<typename DataType> 53 class MessageQueue { 54 WTF_MAKE_NONCOPYABLE(MessageQueue); 55 public: 56 MessageQueue() : m_killed(false) { } 57 58 // Returns true if the queue is still alive, false if the queue has been killed. 59 bool append(PassOwnPtr<DataType>); 60 void appendAndKill(PassOwnPtr<DataType>); 61 bool appendAndCheckEmpty(PassOwnPtr<DataType>); 62 void prepend(PassOwnPtr<DataType>); 63 64 PassOwnPtr<DataType> waitForMessage(); 65 PassOwnPtr<DataType> tryGetMessage(); 66 PassOwnPtr<DataType> tryGetMessageIgnoringKilled(); 67 PassOwnPtr<DataType> waitForMessageWithTimeout(MessageQueueWaitResult&, double absoluteTime); 68 69 void kill(); 70 bool killed() const; 71 72 // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time. 73 bool isEmpty(); 74 75 static double infiniteTime() { return std::numeric_limits<double>::max(); } 76 77 private: 78 mutable Mutex m_mutex; 79 ThreadCondition m_condition; 80 Deque<OwnPtr<DataType> > m_queue; 81 bool m_killed; 82 }; 83 84 template<typename DataType> 85 inline bool MessageQueue<DataType>::append(PassOwnPtr<DataType> message) 86 { 87 MutexLocker lock(m_mutex); 88 m_queue.append(message); 89 m_condition.signal(); 90 return !m_killed; 91 } 92 93 template<typename DataType> 94 inline void MessageQueue<DataType>::appendAndKill(PassOwnPtr<DataType> message) 95 { 96 MutexLocker lock(m_mutex); 97 m_queue.append(message); 98 m_killed = true; 99 m_condition.broadcast(); 100 } 101 102 // Returns true if the queue was empty before the item was added. 103 template<typename DataType> 104 inline bool MessageQueue<DataType>::appendAndCheckEmpty(PassOwnPtr<DataType> message) 105 { 106 MutexLocker lock(m_mutex); 107 bool wasEmpty = m_queue.isEmpty(); 108 m_queue.append(message); 109 m_condition.signal(); 110 return wasEmpty; 111 } 112 113 template<typename DataType> 114 inline void MessageQueue<DataType>::prepend(PassOwnPtr<DataType> message) 115 { 116 MutexLocker lock(m_mutex); 117 m_queue.prepend(message); 118 m_condition.signal(); 119 } 120 121 template<typename DataType> 122 inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessage() 123 { 124 MessageQueueWaitResult exitReason; 125 OwnPtr<DataType> result = waitForMessageWithTimeout(exitReason, infiniteTime()); 126 ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived); 127 return result.release(); 128 } 129 130 template<typename DataType> 131 inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessageWithTimeout(MessageQueueWaitResult& result, double absoluteTime) 132 { 133 MutexLocker lock(m_mutex); 134 bool timedOut = false; 135 136 while (!m_killed && !timedOut && m_queue.isEmpty()) 137 timedOut = !m_condition.timedWait(m_mutex, absoluteTime); 138 139 ASSERT(!timedOut || absoluteTime != infiniteTime()); 140 141 if (m_killed) { 142 result = MessageQueueTerminated; 143 return nullptr; 144 } 145 146 if (timedOut) { 147 result = MessageQueueTimeout; 148 return nullptr; 149 } 150 151 ASSERT_WITH_SECURITY_IMPLICATION(!m_queue.isEmpty()); 152 result = MessageQueueMessageReceived; 153 154 return m_queue.takeFirst(); 155 } 156 157 template<typename DataType> 158 inline PassOwnPtr<DataType> MessageQueue<DataType>::tryGetMessage() 159 { 160 MutexLocker lock(m_mutex); 161 if (m_killed) 162 return nullptr; 163 if (m_queue.isEmpty()) 164 return nullptr; 165 166 return m_queue.takeFirst(); 167 } 168 169 template<typename DataType> 170 inline PassOwnPtr<DataType> MessageQueue<DataType>::tryGetMessageIgnoringKilled() 171 { 172 MutexLocker lock(m_mutex); 173 if (m_queue.isEmpty()) 174 return nullptr; 175 176 return m_queue.takeFirst(); 177 } 178 179 template<typename DataType> 180 inline bool MessageQueue<DataType>::isEmpty() 181 { 182 MutexLocker lock(m_mutex); 183 if (m_killed) 184 return true; 185 return m_queue.isEmpty(); 186 } 187 188 template<typename DataType> 189 inline void MessageQueue<DataType>::kill() 190 { 191 MutexLocker lock(m_mutex); 192 m_killed = true; 193 m_condition.broadcast(); 194 } 195 196 template<typename DataType> 197 inline bool MessageQueue<DataType>::killed() const 198 { 199 MutexLocker lock(m_mutex); 200 return m_killed; 201 } 202 } // namespace WTF 203 204 using WTF::MessageQueue; 205 // MessageQueueWaitResult enum and all its values. 206 using WTF::MessageQueueWaitResult; 207 using WTF::MessageQueueTerminated; 208 using WTF::MessageQueueTimeout; 209 using WTF::MessageQueueMessageReceived; 210 211 #endif // MessageQueue_h 212