|
22 | 22 | #include "../CompatibilityOverride/CompatibilityOverride.h"
|
23 | 23 | #include "swift/ABI/Actor.h"
|
24 | 24 | #include "swift/ABI/Task.h"
|
| 25 | +#include "TaskPrivate.h" |
25 | 26 | #include "swift/Basic/ListMerger.h"
|
26 | 27 | #include "swift/Concurrency/Actor.h"
|
27 | 28 | #include "swift/Runtime/AccessibleFunction.h"
|
@@ -314,39 +315,109 @@ bool _task_serialExecutor_isSameExclusiveExecutionContext(
|
314 | 315 | const SerialExecutorWitnessTable *wtable);
|
315 | 316 |
|
316 | 317 | SWIFT_CC(swift)
|
317 |
| -static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef executor) { |
| 318 | +static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor) { |
318 | 319 | auto current = ExecutorTrackingInfo::current();
|
319 | 320 |
|
320 | 321 | if (!current) {
|
321 |
| - // TODO(ktoso): checking the "is main thread" is not correct, main executor can be not main thread, relates to rdar://106188692 |
322 |
| - return executor.isMainExecutor() && isExecutingOnMainThread(); |
| 322 | + // We have no current executor, i.e. we are running "outside" of Swift |
| 323 | + // Concurrency. We could still be running on a thread/queue owned by |
| 324 | + // the expected executor however, so we need to try a bit harder before |
| 325 | + // we fail. |
| 326 | + |
| 327 | + // Are we expecting the main executor and are using the main thread? |
| 328 | + if (expectedExecutor.isMainExecutor() && isExecutingOnMainThread()) { |
| 329 | + // TODO(concurrency): consider removing this special case, as checkIsolated will compare against mainQueue already |
| 330 | + return true; |
| 331 | + } |
| 332 | + |
| 333 | + // Otherwise, as last resort, let the expected executor check using |
| 334 | + // external means, as it may "know" this thread is managed by it etc. |
| 335 | + swift_task_checkIsolated(expectedExecutor); |
| 336 | + |
| 337 | + // checkIsolated did not crash, so we are on the right executor, after all! |
| 338 | + return true; |
323 | 339 | }
|
324 | 340 |
|
325 |
| - auto currentExecutor = current->getActiveExecutor(); |
326 |
| - if (currentExecutor == executor) { |
| 341 | + SerialExecutorRef currentExecutor = current->getActiveExecutor(); |
| 342 | + |
| 343 | + // Fast-path: the executor is exactly the same memory address; |
| 344 | + // We assume executors do not come-and-go appearing under the same address, |
| 345 | + // and treat pointer equality of executors as good enough to assume the executor. |
| 346 | + if (currentExecutor == expectedExecutor) { |
327 | 347 | return true;
|
328 | 348 | }
|
329 | 349 |
|
330 |
| - if (executor.isComplexEquality()) { |
| 350 | + // Fast-path, specialize the common case of comparing two main executors. |
| 351 | + if (currentExecutor.isMainExecutor() && expectedExecutor.isMainExecutor()) { |
| 352 | + return true; |
| 353 | + } |
| 354 | + |
| 355 | + // If the expected executor is "default" then we should have matched |
| 356 | + // by pointer equality already with the current executor. |
| 357 | + if (expectedExecutor.isDefaultActor()) { |
| 358 | + // If the expected executor is a default actor, it makes no sense to try |
| 359 | + // the 'checkIsolated' call, it must be equal to the other actor, or it is |
| 360 | + // not the same isolation domain. |
| 361 | + swift_Concurrency_fatalError(0, "Incorrect actor executor assumption"); |
| 362 | + return false; |
| 363 | + } |
| 364 | + |
| 365 | + if (expectedExecutor.isMainExecutor() && !currentExecutor.isMainExecutor()) { |
| 366 | + // TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, otherwise messages will be sub-par and hard to address |
| 367 | + swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected MainActor executor"); |
| 368 | + return false; |
| 369 | + } else if (!expectedExecutor.isMainExecutor() && currentExecutor.isMainExecutor()) { |
| 370 | + // TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, otherwise messages will be sub-par and hard to address |
| 371 | + swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected not-MainActor executor"); |
| 372 | + return false; |
| 373 | + } |
| 374 | + |
| 375 | + if (expectedExecutor.isComplexEquality()) { |
331 | 376 | if (!swift_compareWitnessTables(
|
332 | 377 | reinterpret_cast<const WitnessTable*>(currentExecutor.getSerialExecutorWitnessTable()),
|
333 |
| - reinterpret_cast<const WitnessTable*>(executor.getSerialExecutorWitnessTable()))) { |
| 378 | + reinterpret_cast<const WitnessTable*>(expectedExecutor.getSerialExecutorWitnessTable()))) { |
334 | 379 | // different witness table, we cannot invoke complex equality call
|
335 | 380 | return false;
|
336 | 381 | }
|
| 382 | + |
337 | 383 | // Avoid passing nulls to Swift for the isSame check:
|
338 |
| - if (!currentExecutor.getIdentity() || !executor.getIdentity()) { |
| 384 | + if (!currentExecutor.getIdentity() || !expectedExecutor.getIdentity()) { |
339 | 385 | return false;
|
340 | 386 | }
|
341 | 387 |
|
342 |
| - return _task_serialExecutor_isSameExclusiveExecutionContext( |
| 388 | + auto result = _task_serialExecutor_isSameExclusiveExecutionContext( |
343 | 389 | currentExecutor.getIdentity(),
|
344 |
| - executor.getIdentity(), |
| 390 | + expectedExecutor.getIdentity(), |
345 | 391 | swift_getObjectType(currentExecutor.getIdentity()),
|
346 |
| - executor.getSerialExecutorWitnessTable()); |
| 392 | + expectedExecutor.getSerialExecutorWitnessTable()); |
| 393 | + |
| 394 | + return result; |
347 | 395 | }
|
348 | 396 |
|
349 |
| - return false; |
| 397 | + // This provides a last-resort check by giving the expected SerialExecutor the |
| 398 | + // chance to perform a check using some external knowledge if perhaps we are, |
| 399 | + // after all, on this executor, but the Swift concurrency runtime was just not |
| 400 | + // aware. |
| 401 | + // |
| 402 | + // Unless handled in `swift_task_checkIsolated` directly, this should call |
| 403 | + // through to the executor's `SerialExecutor.checkIsolated`. |
| 404 | + // |
| 405 | + // This call is expected to CRASH, unless it has some way of proving that |
| 406 | + // we're actually indeed running on this executor. |
| 407 | + // |
| 408 | + // For example, when running outside of Swift concurrency tasks, but trying to |
| 409 | + // `MainActor.assumeIsolated` while executing DIRECTLY on the main dispatch |
| 410 | + // queue, this allows Dispatch to check for this using its own tracking |
| 411 | + // mechanism, and thus allow the assumeIsolated to work correctly, even though |
| 412 | + // the code executing is not even running inside a Task. |
| 413 | + // |
| 414 | + // Note that this only works because the closure in assumeIsolated is |
| 415 | + // synchronous, and will not cause suspensions, as that would require the |
| 416 | + // presence of a Task. |
| 417 | + swift_task_checkIsolated(expectedExecutor); |
| 418 | + |
| 419 | + // The checkIsolated call did not crash, so we are on the right executor. |
| 420 | + return true; |
350 | 421 | }
|
351 | 422 |
|
352 | 423 | /// Logging level for unexpected executors:
|
|
0 commit comments