• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdint.h>
18 #include <errno.h>
19 #include <sys/types.h>
20 
21 #include <utils/threads.h>
22 #include <utils/Timers.h>
23 #include <utils/Log.h>
24 #include <binder/IPCThreadState.h>
25 
26 #include "MessageQueue.h"
27 
28 namespace android {
29 
30 // ---------------------------------------------------------------------------
31 
insert(const sp<MessageBase> & node)32 void MessageList::insert(const sp<MessageBase>& node)
33 {
34     LIST::iterator cur(mList.begin());
35     LIST::iterator end(mList.end());
36     while (cur != end) {
37         if (*node < **cur) {
38             mList.insert(cur, node);
39             return;
40         }
41         ++cur;
42     }
43     mList.insert(++end, node);
44 }
45 
remove(MessageList::LIST::iterator pos)46 void MessageList::remove(MessageList::LIST::iterator pos)
47 {
48     mList.erase(pos);
49 }
50 
51 // ---------------------------------------------------------------------------
52 
MessageQueue()53 MessageQueue::MessageQueue()
54     : mInvalidate(false)
55 {
56     mInvalidateMessage = new MessageBase(INVALIDATE);
57 }
58 
~MessageQueue()59 MessageQueue::~MessageQueue()
60 {
61 }
62 
waitMessage(nsecs_t timeout)63 MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
64 {
65     MessageList::value_type result;
66 
67     bool again;
68     do {
69         const nsecs_t timeoutTime = systemTime() + timeout;
70         while (true) {
71             Mutex::Autolock _l(mLock);
72             nsecs_t now = systemTime();
73             nsecs_t nextEventTime = -1;
74 
75             // invalidate messages are always handled first
76             if (mInvalidate) {
77                 mInvalidate = false;
78                 mInvalidateMessage->when = now;
79                 result = mInvalidateMessage;
80                 break;
81             }
82 
83             LIST::iterator cur(mMessages.begin());
84             if (cur != mMessages.end()) {
85                 result = *cur;
86             }
87 
88             if (result != 0) {
89                 if (result->when <= now) {
90                     // there is a message to deliver
91                     mMessages.remove(cur);
92                     break;
93                 }
94                 if (timeout>=0 && timeoutTime < now) {
95                     // we timed-out, return a NULL message
96                     result = 0;
97                     break;
98                 }
99                 nextEventTime = result->when;
100                 result = 0;
101             }
102 
103             if (timeout >= 0 && nextEventTime > 0) {
104                 if (nextEventTime > timeoutTime) {
105                     nextEventTime = timeoutTime;
106                 }
107             }
108 
109             if (nextEventTime >= 0) {
110                 //LOGD("nextEventTime = %lld ms", nextEventTime);
111                 if (nextEventTime > 0) {
112                     // we're about to wait, flush the binder command buffer
113                     IPCThreadState::self()->flushCommands();
114                     const nsecs_t reltime = nextEventTime - systemTime();
115                     if (reltime > 0) {
116                         mCondition.waitRelative(mLock, reltime);
117                     }
118                 }
119             } else {
120                 //LOGD("going to wait");
121                 // we're about to wait, flush the binder command buffer
122                 IPCThreadState::self()->flushCommands();
123                 mCondition.wait(mLock);
124             }
125         }
126         // here we're not holding the lock anymore
127 
128         if (result == 0)
129             break;
130 
131         again = result->handler();
132         if (again) {
133             // the message has been processed. release our reference to it
134             // without holding the lock.
135             result = 0;
136         }
137 
138     } while (again);
139 
140     return result;
141 }
142 
postMessage(const MessageList::value_type & message,nsecs_t relTime,uint32_t flags)143 status_t MessageQueue::postMessage(
144         const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
145 {
146     return queueMessage(message, relTime, flags);
147 }
148 
invalidate()149 status_t MessageQueue::invalidate() {
150     Mutex::Autolock _l(mLock);
151     mInvalidate = true;
152     mCondition.signal();
153     return NO_ERROR;
154 }
155 
queueMessage(const MessageList::value_type & message,nsecs_t relTime,uint32_t flags)156 status_t MessageQueue::queueMessage(
157         const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
158 {
159     Mutex::Autolock _l(mLock);
160     message->when = systemTime() + relTime;
161     mMessages.insert(message);
162 
163     //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
164     //dumpLocked(message);
165 
166     mCondition.signal();
167     return NO_ERROR;
168 }
169 
dump(const MessageList::value_type & message)170 void MessageQueue::dump(const MessageList::value_type& message)
171 {
172     Mutex::Autolock _l(mLock);
173     dumpLocked(message);
174 }
175 
dumpLocked(const MessageList::value_type & message)176 void MessageQueue::dumpLocked(const MessageList::value_type& message)
177 {
178     LIST::const_iterator cur(mMessages.begin());
179     LIST::const_iterator end(mMessages.end());
180     int c = 0;
181     while (cur != end) {
182         const char tick = (*cur == message) ? '>' : ' ';
183         LOGD("%c %d: msg{.what=%08x, when=%lld}",
184                 tick, c, (*cur)->what, (*cur)->when);
185         ++cur;
186         c++;
187     }
188 }
189 
190 // ---------------------------------------------------------------------------
191 
192 }; // namespace android
193