blob: 4283674d923eb653967aebc0cfa2099d702d93cd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DECAF_UTIL_CONCURRENT_EXECUTORSERVICE_H_
#define _DECAF_UTIL_CONCURRENT_EXECUTORSERVICE_H_
#include <decaf/util/Config.h>
#include <decaf/lang/Runnable.h>
#include <decaf/util/ArrayList.h>
#include <decaf/util/concurrent/Future.h>
#include <decaf/util/concurrent/FutureTask.h>
#include <decaf/util/concurrent/Executor.h>
#include <decaf/util/concurrent/TimeUnit.h>
#include <decaf/lang/exceptions/InterruptedException.h>
namespace decaf {
namespace util {
namespace concurrent {
/**
* An Executor that provides methods to manage termination and methods that can produce a Future for
* tracking progress of one or more asynchronous tasks.
*
* An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods
* are provided for shutting down an ExecutorService. The shutdown() method will allow previously
* submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks
* from starting and attempts to stop currently executing tasks. Upon termination, an executor has no
* tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused
* ExecutorService should be shut down to allow reclamation of its resources.
*
* Method submit extends base method Executor.execute(decaf.lang.Runnable) by creating and returning a
* Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll
* perform the most commonly useful forms of bulk execution, executing a collection of tasks and then
* waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write
* customized variants of these methods.)
*
* The Executors class provides factory methods for the executor services provided in this package.
*
* @since 1.0
*/
class DECAF_API ExecutorService : public Executor {
public:
virtual ~ExecutorService() {}
/**
* The caller will block until the executor has completed termination meaning all tasks
* that where scheduled before shutdown have now completed and the executor is ready for
* deletion. If the timeout period elapses before the executor reaches the terminated
* state then this method return false to indicate it has not terminated.
*
* @param timeout
* The amount of time to wait before abandoning the wait for termination.
* @param unit
* The unit of time that the timeout value represents.
*
* @return true if the executor terminated or false if the timeout expired.
*
* @throws InterruptedException if this call is interrupted while awaiting termination.
*/
virtual bool awaitTermination(long long timeout, const TimeUnit& unit) = 0;
/**
* Performs an orderly shutdown of this Executor. Previously queued tasks are allowed
* to complete but no new tasks are accepted for execution. Calling this method more
* than once has no affect on this executor.
*/
virtual void shutdown() = 0;
/**
* Attempts to stop all currently executing tasks and returns an ArrayList containing the
* Runnables that did not get executed, these object become the property of the caller and
* are not deleted by this class, they are removed from the work queue and forgotten about.
*
* There is no guarantee that this method will halt execution of currently executing tasks.
*
* @return an ArrayList containing all Runnable instance that were still waiting to be
* executed by this class, call now owns those pointers.
*/
virtual ArrayList<decaf::lang::Runnable*> shutdownNow() = 0;
/**
* Returns whether this executor has been shutdown or not.
*
* @return true if this executor has been shutdown.
*/
virtual bool isShutdown() const = 0;
/**
* Returns whether all tasks have completed after this executor was shut down.
*
* @return true if all tasks have completed after a request to shut down was made.
*/
virtual bool isTerminated() const = 0;
/**
* Submits a value-returning task for execution and returns a Future pointer
* representing the pending results of the task. The Future's <tt>get</tt> method
* will return the task's result upon successful completion. The caller owns the
* returned pointer and is responsible for deleting it. The returned value is a
* proxy to the actual FutureTask that is submitted for execution so is legal for
* the caller to delete this value before its execution has completed.
*
* @param task
* Pointer to the Callable<?> task to submit.
* @param takeOwnership
* Boolean value indicating if the Executor now owns the pointer to the task.
*
* @return a Future<?> pointer representing pending completion of the task.
*
* @throws RejectedExecutionException if the task cannot be scheduled for execution
* @throws NullPointerException if the task is null
*/
template<typename E>
Future<E>* submit(Callable<E>* task, bool takeOwnership = true) {
// Creates a new FutureTask to wrap the target task, and then creates a clone
// that will act as the proxy to return to the caller.
Pointer< FutureTask<E> > newTask(new FutureTask<E>(task, takeOwnership));
Pointer< FutureTask<E> > proxy(newTask->clone());
try {
// Its safe to submit and allow the task to be executed only after creating
// the proxy so that if its run on the current thread and destroyed the
// proxy still holds a vlid reference to the inner FutureTask data keeping it
// from being destroyed before the caller has a chance to call get().
this->doSubmit(newTask.get());
// No exception so we can release our ref, the executor owns it now.
newTask.release();
return proxy.release();
} catch(decaf::util::concurrent::RejectedExecutionException& ex) {
// Policy will delete the submitted task
newTask.release();
ex.setMark(__FILE__, __LINE__);
throw;
}
DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException)
DECAF_CATCHALL_THROW(decaf::lang::Exception)
}
/**
* Submits a Runnable task for execution and returns a Future representing that
* task. The Future's <tt>get</tt> method will return the given result upon successful
* completion. The caller owns the returned pointer and is responsible for deleting it.
* The returned value is a proxy to the actual FutureTask that is submitted for execution
* so is legal for the caller to delete this value before its execution has completed.
*
* @param task
* The pointer to the task to submit.
* @param result
* The result to return
* @param takeOwnership
* Boolean value indicating if the Executor now owns the pointer to the task.
*
* @return a Future<?> pointer representing pending completion of the task,
*
* @throws RejectedExecutionException if the task cannot be scheduled for execution
* @throws NullPointerException if the task is null
*/
template<typename E>
Future<E>* submit(decaf::lang::Runnable* task, const E& result, bool takeOwnership = true) {
// Creates a new FutureTask to wrap the target task, and then creates a clone
// that will act as the proxy to return to the caller.
Pointer< FutureTask<E> > newTask(new FutureTask<E>(task, result, takeOwnership));
Pointer< FutureTask<E> > proxy(newTask->clone());
try {
// Its safe to submit and allow the task to be executed only after creating
// the proxy so that if its run on the current thread and destroyed the
// proxy still holds a vlid reference to the inner FutureTask data keeping it
// from being destroyed before the caller has a chance to call get().
this->doSubmit(newTask.get());
// No exception so we can release our reference, the executor owns it now.
newTask.release();
return proxy.release();
} catch(decaf::util::concurrent::RejectedExecutionException& ex) {
// Policy will delete the submitted task
newTask.release();
ex.setMark(__FILE__, __LINE__);
throw;
}
DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException)
DECAF_CATCHALL_THROW(decaf::lang::Exception)
}
/**
* Submits a Runnable object for execution. A Future object is created and returned
* that will return the default value of the template type upon completion. The caller
* owns the returned pointer and is responsible for deleting it. The returned value is
* a proxy to the actual FutureTask that is submitted for execution so is legal for the
* caller to delete this value before its execution has completed.
*
* @param task
* Pointer to a Runnable object that will be executed by this ExecutorService.
* @param takeOwnership
* Boolean value indicating if the Executor now owns the pointer to the task.
*
* @return a new Future<?> pointer that is owned by the caller.
*
* @throws RejectedExecutionException if the task cannot be scheduled for execution
* @throws NullPointerException if the Runnable pointer passed is NULL.
*/
template<typename E>
Future<E>* submit(decaf::lang::Runnable* task, bool takeOwnership = true) {
// Creates a new FutureTask to wrap the target task, and then creates a clone
// that will act as the proxy to return to the caller.
Pointer< FutureTask<E> > newTask(new FutureTask<E>(task, E(), takeOwnership));
Pointer< FutureTask<E> > proxy(newTask->clone());
try {
// Its safe to submit and allow the task to be executed only after creating
// the proxy so that if its run on the current thread and destroyed the
// proxy still holds a vlid reference to the inner FutureTask data keeping it
// from being destroyed before the caller has a chance to call get().
this->doSubmit(newTask.get());
// No exception so we can release our ref, the executor owns it now.
newTask.release();
return proxy.release();
} catch(decaf::util::concurrent::RejectedExecutionException& ex) {
// Policy will delete the submitted task
newTask.release();
ex.setMark(__FILE__, __LINE__);
throw;
}
DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException)
DECAF_CATCHALL_THROW(decaf::lang::Exception)
}
protected:
/**
* Perform the actual submit of a FutureType instance, the caller is responsible for
* creating the properly typed Future<E> object and returning that to its caller. The
* pointer provided is the property of this Executor and must be deleted by this executor
* once its completed.
*
* @param future
* Pointer to a base FutureType instance that is to be submitted to the Executor.
*/
virtual void doSubmit(FutureType* future) = 0;
};
}}}
#endif /* _DECAF_UTIL_CONCURRENT_EXECUTORSERVICE_H_ */