Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/ABI/Task.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ class alignas(2 * alignof(void*)) Job :
return Flags.getPriority();
}

void setPriority(JobPriority priority) {
Flags.setPriority(priority);
}

uint32_t getJobId() const {
return Id;
}
Expand Down
31 changes: 30 additions & 1 deletion lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,36 @@ FuncDecl *SILGenModule::getExit() {
Type SILGenModule::getConfiguredExecutorFactory() {
auto &ctx = getASTContext();

// Look in the main module for a typealias
// First look in the @main struct, if any
NominalTypeDecl *mainType = ctx.MainModule->getMainTypeDecl();
if (mainType) {
SmallVector<ValueDecl *, 1> decls;
auto identifier = ctx.getIdentifier("DefaultExecutorFactory");
mainType->lookupQualified(mainType,
DeclNameRef(identifier),
SourceLoc(),
NL_RemoveNonVisible | NL_RemoveOverridden
| NL_OnlyTypes | NL_ProtocolMembers,
decls);
for (auto decl : decls) {
TypeDecl *typeDecl = dyn_cast<TypeDecl>(decl);
if (typeDecl) {
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(typeDecl)) {
return nominalDecl->getDeclaredType();
}

if (isa<AssociatedTypeDecl>(typeDecl)) {
// We ignore associatedtype declarations; those with a default will
// turn into a `typealias` instead.
continue;
}

return typeDecl->getDeclaredInterfaceType();
}
}
}

// Failing that, look at the top level
Type factory = ctx.getNamedSwiftType(ctx.MainModule, "DefaultExecutorFactory");

// If we don't find it, fall back to _Concurrency.PlatformExecutorFactory
Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/Concurrency/CFExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum CoreFoundation {

// .. Main Executor ............................................................

/// A CFRunLoop-based main executor (Apple platforms only)
@available(StdlibDeploymentTarget 6.2, *)
final class CFMainExecutor: DispatchMainExecutor, @unchecked Sendable {

Expand All @@ -58,6 +59,7 @@ final class CFMainExecutor: DispatchMainExecutor, @unchecked Sendable {

// .. Task Executor ............................................................

/// A `TaskExecutor` to match `CFMainExecutor` (Apple platforms only)
@available(StdlibDeploymentTarget 6.2, *)
final class CFTaskExecutor: DispatchGlobalTaskExecutor,
@unchecked Sendable {
Expand Down
57 changes: 57 additions & 0 deletions stdlib/public/Concurrency/Clock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,65 @@ public protocol Clock<Duration>: Sendable {

#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
func sleep(until deadline: Instant, tolerance: Instant.Duration?) async throws

/// Run the given job on an unspecified executor at some point
/// after the given instant.
///
/// Parameters:
///
/// - job: The job we wish to run
/// - at instant: The time at which we would like it to run.
/// - tolerance: The ideal maximum delay we are willing to tolerate.
///
@available(StdlibDeploymentTarget 6.2, *)
func run(_ job: consuming ExecutorJob,
at instant: Instant, tolerance: Duration?)

/// Enqueue the given job on the specified executor at some point after the
/// given instant.
///
/// The default implementation uses the `run` method to trigger a job that
/// does `executor.enqueue(job)`. If a particular `Clock` knows that the
/// executor it has been asked to use is the same one that it will run jobs
/// on, it can short-circuit this behaviour and directly use `run` with
/// the original job.
///
/// Parameters:
///
/// - job: The job we wish to run
/// - on executor: The executor on which we would like it to run.
/// - at instant: The time at which we would like it to run.
/// - tolerance: The ideal maximum delay we are willing to tolerate.
///
@available(StdlibDeploymentTarget 6.2, *)
func enqueue(_ job: consuming ExecutorJob,
on executor: some Executor,
at instant: Instant, tolerance: Duration?)
#endif
}

#if !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
extension Clock {
// The default implementation works by creating a trampoline and calling
// the run() method.
@available(StdlibDeploymentTarget 6.2, *)
public func enqueue(_ job: consuming ExecutorJob,
on executor: some Executor,
at instant: Instant, tolerance: Duration?) {
let trampoline = job.createTrampoline(to: executor)
run(trampoline, at: instant, tolerance: tolerance)
}

// Clocks that do not implement run will fatalError() if you try to use
// them with an executor that does not understand them.
@available(StdlibDeploymentTarget 6.2, *)
public func run(_ job: consuming ExecutorJob,
at instant: Instant, tolerance: Duration?) {
fatalError("\(Self.self) does not implement run(_:at:tolerance:).")
}
}
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY

@available(StdlibDeploymentTarget 5.7, *)
extension Clock {
/// Measure the elapsed time to execute a closure.
Expand Down Expand Up @@ -117,6 +173,7 @@ extension Clock {
enum _ClockID: Int32 {
case continuous = 1
case suspending = 2
case walltime = 3
}

@available(StdlibDeploymentTarget 5.7, *)
Expand Down
33 changes: 33 additions & 0 deletions stdlib/public/Concurrency/ContinuousClock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,36 @@ extension ContinuousClock.Instant: InstantProtocol {
rhs.duration(to: lhs)
}
}

#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
@available(StdlibDeploymentTarget 6.2, *)
extension ContinuousClock {

public func run(_ job: consuming ExecutorJob,
at instant: Instant,
tolerance: Duration?) {
guard let executor = Task<Never,Never>.currentSchedulingExecutor else {
fatalError("no scheduling executor is available")
}

executor.enqueue(job, at: instant,
tolerance: tolerance,
clock: self)
}

public func enqueue(_ job: consuming ExecutorJob,
on executor: some Executor,
at instant: Instant,
tolerance: Duration?) {
if let schedulingExecutor = executor.asSchedulingExecutor {
schedulingExecutor.enqueue(job, at: instant,
tolerance: tolerance,
clock: self)
} else {
let trampoline = job.createTrampoline(to: executor)
run(trampoline, at: instant, tolerance: tolerance)
}
}

}
#endif
Loading