Home | History | Annotate | Download | only in surfaceflinger
      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 
     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 
     46 void MessageList::remove(MessageList::LIST::iterator pos)
     47 {
     48     mList.erase(pos);
     49 }
     50 
     51 // ---------------------------------------------------------------------------
     52 
     53 MessageQueue::MessageQueue()
     54     : mInvalidate(false)
     55 {
     56     mInvalidateMessage = new MessageBase(INVALIDATE);
     57 }
     58 
     59 MessageQueue::~MessageQueue()
     60 {
     61 }
     62 
     63 sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
     64 {
     65     sp<MessageBase> 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             LIST::iterator cur(mMessages.begin());
     76             if (cur != mMessages.end()) {
     77                 result = *cur;
     78             }
     79 
     80             if (result != 0) {
     81                 if (result->when <= now) {
     82                     // there is a message to deliver
     83                     mMessages.remove(cur);
     84                     break;
     85                 }
     86                 nextEventTime = result->when;
     87                 result = 0;
     88             }
     89 
     90             // see if we have an invalidate message
     91             if (mInvalidate) {
     92                 mInvalidate = false;
     93                 mInvalidateMessage->when = now;
     94                 result = mInvalidateMessage;
     95                 break;
     96             }
     97 
     98             if (timeout >= 0) {
     99                 if (timeoutTime < now) {
    100                     // we timed-out, return a NULL message
    101                     result = 0;
    102                     break;
    103                 }
    104                 if (nextEventTime > 0) {
    105                     if (nextEventTime > timeoutTime) {
    106                         nextEventTime = timeoutTime;
    107                     }
    108                 } else {
    109                     nextEventTime = timeoutTime;
    110                 }
    111             }
    112 
    113             if (nextEventTime >= 0) {
    114                 //LOGD("nextEventTime = %lld ms", nextEventTime);
    115                 if (nextEventTime > 0) {
    116                     // we're about to wait, flush the binder command buffer
    117                     IPCThreadState::self()->flushCommands();
    118                     const nsecs_t reltime = nextEventTime - systemTime();
    119                     if (reltime > 0) {
    120                         mCondition.waitRelative(mLock, reltime);
    121                     }
    122                 }
    123             } else {
    124                 //LOGD("going to wait");
    125                 // we're about to wait, flush the binder command buffer
    126                 IPCThreadState::self()->flushCommands();
    127                 mCondition.wait(mLock);
    128             }
    129         }
    130         // here we're not holding the lock anymore
    131 
    132         if (result == 0)
    133             break;
    134 
    135         again = result->handler();
    136         if (again) {
    137             // the message has been processed. release our reference to it
    138             // without holding the lock.
    139             result->notify();
    140             result = 0;
    141         }
    142 
    143     } while (again);
    144 
    145     return result;
    146 }
    147 
    148 status_t MessageQueue::postMessage(
    149         const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
    150 {
    151     return queueMessage(message, relTime, flags);
    152 }
    153 
    154 status_t MessageQueue::invalidate() {
    155     Mutex::Autolock _l(mLock);
    156     mInvalidate = true;
    157     mCondition.signal();
    158     return NO_ERROR;
    159 }
    160 
    161 status_t MessageQueue::queueMessage(
    162         const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
    163 {
    164     Mutex::Autolock _l(mLock);
    165     message->when = systemTime() + relTime;
    166     mMessages.insert(message);
    167 
    168     //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
    169     //dumpLocked(message);
    170 
    171     mCondition.signal();
    172     return NO_ERROR;
    173 }
    174 
    175 void MessageQueue::dump(const sp<MessageBase>& message)
    176 {
    177     Mutex::Autolock _l(mLock);
    178     dumpLocked(message);
    179 }
    180 
    181 void MessageQueue::dumpLocked(const sp<MessageBase>& message)
    182 {
    183     LIST::const_iterator cur(mMessages.begin());
    184     LIST::const_iterator end(mMessages.end());
    185     int c = 0;
    186     while (cur != end) {
    187         const char tick = (*cur == message) ? '>' : ' ';
    188         LOGD("%c %d: msg{.what=%08x, when=%lld}",
    189                 tick, c, (*cur)->what, (*cur)->when);
    190         ++cur;
    191         c++;
    192     }
    193 }
    194 
    195 // ---------------------------------------------------------------------------
    196 
    197 }; // namespace android
    198