1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "MessageThread"
27
28#include "config.h"
29
30#include <sys/time.h>
31#include <time.h>
32
33#include "MessageThread.h"
34#include "ScriptController.h"
35
36#include <utils/Log.h>
37
38namespace android {
39
40static bool compareMessages(const Message& msg1,
41                            const Message& msg2,
42                            bool memberIsNull) {
43    return (msg1.object() == msg2.object() &&
44            (memberIsNull || msg1.member() == msg2.member()));
45}
46
47bool MessageQueue::hasMessages(const Message& message) {
48    AutoMutex lock(m_mutex);
49
50    static const Message::GenericMemberFunction nullMember = NULL;
51    const bool memberIsNull = message.member() == nullMember;
52
53    for (list<Message*>::iterator it = m_messages.begin();
54         it != m_messages.end(); ++it) {
55        Message* m = *it;
56        if (compareMessages(message, *m, memberIsNull))
57            return true;
58    }
59    return false;
60}
61
62void MessageQueue::remove(const Message& message) {
63    AutoMutex lock(m_mutex);
64
65    static const Message::GenericMemberFunction nullMember = NULL;
66    const bool memberIsNull = message.member() == nullMember;
67
68    for (list<Message*>::iterator it = m_messages.begin();
69         it != m_messages.end(); ++it) {
70        Message* m = *it;
71        if (compareMessages(message, *m, memberIsNull)) {
72            it = m_messages.erase(it);
73            delete m;
74        }
75    }
76}
77
78void MessageQueue::post(Message* message) {
79    AutoMutex lock(m_mutex);
80
81    double when = message->m_when;
82    ALOG_ASSERT(when > 0, "Message time may not be 0");
83
84    list<Message*>::iterator it;
85    for (it = m_messages.begin(); it != m_messages.end(); ++it) {
86        Message* m = *it;
87        if (when < m->m_when) {
88            break;
89        }
90    }
91    m_messages.insert(it, message);
92    m_condition.signal();
93}
94
95void MessageQueue::postAtFront(Message* message) {
96    AutoMutex lock(m_mutex);
97    message->m_when = 0;
98    m_messages.push_front(message);
99}
100
101Message* MessageQueue::next() {
102    AutoMutex lock(m_mutex);
103    while (true) {
104        if (m_messages.empty()) {
105            // No messages, wait until another arrives
106            m_condition.wait(m_mutex);
107        }
108        Message* next = m_messages.front();
109        double now = WTF::currentTimeMS();
110        double diff = next->m_when - now;
111        if (diff > 0) {
112            // Not time for this message yet, wait the difference in nanos
113            m_condition.waitRelative(m_mutex,
114                    static_cast<nsecs_t>(diff * 1000000) /* nanos */);
115        } else {
116            // Time for this message to run.
117            m_messages.pop_front();
118            return next;
119        }
120    }
121}
122
123bool MessageThread::threadLoop() {
124    WebCore::ScriptController::initializeThreading();
125
126    while (true) {
127        Message* message = m_queue.next();
128        if (message != NULL) {
129            message->run();
130        }
131    }
132    return false;
133}
134
135// Global thread object obtained by messageThread().
136static sp<MessageThread> gMessageThread;
137
138MessageThread* messageThread() {
139    if (gMessageThread == NULL) {
140        gMessageThread = new MessageThread();
141        gMessageThread->run("WebCoreThread");
142    }
143    return gMessageThread.get();
144}
145
146}  // namespace android
147