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#ifndef _LIBS_UTILS_WORK_QUEUE_H
180818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#define _LIBS_UTILS_WORK_QUEUE_H
190818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
200818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#include <utils/Errors.h>
210818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#include <utils/Vector.h>
220818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#include <utils/threads.h>
230818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
240818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownnamespace android {
250818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
260818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown/*
270818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * A threaded work queue.
280818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown *
290818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * This class is designed to make it easy to run a bunch of isolated work
300818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * units in parallel, using up to the specified number of threads.
310818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * To use it, write a loop to post work units to the work queue, then synchronize
320818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown * on the queue at the end.
330818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown */
340818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownclass WorkQueue {
350818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownpublic:
360818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    class WorkUnit {
370818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    public:
380818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        WorkUnit() { }
390818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        virtual ~WorkUnit() { }
400818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
410818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        /*
420818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown         * Runs the work unit.
430818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown         * If the result is 'true' then the work queue continues scheduling work as usual.
440818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown         * If the result is 'false' then the work queue is canceled.
450818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown         */
460818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        virtual bool run() = 0;
470818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    };
480818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
490818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    /* Creates a work queue with the specified maximum number of work threads. */
500818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    WorkQueue(size_t maxThreads, bool canCallJava = true);
510818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
520818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    /* Destroys the work queue.
530818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * Cancels pending work and waits for all remaining threads to complete.
540818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     */
550818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    ~WorkQueue();
560818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
570818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    /* Posts a work unit to run later.
580818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * If the work queue has been canceled or is already finished, returns INVALID_OPERATION
590818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * and does not take ownership of the work unit (caller must destroy it itself).
600818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * Otherwise, returns OK and takes ownership of the work unit (the work queue will
610818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * destroy it automatically).
620818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     *
630818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * For flow control, this method blocks when the size of the pending work queue is more
640818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * 'backlog' times the number of threads.  This condition reduces the rate of entry into
650818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * the pending work queue and prevents it from growing much more rapidly than the
660818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * work threads can actually handle.
670818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     *
680818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * If 'backlog' is 0, then no throttle is applied.
690818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     */
700818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    status_t schedule(WorkUnit* workUnit, size_t backlog = 2);
710818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
720818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    /* Cancels all pending work.
730818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * If the work queue is already finished, returns INVALID_OPERATION.
740818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * If the work queue is already canceled, returns OK and does nothing else.
750818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * Otherwise, returns OK, discards all pending work units and prevents additional
760818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * work units from being scheduled.
770818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     *
780818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * Call finish() after cancel() to wait for all remaining work to complete.
790818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     */
800818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    status_t cancel();
810818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
820818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    /* Waits for all work to complete.
830818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * If the work queue is already finished, returns INVALID_OPERATION.
840818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     * Otherwise, waits for all work to complete and returns OK.
850818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown     */
860818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    status_t finish();
870818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
880818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brownprivate:
890818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    class WorkThread : public Thread {
900818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    public:
910818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        WorkThread(WorkQueue* workQueue, bool canCallJava);
920818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        virtual ~WorkThread();
930818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
940818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    private:
950818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        virtual bool threadLoop();
960818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
970818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown        WorkQueue* const mWorkQueue;
980818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    };
990818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1000818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    status_t cancelLocked();
1010818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    bool threadLoop(); // called from each work thread
1020818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1030818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    const size_t mMaxThreads;
1040818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    const bool mCanCallJava;
1050818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1060818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    Mutex mLock;
1070818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    Condition mWorkChangedCondition;
1080818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    Condition mWorkDequeuedCondition;
1090818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1100818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    bool mCanceled;
1110818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    bool mFinished;
1120818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    size_t mIdleThreads;
1130818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    Vector<sp<WorkThread> > mWorkThreads;
1140818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown    Vector<WorkUnit*> mWorkUnits;
1150818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown};
1160818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1170818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown}; // namespace android
1180818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown
1190818b0921ef6cda07f41b56d2ef19b2849dfefd1Jeff Brown#endif // _LIBS_UTILS_WORK_QUEUE_H
120