WorkQueue.cpp revision 0818b0921ef6cda07f41b56d2ef19b2849dfefd1
10818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown/*
20818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * Copyright (C) 2012 The Android Open Source Project
30818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown *
40818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
50818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * you may not use this file except in compliance with the License.
60818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * You may obtain a copy of the License at
70818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown *
80818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
90818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown *
100818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * Unless required by applicable law or agreed to in writing, software
110818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
120818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * See the License for the specific language governing permissions and
140818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * limitations under the License.
150818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown */
160818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
170818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown// #define LOG_NDEBUG 0
180818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#define LOG_TAG "WorkQueue"
190818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
200818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#include <utils/Log.h>
210818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#include <utils/WorkQueue.h>
220818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
230818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownnamespace android {
240818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
250818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown// --- WorkQueue ---
260818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
270818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff BrownWorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) :
280818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mMaxThreads(maxThreads), mCanCallJava(canCallJava),
290818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mCanceled(false), mFinished(false), mIdleThreads(0) {
300818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
310818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
320818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff BrownWorkQueue::~WorkQueue() {
330818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    if (!cancel()) {
340818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        finish();
350818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
360818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
370818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
380818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownstatus_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) {
390818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    AutoMutex _l(mLock);
400818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
410818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    if (mFinished || mCanceled) {
420818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        return INVALID_OPERATION;
430818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
440818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
450818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    if (mWorkThreads.size() < mMaxThreads
460818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            && mIdleThreads < mWorkUnits.size() + 1) {
470818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        sp<WorkThread> workThread = new WorkThread(this, mCanCallJava);
480818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        status_t status = workThread->run("WorkQueue::WorkThread");
490818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        if (status) {
500818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            return status;
510818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
520818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkThreads.add(workThread);
530818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mIdleThreads += 1;
540818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    } else if (backlog) {
550818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        while (mWorkUnits.size() >= mMaxThreads * backlog) {
560818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            mWorkDequeuedCondition.wait(mLock);
570818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            if (mFinished || mCanceled) {
580818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                return INVALID_OPERATION;
590818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            }
600818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
610818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
620818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
630818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    mWorkUnits.add(workUnit);
640818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    mWorkChangedCondition.broadcast();
650818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return OK;
660818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
670818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
680818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownstatus_t WorkQueue::cancel() {
690818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    AutoMutex _l(mLock);
700818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
710818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return cancelLocked();
720818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
730818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
740818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownstatus_t WorkQueue::cancelLocked() {
750818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    if (mFinished) {
760818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        return INVALID_OPERATION;
770818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
780818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
790818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    if (!mCanceled) {
800818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mCanceled = true;
810818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
820818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        size_t count = mWorkUnits.size();
830818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        for (size_t i = 0; i < count; i++) {
840818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            delete mWorkUnits.itemAt(i);
850818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
860818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkUnits.clear();
870818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkChangedCondition.broadcast();
880818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkDequeuedCondition.broadcast();
890818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
900818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return OK;
910818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
920818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
930818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownstatus_t WorkQueue::finish() {
940818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    { // acquire lock
950818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        AutoMutex _l(mLock);
960818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
970818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        if (mFinished) {
980818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            return INVALID_OPERATION;
990818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
1000818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1010818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mFinished = true;
1020818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkChangedCondition.broadcast();
1030818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    } // release lock
1040818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1050818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    // It is not possible for the list of work threads to change once the mFinished
1060818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    // flag has been set, so we can access mWorkThreads outside of the lock here.
1070818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    size_t count = mWorkThreads.size();
1080818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    for (size_t i = 0; i < count; i++) {
1090818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mWorkThreads.itemAt(i)->join();
1100818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    }
1110818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    mWorkThreads.clear();
1120818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return OK;
1130818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
1140818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1150818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownbool WorkQueue::threadLoop() {
1160818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    WorkUnit* workUnit;
1170818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    { // acquire lock
1180818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        AutoMutex _l(mLock);
1190818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1200818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        for (;;) {
1210818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            if (mCanceled) {
1220818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                return false;
1230818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            }
1240818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1250818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            if (!mWorkUnits.isEmpty()) {
1260818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                workUnit = mWorkUnits.itemAt(0);
1270818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                mWorkUnits.removeAt(0);
1280818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                mIdleThreads -= 1;
1290818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                mWorkDequeuedCondition.broadcast();
1300818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                break;
1310818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            }
1320818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1330818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            if (mFinished) {
1340818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown                return false;
1350818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            }
1360818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1370818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            mWorkChangedCondition.wait(mLock);
1380818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
1390818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    } // release lock
1400818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1410818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    bool shouldContinue = workUnit->run();
1420818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    delete workUnit;
1430818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1440818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    { // acquire lock
1450818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        AutoMutex _l(mLock);
1460818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1470818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        mIdleThreads += 1;
1480818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1490818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        if (!shouldContinue) {
1500818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            cancelLocked();
1510818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown            return false;
1520818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        }
1530818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    } // release lock
1540818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1550818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return true;
1560818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
1570818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1580818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown// --- WorkQueue::WorkThread ---
1590818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1600818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff BrownWorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) :
1610818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        Thread(canCallJava), mWorkQueue(workQueue) {
1620818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
1630818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1640818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff BrownWorkQueue::WorkThread::~WorkThread() {
1650818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
1660818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1670818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownbool WorkQueue::WorkThread::threadLoop() {
1680818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    return mWorkQueue->threadLoop();
1690818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}
1700818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1710818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown};  // namespace android
172