OSDN Git Service

[DO NOT MERGE] Check bounds in offsetToPtr
[android-x86/frameworks-base.git] / tools / aapt / WorkQueue.cpp
1 /*
2  * Copyright (C) 2012 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 // #define LOG_NDEBUG 0
18 #define LOG_TAG "WorkQueue"
19
20 #include <utils/Log.h>
21 #include "WorkQueue.h"
22
23 namespace android {
24
25 // --- WorkQueue ---
26
27 WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) :
28         mMaxThreads(maxThreads), mCanCallJava(canCallJava),
29         mCanceled(false), mFinished(false), mIdleThreads(0) {
30 }
31
32 WorkQueue::~WorkQueue() {
33     if (!cancel()) {
34         finish();
35     }
36 }
37
38 status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) {
39     AutoMutex _l(mLock);
40
41     if (mFinished || mCanceled) {
42         return INVALID_OPERATION;
43     }
44
45     if (mWorkThreads.size() < mMaxThreads
46             && mIdleThreads < mWorkUnits.size() + 1) {
47         sp<WorkThread> workThread = new WorkThread(this, mCanCallJava);
48         status_t status = workThread->run("WorkQueue::WorkThread");
49         if (status) {
50             return status;
51         }
52         mWorkThreads.add(workThread);
53         mIdleThreads += 1;
54     } else if (backlog) {
55         while (mWorkUnits.size() >= mMaxThreads * backlog) {
56             mWorkDequeuedCondition.wait(mLock);
57             if (mFinished || mCanceled) {
58                 return INVALID_OPERATION;
59             }
60         }
61     }
62
63     mWorkUnits.add(workUnit);
64     mWorkChangedCondition.broadcast();
65     return OK;
66 }
67
68 status_t WorkQueue::cancel() {
69     AutoMutex _l(mLock);
70
71     return cancelLocked();
72 }
73
74 status_t WorkQueue::cancelLocked() {
75     if (mFinished) {
76         return INVALID_OPERATION;
77     }
78
79     if (!mCanceled) {
80         mCanceled = true;
81
82         size_t count = mWorkUnits.size();
83         for (size_t i = 0; i < count; i++) {
84             delete mWorkUnits.itemAt(i);
85         }
86         mWorkUnits.clear();
87         mWorkChangedCondition.broadcast();
88         mWorkDequeuedCondition.broadcast();
89     }
90     return OK;
91 }
92
93 status_t WorkQueue::finish() {
94     { // acquire lock
95         AutoMutex _l(mLock);
96
97         if (mFinished) {
98             return INVALID_OPERATION;
99         }
100
101         mFinished = true;
102         mWorkChangedCondition.broadcast();
103     } // release lock
104
105     // It is not possible for the list of work threads to change once the mFinished
106     // flag has been set, so we can access mWorkThreads outside of the lock here.
107     size_t count = mWorkThreads.size();
108     for (size_t i = 0; i < count; i++) {
109         mWorkThreads.itemAt(i)->join();
110     }
111     mWorkThreads.clear();
112     return OK;
113 }
114
115 bool WorkQueue::threadLoop() {
116     WorkUnit* workUnit;
117     { // acquire lock
118         AutoMutex _l(mLock);
119
120         for (;;) {
121             if (mCanceled) {
122                 return false;
123             }
124
125             if (!mWorkUnits.isEmpty()) {
126                 workUnit = mWorkUnits.itemAt(0);
127                 mWorkUnits.removeAt(0);
128                 mIdleThreads -= 1;
129                 mWorkDequeuedCondition.broadcast();
130                 break;
131             }
132
133             if (mFinished) {
134                 return false;
135             }
136
137             mWorkChangedCondition.wait(mLock);
138         }
139     } // release lock
140
141     bool shouldContinue = workUnit->run();
142     delete workUnit;
143
144     { // acquire lock
145         AutoMutex _l(mLock);
146
147         mIdleThreads += 1;
148
149         if (!shouldContinue) {
150             cancelLocked();
151             return false;
152         }
153     } // release lock
154
155     return true;
156 }
157
158 // --- WorkQueue::WorkThread ---
159
160 WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) :
161         Thread(canCallJava), mWorkQueue(workQueue) {
162 }
163
164 WorkQueue::WorkThread::~WorkThread() {
165 }
166
167 bool WorkQueue::WorkThread::threadLoop() {
168     return mWorkQueue->threadLoop();
169 }
170
171 };  // namespace android