1113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin/* 2113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * Copyright (C) 2011 The Android Open Source Project 3113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * 4113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * you may not use this file except in compliance with the License. 6113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * You may obtain a copy of the License at 7113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * 8113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * http://www.apache.org/licenses/LICENSE-2.0 9113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * 10113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * Unless required by applicable law or agreed to in writing, software 11113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * See the License for the specific language governing permissions and 14113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin * limitations under the License. 15113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin */ 16113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 17113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linpackage com.android.gallery3d.util; 18113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 19113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.common.Utils; 20113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.util.ThreadPool.Job; 21113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.util.ThreadPool.JobContext; 22113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 23113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport java.util.LinkedList; 24113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 25113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin// Limit the number of concurrent jobs that has been submitted into a ThreadPool 26113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin@SuppressWarnings("rawtypes") 27113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linpublic class JobLimiter implements FutureListener { 28113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static final String TAG = "JobLimiter"; 29113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 30113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin // State Transition: 31113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin // INIT -> DONE, CANCELLED 32113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin // DONE -> CANCELLED 33113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static final int STATE_INIT = 0; 34113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static final int STATE_DONE = 1; 35113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static final int STATE_CANCELLED = 2; 36113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 37113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private final LinkedList<JobWrapper<?>> mJobs = new LinkedList<JobWrapper<?>>(); 38113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private final ThreadPool mPool; 39113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private int mLimit; 40113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 41113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static class JobWrapper<T> implements Future<T>, Job<T> { 42113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private int mState = STATE_INIT; 43113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private Job<T> mJob; 44113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private Future<T> mDelegate; 45113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private FutureListener<T> mListener; 46113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private T mResult; 47113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 48113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public JobWrapper(Job<T> job, FutureListener<T> listener) { 49113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mJob = job; 50113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mListener = listener; 51113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 52113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 53113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public synchronized void setFuture(Future<T> future) { 54113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (mState != STATE_INIT) return; 55113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mDelegate = future; 56113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 57113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 58113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 59113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public void cancel() { 60113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin FutureListener<T> listener = null; 61113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin synchronized (this) { 62113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (mState != STATE_DONE) { 63113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin listener = mListener; 64113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mJob = null; 65113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mListener = null; 66113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (mDelegate != null) { 67113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mDelegate.cancel(); 68113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mDelegate = null; 69113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 70113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 71113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mState = STATE_CANCELLED; 72113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mResult = null; 73113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin notifyAll(); 74113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 75113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (listener != null) listener.onFutureDone(this); 76113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 77113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 78113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 79113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public synchronized boolean isCancelled() { 80113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin return mState == STATE_CANCELLED; 81113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 82113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 83113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 84113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public boolean isDone() { 85113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin // Both CANCELLED AND DONE is considered as done 86113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin return mState != STATE_INIT; 87113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 88113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 89113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 90113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public synchronized T get() { 91113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin while (mState == STATE_INIT) { 92113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin // handle the interrupted exception of wait() 93113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin Utils.waitWithoutInterrupt(this); 94113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 95113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin return mResult; 96113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 97113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 98113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 99113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public void waitDone() { 100113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin get(); 101113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 102113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 103113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 104113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public T run(JobContext jc) { 105113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin Job<T> job = null; 106113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin synchronized (this) { 107113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (mState == STATE_CANCELLED) return null; 108113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin job = mJob; 109113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 110113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin T result = null; 111113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin try { 112113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin result = job.run(jc); 113113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } catch (Throwable t) { 114113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin Log.w(TAG, "error executing job: " + job, t); 115113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 116113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin FutureListener<T> listener = null; 117113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin synchronized (this) { 118113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (mState == STATE_CANCELLED) return null; 119113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mState = STATE_DONE; 120113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin listener = mListener; 121113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mListener = null; 122113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mJob = null; 123113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mResult = result; 124113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin notifyAll(); 125113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 126113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (listener != null) listener.onFutureDone(this); 127113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin return result; 128113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 129113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 130113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 131113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public JobLimiter(ThreadPool pool, int limit) { 132113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mPool = Utils.checkNotNull(pool); 133113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mLimit = limit; 134113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 135113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 136113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public synchronized <T> Future<T> submit(Job<T> job, FutureListener<T> listener) { 137113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin JobWrapper<T> future = new JobWrapper<T>(Utils.checkNotNull(job), listener); 138113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mJobs.addLast(future); 139113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin submitTasksIfAllowed(); 140113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin return future; 141113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 142113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 143113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @SuppressWarnings({"rawtypes", "unchecked"}) 144113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private void submitTasksIfAllowed() { 145113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin while (mLimit > 0 && !mJobs.isEmpty()) { 146113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin JobWrapper wrapper = mJobs.removeFirst(); 147113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin if (!wrapper.isCancelled()) { 148113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin --mLimit; 149113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin wrapper.setFuture(mPool.submit(wrapper, this)); 150113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 151113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 152113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 153113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin 154113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin @Override 155113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin public synchronized void onFutureDone(Future future) { 156113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin ++mLimit; 157113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin submitTasksIfAllowed(); 158113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin } 159113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin} 160