mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Replace Task.h with right (5.6) version
I seem to have copied over the wrong version of Task.h. There is an ABI
mismatch in the size of AsyncContext due to the removal of Flags. This
resulted in programs crashing when running against the backdeploy
library and should have crashed when running on the swift 5.6 runtime.
The successResultPointer pointer was set in AsyncTask::waitFuture, but
with the wrong layout. When the pointer was read in the concurrency
backdeploy library, it was at a different offset, and thus contained a
nullptr.
I pulled the AsyncContextKind and AsyncContextFlags from the old
MetadataValues.h into Task.h as they were removed in commit
aca744b211, but are necessary with the
flags included.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#ifndef SWIFT_ABI_TASK_BACKDEPLOY56_H
|
||||
#define SWIFT_ABI_TASK_BACKDEPLOY56_H
|
||||
|
||||
#include "Concurrency/TaskLocal.h"
|
||||
#include "Executor.h"
|
||||
#include "swift/ABI/HeapObject.h"
|
||||
#include "swift/ABI/Metadata.h"
|
||||
@@ -26,7 +27,7 @@
|
||||
#include "VoucherShims.h"
|
||||
#include "swift/Basic/STLExtras.h"
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <queue> // TODO: remove and replace with our own mpsc
|
||||
|
||||
namespace swift {
|
||||
class AsyncTask;
|
||||
@@ -275,13 +276,6 @@ public:
|
||||
void setTaskId();
|
||||
uint64_t getTaskId();
|
||||
|
||||
/// Get the task's resume function, for logging purposes only. This will
|
||||
/// attempt to see through the various adapters that are sometimes used, and
|
||||
/// failing that will return ResumeTask. The returned function pointer may
|
||||
/// have a different signature than ResumeTask, and it's only for identifying
|
||||
/// code associated with the task.
|
||||
const void *getResumeFunctionForLogging();
|
||||
|
||||
/// Given that we've already fully established the job context
|
||||
/// in the current thread, start running this task. To establish
|
||||
/// the job context correctly, call swift_job_run or
|
||||
@@ -316,14 +310,15 @@ public:
|
||||
void flagAsRunning();
|
||||
void flagAsRunning_slow();
|
||||
|
||||
/// Flag that this task is now suspended.
|
||||
/// Flag that this task is now suspended. This can update the
|
||||
/// priority stored in the job flags if the priority hsa been
|
||||
/// escalated. Generally this should be done immediately after
|
||||
/// clearing ActiveTask and immediately before enqueuing the task
|
||||
/// somewhere. TODO: record where the task is enqueued if
|
||||
/// possible.
|
||||
void flagAsSuspended();
|
||||
void flagAsSuspended_slow();
|
||||
|
||||
/// Flag that the task is to be enqueued on the provided executor and actually
|
||||
/// enqueue it
|
||||
void flagAsAndEnqueueOnExecutor(ExecutorRef newExecutor);
|
||||
|
||||
/// Flag that this task is now completed. This normally does not do anything
|
||||
/// but can be used to locally insert logging.
|
||||
void flagAsCompleted();
|
||||
@@ -566,7 +561,7 @@ public:
|
||||
/// \c Executing, then \c waitingTask has been added to the
|
||||
/// wait queue and will be scheduled when the future completes. Otherwise,
|
||||
/// the future has completed and can be queried.
|
||||
/// The waiting task's async context will be initialized with the parameters if
|
||||
/// The waiting task's async context will be intialized with the parameters if
|
||||
/// the current's task state is executing.
|
||||
FutureFragment::Status waitFuture(AsyncTask *waitingTask,
|
||||
AsyncContext *waitingTaskContext,
|
||||
@@ -614,6 +609,65 @@ inline void Job::runInFullyEstablishedContext() {
|
||||
|
||||
// ==== ------------------------------------------------------------------------
|
||||
|
||||
/// The Swift5.6 AsyncContextKind for the AsyncContext.
|
||||
/// Note that these were removed in Swift5.7
|
||||
/// (aca744b21165a20655502b563a6fa54c2c83efdf).
|
||||
/// Kinds of async context.
|
||||
enum class AsyncContextKind {
|
||||
/// An ordinary asynchronous function.
|
||||
Ordinary = 0,
|
||||
|
||||
/// A context which can yield to its caller.
|
||||
Yielding = 1,
|
||||
|
||||
/// A continuation context.
|
||||
Continuation = 2,
|
||||
|
||||
// Other kinds are reserved for interesting special
|
||||
// intermediate contexts.
|
||||
|
||||
// Kinds >= 192 are private to the implementation.
|
||||
First_Reserved = 192
|
||||
};
|
||||
|
||||
|
||||
/// The Swift5.6 AsyncContextFlags for the AsyncContext.
|
||||
/// Note that these were removed in Swift5.7
|
||||
/// (aca744b21165a20655502b563a6fa54c2c83efdf).
|
||||
/// Flags for async contexts.
|
||||
class AsyncContextFlags : public FlagSet<uint32_t> {
|
||||
public:
|
||||
enum {
|
||||
Kind = 0,
|
||||
Kind_width = 8,
|
||||
|
||||
CanThrow = 8,
|
||||
|
||||
// Kind-specific flags should grow down from 31.
|
||||
|
||||
Continuation_IsExecutorSwitchForced = 31,
|
||||
};
|
||||
|
||||
explicit AsyncContextFlags(uint32_t bits) : FlagSet(bits) {}
|
||||
constexpr AsyncContextFlags() {}
|
||||
AsyncContextFlags(AsyncContextKind kind) {
|
||||
setKind(kind);
|
||||
}
|
||||
|
||||
/// The kind of context this represents.
|
||||
FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, AsyncContextKind,
|
||||
getKind, setKind)
|
||||
|
||||
/// Whether this context is permitted to throw.
|
||||
FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow, canThrow, setCanThrow)
|
||||
|
||||
/// See AsyncContinuationFlags::isExecutorSwitchForced.
|
||||
FLAGSET_DEFINE_FLAG_ACCESSORS(Continuation_IsExecutorSwitchForced,
|
||||
continuation_isExecutorSwitchForced,
|
||||
continuation_setIsExecutorSwitchForced)
|
||||
};
|
||||
|
||||
|
||||
/// An asynchronous context within a task. Generally contexts are
|
||||
/// allocated using the task-local stack alloc/dealloc operations, but
|
||||
/// there's no guarantee of that, and the ABI is designed to permit
|
||||
@@ -634,9 +688,19 @@ public:
|
||||
TaskContinuationFunction * __ptrauth_swift_async_context_resume
|
||||
ResumeParent;
|
||||
|
||||
AsyncContext(TaskContinuationFunction *resumeParent,
|
||||
/// Flags describing this context.
|
||||
///
|
||||
/// Note that this field is only 32 bits; any alignment padding
|
||||
/// following this on 64-bit platforms can be freely used by the
|
||||
/// function. If the function is a yielding function, that padding
|
||||
/// is of course interrupted by the YieldToParent field.
|
||||
AsyncContextFlags Flags;
|
||||
|
||||
AsyncContext(AsyncContextFlags flags,
|
||||
TaskContinuationFunction *resumeParent,
|
||||
AsyncContext *parent)
|
||||
: Parent(parent), ResumeParent(resumeParent) {}
|
||||
: Parent(parent), ResumeParent(resumeParent),
|
||||
Flags(flags) {}
|
||||
|
||||
AsyncContext(const AsyncContext &) = delete;
|
||||
AsyncContext &operator=(const AsyncContext &) = delete;
|
||||
@@ -660,58 +724,36 @@ public:
|
||||
TaskContinuationFunction * __ptrauth_swift_async_context_yield
|
||||
YieldToParent;
|
||||
|
||||
YieldingAsyncContext(TaskContinuationFunction *resumeParent,
|
||||
YieldingAsyncContext(AsyncContextFlags flags,
|
||||
TaskContinuationFunction *resumeParent,
|
||||
TaskContinuationFunction *yieldToParent,
|
||||
AsyncContext *parent)
|
||||
: AsyncContext(resumeParent, parent),
|
||||
: AsyncContext(flags, resumeParent, parent),
|
||||
YieldToParent(yieldToParent) {}
|
||||
|
||||
static bool classof(const AsyncContext *context) {
|
||||
return context->Flags.getKind() == AsyncContextKind::Yielding;
|
||||
}
|
||||
};
|
||||
|
||||
/// An async context that can be resumed as a continuation.
|
||||
class ContinuationAsyncContext : public AsyncContext {
|
||||
public:
|
||||
class FlagsType : public FlagSet<size_t> {
|
||||
public:
|
||||
enum {
|
||||
CanThrow = 0,
|
||||
IsExecutorSwitchForced = 1,
|
||||
};
|
||||
|
||||
explicit FlagsType(size_t bits) : FlagSet(bits) {}
|
||||
constexpr FlagsType() {}
|
||||
|
||||
/// Whether this is a throwing continuation.
|
||||
FLAGSET_DEFINE_FLAG_ACCESSORS(CanThrow,
|
||||
canThrow,
|
||||
setCanThrow)
|
||||
|
||||
/// See AsyncContinuationFlags::isExecutorSwitchForced().
|
||||
FLAGSET_DEFINE_FLAG_ACCESSORS(IsExecutorSwitchForced,
|
||||
isExecutorSwitchForced,
|
||||
setIsExecutorSwitchForced)
|
||||
};
|
||||
|
||||
/// Flags for the continuation. Not public ABI.
|
||||
FlagsType Flags;
|
||||
|
||||
/// An atomic object used to ensure that a continuation is not
|
||||
/// scheduled immediately during a resume if it hasn't yet been
|
||||
/// awaited by the function which set it up. Not public ABI.
|
||||
/// awaited by the function which set it up.
|
||||
std::atomic<ContinuationStatus> AwaitSynchronization;
|
||||
|
||||
/// The error result value of the continuation.
|
||||
/// This should be null-initialized when setting up the continuation.
|
||||
/// Throwing resumers must overwrite this with a non-null value.
|
||||
/// Public ABI.
|
||||
SwiftError *ErrorResult;
|
||||
|
||||
/// A pointer to the normal result value of the continuation.
|
||||
/// Normal resumers must initialize this before resuming.
|
||||
/// Public ABI.
|
||||
OpaqueValue *NormalResult;
|
||||
|
||||
/// The executor that should be resumed to.
|
||||
/// Public ABI.
|
||||
ExecutorRef ResumeToExecutor;
|
||||
|
||||
void setErrorResult(SwiftError *error) {
|
||||
@@ -719,7 +761,11 @@ public:
|
||||
}
|
||||
|
||||
bool isExecutorSwitchForced() const {
|
||||
return Flags.isExecutorSwitchForced();
|
||||
return Flags.continuation_isExecutorSwitchForced();
|
||||
}
|
||||
|
||||
static bool classof(const AsyncContext *context) {
|
||||
return context->Flags.getKind() == AsyncContextKind::Continuation;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user