• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Threading.h>
38 
39 namespace WTF {
40 
41     enum MessageQueueWaitResult {
42         MessageQueueTerminated,       // Queue was destroyed while waiting for message.
43         MessageQueueTimeout,          // Timeout was specified and it expired.
44         MessageQueueMessageReceived,  // A message was successfully received and returned.
45     };
46 
47     template<typename DataType>
48     class MessageQueue : public Noncopyable {
49     public:
MessageQueue()50         MessageQueue() : m_killed(false) { }
51 
52         void append(const DataType&);
53         bool appendAndCheckEmpty(const DataType&);
54         void prepend(const DataType&);
55         bool waitForMessage(DataType&);
56         template<typename Predicate>
57         MessageQueueWaitResult waitForMessageFilteredWithTimeout(DataType&, Predicate&, double absoluteTime);
58         void kill();
59 
60         bool tryGetMessage(DataType&);
61         bool killed() const;
62 
63         // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time.
64         bool isEmpty();
65 
infiniteTime()66         static double infiniteTime() { return std::numeric_limits<double>::max(); }
67 
68     private:
alwaysTruePredicate(DataType &)69         static bool alwaysTruePredicate(DataType&) { return true; }
70 
71         mutable Mutex m_mutex;
72         ThreadCondition m_condition;
73         Deque<DataType> m_queue;
74         bool m_killed;
75     };
76 
77     template<typename DataType>
append(const DataType & message)78     inline void MessageQueue<DataType>::append(const DataType& message)
79     {
80         MutexLocker lock(m_mutex);
81         m_queue.append(message);
82         m_condition.signal();
83     }
84 
85     // Returns true if the queue was empty before the item was added.
86     template<typename DataType>
appendAndCheckEmpty(const DataType & message)87     inline bool MessageQueue<DataType>::appendAndCheckEmpty(const DataType& message)
88     {
89         MutexLocker lock(m_mutex);
90         bool wasEmpty = m_queue.isEmpty();
91         m_queue.append(message);
92         m_condition.signal();
93         return wasEmpty;
94     }
95 
96     template<typename DataType>
prepend(const DataType & message)97     inline void MessageQueue<DataType>::prepend(const DataType& message)
98     {
99         MutexLocker lock(m_mutex);
100         m_queue.prepend(message);
101         m_condition.signal();
102     }
103 
104     template<typename DataType>
waitForMessage(DataType & result)105     inline bool MessageQueue<DataType>::waitForMessage(DataType& result)
106     {
107         MessageQueueWaitResult exitReason = waitForMessageFilteredWithTimeout(result, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime());
108         ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived);
109         return exitReason == MessageQueueMessageReceived;
110     }
111 
112     template<typename DataType>
113     template<typename Predicate>
waitForMessageFilteredWithTimeout(DataType & result,Predicate & predicate,double absoluteTime)114     inline MessageQueueWaitResult MessageQueue<DataType>::waitForMessageFilteredWithTimeout(DataType& result, Predicate& predicate, double absoluteTime)
115     {
116         MutexLocker lock(m_mutex);
117         bool timedOut = false;
118 
119         DequeConstIterator<DataType> found = m_queue.end();
120         while (!m_killed && !timedOut && (found = m_queue.findIf(predicate)) == m_queue.end())
121             timedOut = !m_condition.timedWait(m_mutex, absoluteTime);
122 
123         ASSERT(!timedOut || absoluteTime != infiniteTime());
124 
125         if (m_killed)
126             return MessageQueueTerminated;
127 
128         if (timedOut)
129             return MessageQueueTimeout;
130 
131         ASSERT(found != m_queue.end());
132         result = *found;
133         m_queue.remove(found);
134         return MessageQueueMessageReceived;
135     }
136 
137     template<typename DataType>
tryGetMessage(DataType & result)138     inline bool MessageQueue<DataType>::tryGetMessage(DataType& result)
139     {
140         MutexLocker lock(m_mutex);
141         if (m_killed)
142             return false;
143         if (m_queue.isEmpty())
144             return false;
145 
146         result = m_queue.first();
147         m_queue.removeFirst();
148         return true;
149     }
150 
151     template<typename DataType>
isEmpty()152     inline bool MessageQueue<DataType>::isEmpty()
153     {
154         MutexLocker lock(m_mutex);
155         if (m_killed)
156             return true;
157         return m_queue.isEmpty();
158     }
159 
160     template<typename DataType>
kill()161     inline void MessageQueue<DataType>::kill()
162     {
163         MutexLocker lock(m_mutex);
164         m_killed = true;
165         m_condition.broadcast();
166     }
167 
168     template<typename DataType>
killed()169     inline bool MessageQueue<DataType>::killed() const
170     {
171         MutexLocker lock(m_mutex);
172         return m_killed;
173     }
174 } // namespace WTF
175 
176 using WTF::MessageQueue;
177 // MessageQueueWaitResult enum and all its values.
178 using WTF::MessageQueueWaitResult;
179 using WTF::MessageQueueTerminated;
180 using WTF::MessageQueueTimeout;
181 using WTF::MessageQueueMessageReceived;
182 
183 #endif // MessageQueue_h
184