1 //===- BuildExecutionQueue.h ------------------------------------*- C++ -*-===// 2 // 3 // This source file is part of the Swift.org open source project 4 // 5 // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors 6 // Licensed under Apache License v2.0 with Runtime Library Exception 7 // 8 // See http://swift.org/LICENSE.txt for license information 9 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLBUILD_BUILDSYSTEM_BUILDEXECUTIONQUEUE_H 14 #define LLBUILD_BUILDSYSTEM_BUILDEXECUTIONQUEUE_H 15 16 #include "llbuild/Basic/Compiler.h" 17 #include "llbuild/Basic/LLVM.h" 18 19 #include "llvm/ADT/StringRef.h" 20 21 #include <cstdint> 22 #include <functional> 23 24 namespace llbuild { 25 namespace buildsystem { 26 27 class BuildExecutionQueueDelegate; 28 class Command; 29 enum class CommandResult; 30 31 /// Opaque type which allows the queue implementation to maintain additional 32 /// state and associate subsequent requests (e.g., \see executeProcess()) with 33 /// the dispatching job. 34 struct QueueJobContext; 35 36 /// Wrapper for individual pieces of work that are added to the execution queue. 37 /// 38 /// All work on the exeuction queue is always done on behalf of some command in 39 /// the build system it is executing. 40 class QueueJob { 41 /// The command this job is running on behalf of. 42 Command* forCommand = nullptr; 43 44 /// The function to execute to do the work. 45 typedef std::function<void(QueueJobContext*)> work_fn_ty; 46 work_fn_ty work; 47 48 public: 49 /// Default constructor, for use as a sentinel. QueueJob()50 QueueJob() {} 51 52 /// General constructor. QueueJob(Command * forCommand,work_fn_ty work)53 QueueJob(Command* forCommand, work_fn_ty work) 54 : forCommand(forCommand), work(work) {} 55 getForCommand()56 Command* getForCommand() const { return forCommand; } 57 execute(QueueJobContext * context)58 void execute(QueueJobContext* context) { work(context); } 59 }; 60 61 /// This abstact class encapsulates the interface needed by the build system for 62 /// contributing work which needs to be executed to perform a particular build. 63 class BuildExecutionQueue { 64 // DO NOT COPY 65 BuildExecutionQueue(const BuildExecutionQueue&) 66 LLBUILD_DELETED_FUNCTION; 67 void operator=(const BuildExecutionQueue&) 68 LLBUILD_DELETED_FUNCTION; 69 BuildExecutionQueue &operator=(BuildExecutionQueue&& rhs) 70 LLBUILD_DELETED_FUNCTION; 71 72 BuildExecutionQueueDelegate& delegate; 73 74 public: 75 BuildExecutionQueue(BuildExecutionQueueDelegate& delegate); 76 virtual ~BuildExecutionQueue(); 77 78 /// @name Accessors 79 /// @{ 80 getDelegate()81 BuildExecutionQueueDelegate& getDelegate() { return delegate; } getDelegate()82 const BuildExecutionQueueDelegate& getDelegate() const { return delegate; } 83 84 /// @} 85 86 /// Add a job to be executed. 87 virtual void addJob(QueueJob job) = 0; 88 89 /// Cancel all jobs and subprocesses of this queue. 90 virtual void cancelAllJobs() = 0; 91 92 /// @name Execution Interfaces 93 /// 94 /// These are additional interfaces provided by the execution queue which can 95 /// be invoked by the individual \see QueueJob::execute() to perform 96 /// particular actions. The benefit of delegating to the execution queue to 97 /// perform these actions is that the queue can potentially do a better job of 98 /// scheduling activities. 99 /// 100 /// @{ 101 102 /// Execute the given command line. 103 /// 104 /// This will launch and execute the given command line and wait for it to 105 /// complete. 106 /// 107 /// \param context The context object passed to the job's worker function. 108 /// 109 /// \param commandLine The command line to execute. 110 /// 111 /// \param environment The environment to launch with. 112 /// 113 /// \param inheritEnvironment If true, the supplied environment will be 114 /// overlayed on top base environment supplied when creating the queue. If 115 /// false, only the supplied environment will be passed to the subprocess. 116 /// 117 /// \returns Result of the process execution. 118 // 119 // FIXME: This interface will need to get more complicated, and provide the 120 // command result and facilities for dealing with the output. 121 virtual CommandResult 122 executeProcess(QueueJobContext* context, 123 ArrayRef<StringRef> commandLine, 124 ArrayRef<std::pair<StringRef, StringRef>> environment, 125 bool inheritEnvironment = true) = 0; 126 127 /// @} 128 129 /// Execute the given command, using an inherited environment. 130 CommandResult executeProcess(QueueJobContext* context, 131 ArrayRef<StringRef> commandLine); 132 133 /// Execute the given command using "/bin/sh". 134 /// 135 /// This will launch and execute the given command line and wait for it to 136 /// complete. 137 /// 138 /// \param context The context object passed to the job's worker function. 139 /// \param command The command to execute. 140 /// \returns True on success. 141 // 142 // FIXME: This interface will need to get more complicated, and provide the 143 // command result and facilities for dealing with the output. 144 bool executeShellCommand(QueueJobContext* context, StringRef command); 145 146 }; 147 148 /// Delegate interface for execution queue status. 149 /// 150 /// All delegate interfaces are invoked synchronously by the execution queue, 151 /// and should defer any long running operations to avoid blocking the queue 152 /// unnecessarily. 153 /// 154 /// NOTE: The delegate *MUST* be thread-safe with respect to all calls, which 155 /// will arrive concurrently and without any specified thread. 156 class BuildExecutionQueueDelegate { 157 // DO NOT COPY 158 BuildExecutionQueueDelegate(const BuildExecutionQueueDelegate&) 159 LLBUILD_DELETED_FUNCTION; 160 void operator=(const BuildExecutionQueueDelegate&) 161 LLBUILD_DELETED_FUNCTION; 162 BuildExecutionQueueDelegate &operator=(BuildExecutionQueueDelegate&& rhs) 163 LLBUILD_DELETED_FUNCTION; 164 165 public: 166 /// Handle used to communicate information about a launched process. 167 struct ProcessHandle { 168 /// Opaque ID. 169 uintptr_t id; 170 }; 171 172 public: BuildExecutionQueueDelegate()173 BuildExecutionQueueDelegate() {} 174 virtual ~BuildExecutionQueueDelegate(); 175 176 /// Called when a command's job has been started. 177 /// 178 /// The queue guarantees that any commandStarted() call will be paired with 179 /// exactly one \see commandFinished() call. 180 // 181 // FIXME: We may eventually want to allow the individual job to provide some 182 // additional context here, for complex commands. 183 // 184 // FIXME: Design a way to communicate the "lane" here, for use in "super 185 // console" like UIs. 186 virtual void commandJobStarted(Command*) = 0; 187 188 /// Called when a command's job has been finished. 189 /// 190 /// NOTE: This callback is invoked by the quee without any understanding of 191 /// how the command is tied to the engine. In particular, it is almost always 192 /// the case that the command will have already completed from the perspective 193 /// of the low-level engine (and its dependents may have started 194 /// executing). Clients which want to understand when a command is complete 195 /// before the engine has been notified as such should use \see 196 /// BuildSystem::commandFinished(). 197 virtual void commandJobFinished(Command*) = 0; 198 199 /// Called when a command's job has started executing an external process. 200 /// 201 /// The queue guarantees that any commandProcessStarted() call will be paired 202 /// with exactly one \see commandProcessFinished() call. 203 /// 204 /// \param handle - A unique handle used in subsequent delegate calls to 205 /// identify the process. This handle should only be used to associate 206 /// different status calls relating to the same process. It is only guaranteed 207 /// to be unique from when it has been provided here to when it has been 208 /// provided to the \see commandProcessFinished() call. 209 virtual void commandProcessStarted(Command*, ProcessHandle handle) = 0; 210 211 /// Called to report an error in the management of a command process. 212 /// 213 /// \param handle - The process handle. 214 /// \param message - The error message. 215 // 216 // FIXME: Need to move to more structured error handling. 217 virtual void commandProcessHadError(Command*, ProcessHandle handle, 218 const Twine& message) = 0; 219 220 /// Called to report a command processes' (merged) standard output and error. 221 /// 222 /// \param handle - The process handle. 223 /// \param data - The process output. 224 virtual void commandProcessHadOutput(Command*, ProcessHandle handle, 225 StringRef data) = 0; 226 227 /// Called when a command's job has finished executing an external process. 228 /// 229 /// \param handle - The handle used to identify the process. This handle will 230 /// become invalid as soon as the client returns from this API call. 231 /// 232 /// \param result - Whether the process suceeded, failed or was cancelled. 233 /// \param exitStatus - The raw exit status of the process, or -1 if an error 234 /// was encountered. 235 // 236 // FIXME: Need to include additional information on the status here, e.g., the 237 // signal status, and the process output (if buffering). 238 virtual void commandProcessFinished(Command*, ProcessHandle handle, 239 CommandResult result, 240 int exitStatus) = 0; 241 }; 242 243 /// Create an execution queue that schedules jobs to individual lanes with a 244 /// capped limit on the number of concurrent lanes. 245 BuildExecutionQueue *createLaneBasedExecutionQueue( 246 BuildExecutionQueueDelegate& delegate, int numLanes, 247 const char* const* environment); 248 249 } 250 } 251 252 #endif 253