Home | History | Annotate | Download | only in wtf
      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