mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* Add the signal number of the terminated task to the output of the driver on platforms for which the signal number is available. The new key in the parseable driver output is "signal". * Add a test to verify that the signal number is emitted. * Add documentation for the new "signal" key emitted in the parseable driver output. https://bugs.swift.org/browse/SR-3175
197 lines
7.9 KiB
C++
197 lines
7.9 KiB
C++
//===--- TaskQueue.h - Task Execution Work Queue ----------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_TASKQUEUE_H
|
|
#define SWIFT_BASIC_TASKQUEUE_H
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/Config/config.h"
|
|
#include "llvm/Support/Program.h"
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <queue>
|
|
|
|
namespace swift {
|
|
namespace sys {
|
|
|
|
class Task; // forward declared to allow for platform-specific implementations
|
|
|
|
typedef llvm::sys::ProcessInfo::ProcessId ProcessId;
|
|
|
|
/// \brief Indicates how a TaskQueue should respond to the task finished event.
|
|
enum class TaskFinishedResponse {
|
|
/// Indicates that execution should continue.
|
|
ContinueExecution,
|
|
/// Indicates that execution should stop (no new tasks will begin execution,
|
|
/// but tasks which are currently executing will be allowed to finish).
|
|
StopExecution,
|
|
};
|
|
|
|
/// \brief A class encapsulating the execution of multiple tasks in parallel.
|
|
class TaskQueue {
|
|
/// Tasks which have not begun execution.
|
|
std::queue<std::unique_ptr<Task>> QueuedTasks;
|
|
|
|
/// The number of tasks to execute in parallel.
|
|
unsigned NumberOfParallelTasks;
|
|
|
|
public:
|
|
/// \brief Create a new TaskQueue instance.
|
|
///
|
|
/// \param NumberOfParallelTasks indicates the number of tasks which should
|
|
/// be run in parallel. If 0, the TaskQueue will choose the most appropriate
|
|
/// number of parallel tasks for the current system.
|
|
TaskQueue(unsigned NumberOfParallelTasks = 0);
|
|
virtual ~TaskQueue();
|
|
|
|
// TODO: remove once -Wdocumentation stops warning for \param, \returns on
|
|
// std::function (<rdar://problem/15665132>).
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
/// \brief A callback which will be executed when each task begins execution
|
|
///
|
|
/// \param Pid the ProcessId of the task which just began execution.
|
|
/// \param Context the context which was passed when the task was added
|
|
typedef std::function<void(ProcessId Pid, void *Context)> TaskBeganCallback;
|
|
|
|
/// \brief A callback which will be executed after each task finishes
|
|
/// execution.
|
|
///
|
|
/// \param Pid the ProcessId of the task which finished execution.
|
|
/// \param ReturnCode the return code of the task which finished execution.
|
|
/// \param Output the output from the task which finished execution,
|
|
/// if available. (This may not be available on all platforms.)
|
|
/// \param Errors the errors from the task which finished execution, if
|
|
/// available and SeparateErrors was true. (This may not be available on all
|
|
/// platforms.)
|
|
/// \param Context the context which was passed when the task was added
|
|
///
|
|
/// \returns true if further execution of tasks should stop,
|
|
/// false if execution should continue
|
|
typedef std::function<TaskFinishedResponse(ProcessId Pid, int ReturnCode,
|
|
StringRef Output, StringRef Errors, void *Context)>
|
|
TaskFinishedCallback;
|
|
|
|
/// \brief A callback which will be executed if a task exited abnormally due
|
|
/// to a signal.
|
|
///
|
|
/// \param Pid the ProcessId of the task which exited abnormally.
|
|
/// \param ErrorMsg a string describing why the task exited abnormally. If
|
|
/// no reason could be deduced, this may be empty.
|
|
/// \param Output the output from the task which exited abnormally, if
|
|
/// available. (This may not be available on all platforms.)
|
|
/// \param Errors the errors from the task which exited abnormally, if
|
|
/// available and SeparateErrors was true. (This may not be available on all
|
|
/// platforms.)
|
|
/// \param Context the context which was passed when the task was added
|
|
/// \param Signal the terminating signal number, if available.
|
|
/// This may not be available on all platforms. If it is ever provided,
|
|
/// it should not be removed in future versions of the compiler.
|
|
///
|
|
/// \returns a TaskFinishedResponse indicating whether or not execution
|
|
/// should proceed
|
|
typedef std::function<TaskFinishedResponse(ProcessId Pid, StringRef ErrorMsg,
|
|
StringRef Output, StringRef Errors,
|
|
void *Context, Optional<int> Signal)>
|
|
TaskSignalledCallback;
|
|
#pragma clang diagnostic pop
|
|
|
|
/// \brief Indicates whether TaskQueue supports buffering output on the
|
|
/// current system.
|
|
///
|
|
/// \note If this returns false, the TaskFinishedCallback passed
|
|
/// to \ref execute will always receive an empty StringRef for output, even
|
|
/// if the task actually generated output.
|
|
static bool supportsBufferingOutput();
|
|
|
|
/// \brief Indicates whether TaskQueue supports parallel execution on the
|
|
/// current system.
|
|
static bool supportsParallelExecution();
|
|
|
|
/// \returns the maximum number of tasks which this TaskQueue will execute in
|
|
/// parallel
|
|
unsigned getNumberOfParallelTasks() const;
|
|
|
|
/// \brief Adds a task to the TaskQueue.
|
|
///
|
|
/// \param ExecPath the path to the executable which the task should execute
|
|
/// \param Args the arguments which should be passed to the task
|
|
/// \param Env the environment which should be used for the task;
|
|
/// must be null-terminated. If empty, inherits the parent's environment.
|
|
/// \param Context an optional context which will be associated with the task
|
|
/// \param SeparateErrors Controls whether error output is reported separately
|
|
virtual void addTask(const char *ExecPath, ArrayRef<const char *> Args,
|
|
ArrayRef<const char *> Env = llvm::None,
|
|
void *Context = nullptr, bool SeparateErrors = false);
|
|
|
|
/// \brief Synchronously executes the tasks in the TaskQueue.
|
|
///
|
|
/// \param Began a callback which will be called when a task begins
|
|
/// \param Finished a callback which will be called when a task finishes
|
|
/// \param Signalled a callback which will be called if a task exited
|
|
/// abnormally due to a signal
|
|
///
|
|
/// \returns true if all tasks did not execute successfully
|
|
virtual bool
|
|
execute(TaskBeganCallback Began = TaskBeganCallback(),
|
|
TaskFinishedCallback Finished = TaskFinishedCallback(),
|
|
TaskSignalledCallback Signalled = TaskSignalledCallback());
|
|
|
|
/// Returns true if there are any tasks that have been queued but have not
|
|
/// yet been executed.
|
|
bool hasRemainingTasks() {
|
|
return !QueuedTasks.empty();
|
|
}
|
|
};
|
|
|
|
/// \brief A class which simulates execution of tasks with behavior similar to
|
|
/// TaskQueue.
|
|
class DummyTaskQueue : public TaskQueue {
|
|
class DummyTask {
|
|
public:
|
|
const char *ExecPath;
|
|
ArrayRef<const char *> Args;
|
|
ArrayRef<const char *> Env;
|
|
void *Context;
|
|
bool SeparateErrors;
|
|
|
|
DummyTask(const char *ExecPath, ArrayRef<const char *> Args,
|
|
ArrayRef<const char *> Env = llvm::None, void *Context = nullptr,
|
|
bool SeparateErrors = false)
|
|
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context),
|
|
SeparateErrors(SeparateErrors) {}
|
|
};
|
|
|
|
std::queue<std::unique_ptr<DummyTask>> QueuedTasks;
|
|
|
|
public:
|
|
/// \brief Create a new DummyTaskQueue instance.
|
|
DummyTaskQueue(unsigned NumberOfParallelTasks = 0);
|
|
virtual ~DummyTaskQueue();
|
|
|
|
virtual void addTask(const char *ExecPath, ArrayRef<const char *> Args,
|
|
ArrayRef<const char *> Env = llvm::None,
|
|
void *Context = nullptr, bool SeparateErrors = false);
|
|
|
|
virtual bool
|
|
execute(TaskBeganCallback Began = TaskBeganCallback(),
|
|
TaskFinishedCallback Finished = TaskFinishedCallback(),
|
|
TaskSignalledCallback Signalled = TaskSignalledCallback());
|
|
};
|
|
|
|
} // end namespace sys
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_BASIC_TASKQUEUE_H
|