blob: fb80fb88245ffb1fe6d1ed46f64757ab9ccf6646 [file] [log] [blame]
//===- BuildExecutionQueue.h ------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef LLBUILD_BUILDSYSTEM_BUILDEXECUTIONQUEUE_H
#define LLBUILD_BUILDSYSTEM_BUILDEXECUTIONQUEUE_H
#include "llbuild/Basic/Compiler.h"
#include "llbuild/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
#include <functional>
namespace llbuild {
namespace buildsystem {
class BuildExecutionQueueDelegate;
class Command;
enum class CommandResult;
/// Opaque type which allows the queue implementation to maintain additional
/// state and associate subsequent requests (e.g., \see executeProcess()) with
/// the dispatching job.
struct QueueJobContext;
/// Wrapper for individual pieces of work that are added to the execution queue.
///
/// All work on the exeuction queue is always done on behalf of some command in
/// the build system it is executing.
class QueueJob {
/// The command this job is running on behalf of.
Command* forCommand = nullptr;
/// The function to execute to do the work.
typedef std::function<void(QueueJobContext*)> work_fn_ty;
work_fn_ty work;
public:
/// Default constructor, for use as a sentinel.
QueueJob() {}
/// General constructor.
QueueJob(Command* forCommand, work_fn_ty work)
: forCommand(forCommand), work(work) {}
Command* getForCommand() const { return forCommand; }
void execute(QueueJobContext* context) { work(context); }
};
/// This abstact class encapsulates the interface needed by the build system for
/// contributing work which needs to be executed to perform a particular build.
class BuildExecutionQueue {
// DO NOT COPY
BuildExecutionQueue(const BuildExecutionQueue&)
LLBUILD_DELETED_FUNCTION;
void operator=(const BuildExecutionQueue&)
LLBUILD_DELETED_FUNCTION;
BuildExecutionQueue &operator=(BuildExecutionQueue&& rhs)
LLBUILD_DELETED_FUNCTION;
BuildExecutionQueueDelegate& delegate;
public:
BuildExecutionQueue(BuildExecutionQueueDelegate& delegate);
virtual ~BuildExecutionQueue();
/// @name Accessors
/// @{
BuildExecutionQueueDelegate& getDelegate() { return delegate; }
const BuildExecutionQueueDelegate& getDelegate() const { return delegate; }
/// @}
/// Add a job to be executed.
virtual void addJob(QueueJob job) = 0;
/// Cancel all jobs and subprocesses of this queue.
virtual void cancelAllJobs() = 0;
/// @name Execution Interfaces
///
/// These are additional interfaces provided by the execution queue which can
/// be invoked by the individual \see QueueJob::execute() to perform
/// particular actions. The benefit of delegating to the execution queue to
/// perform these actions is that the queue can potentially do a better job of
/// scheduling activities.
///
/// @{
/// Execute the given command line.
///
/// This will launch and execute the given command line and wait for it to
/// complete.
///
/// \param context The context object passed to the job's worker function.
///
/// \param commandLine The command line to execute.
///
/// \param environment The environment to launch with.
///
/// \param inheritEnvironment If true, the supplied environment will be
/// overlayed on top base environment supplied when creating the queue. If
/// false, only the supplied environment will be passed to the subprocess.
///
/// \returns Result of the process execution.
//
// FIXME: This interface will need to get more complicated, and provide the
// command result and facilities for dealing with the output.
virtual CommandResult
executeProcess(QueueJobContext* context,
ArrayRef<StringRef> commandLine,
ArrayRef<std::pair<StringRef, StringRef>> environment,
bool inheritEnvironment = true) = 0;
/// @}
/// Execute the given command, using an inherited environment.
CommandResult executeProcess(QueueJobContext* context,
ArrayRef<StringRef> commandLine);
/// Execute the given command using "/bin/sh".
///
/// This will launch and execute the given command line and wait for it to
/// complete.
///
/// \param context The context object passed to the job's worker function.
/// \param command The command to execute.
/// \returns True on success.
//
// FIXME: This interface will need to get more complicated, and provide the
// command result and facilities for dealing with the output.
bool executeShellCommand(QueueJobContext* context, StringRef command);
};
/// Delegate interface for execution queue status.
///
/// All delegate interfaces are invoked synchronously by the execution queue,
/// and should defer any long running operations to avoid blocking the queue
/// unnecessarily.
///
/// NOTE: The delegate *MUST* be thread-safe with respect to all calls, which
/// will arrive concurrently and without any specified thread.
class BuildExecutionQueueDelegate {
// DO NOT COPY
BuildExecutionQueueDelegate(const BuildExecutionQueueDelegate&)
LLBUILD_DELETED_FUNCTION;
void operator=(const BuildExecutionQueueDelegate&)
LLBUILD_DELETED_FUNCTION;
BuildExecutionQueueDelegate &operator=(BuildExecutionQueueDelegate&& rhs)
LLBUILD_DELETED_FUNCTION;
public:
/// Handle used to communicate information about a launched process.
struct ProcessHandle {
/// Opaque ID.
uintptr_t id;
};
public:
BuildExecutionQueueDelegate() {}
virtual ~BuildExecutionQueueDelegate();
/// Called when a command's job has been started.
///
/// The queue guarantees that any commandStarted() call will be paired with
/// exactly one \see commandFinished() call.
//
// FIXME: We may eventually want to allow the individual job to provide some
// additional context here, for complex commands.
//
// FIXME: Design a way to communicate the "lane" here, for use in "super
// console" like UIs.
virtual void commandJobStarted(Command*) = 0;
/// Called when a command's job has been finished.
///
/// NOTE: This callback is invoked by the quee without any understanding of
/// how the command is tied to the engine. In particular, it is almost always
/// the case that the command will have already completed from the perspective
/// of the low-level engine (and its dependents may have started
/// executing). Clients which want to understand when a command is complete
/// before the engine has been notified as such should use \see
/// BuildSystem::commandFinished().
virtual void commandJobFinished(Command*) = 0;
/// Called when a command's job has started executing an external process.
///
/// The queue guarantees that any commandProcessStarted() call will be paired
/// with exactly one \see commandProcessFinished() call.
///
/// \param handle - A unique handle used in subsequent delegate calls to
/// identify the process. This handle should only be used to associate
/// different status calls relating to the same process. It is only guaranteed
/// to be unique from when it has been provided here to when it has been
/// provided to the \see commandProcessFinished() call.
virtual void commandProcessStarted(Command*, ProcessHandle handle) = 0;
/// Called to report an error in the management of a command process.
///
/// \param handle - The process handle.
/// \param message - The error message.
//
// FIXME: Need to move to more structured error handling.
virtual void commandProcessHadError(Command*, ProcessHandle handle,
const Twine& message) = 0;
/// Called to report a command processes' (merged) standard output and error.
///
/// \param handle - The process handle.
/// \param data - The process output.
virtual void commandProcessHadOutput(Command*, ProcessHandle handle,
StringRef data) = 0;
/// Called when a command's job has finished executing an external process.
///
/// \param handle - The handle used to identify the process. This handle will
/// become invalid as soon as the client returns from this API call.
///
/// \param result - Whether the process suceeded, failed or was cancelled.
/// \param exitStatus - The raw exit status of the process, or -1 if an error
/// was encountered.
//
// FIXME: Need to include additional information on the status here, e.g., the
// signal status, and the process output (if buffering).
virtual void commandProcessFinished(Command*, ProcessHandle handle,
CommandResult result,
int exitStatus) = 0;
};
/// Create an execution queue that schedules jobs to individual lanes with a
/// capped limit on the number of concurrent lanes.
BuildExecutionQueue *createLaneBasedExecutionQueue(
BuildExecutionQueueDelegate& delegate, int numLanes,
const char* const* environment);
}
}
#endif