File: runOnMainActor.swift

package info (click to toggle)
swiftlang 6.1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,791,532 kB
  • sloc: cpp: 9,901,743; ansic: 2,201,431; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (158 lines) | stat: -rw-r--r-- 4,535 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -Xfrontend -disable-dynamic-actor-isolation -swift-version 6 -g -import-objc-header %S/Inputs/RunOnMainActor.h %import-libdispatch )

// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: concurrency_runtime
// REQUIRES: libdispatch
// REQUIRES: asserts

// UNSUPPORTED: freestanding

// For now we do not support back deployment or use os stdlib
// UNSUPPORTED: back_deployment_concurrency
// UNSUPPORTED: use_os_stdlib

import StdlibUnittest
import Dispatch

// MARK: Test runOnMainActor in all modes. We use the one future proof API in
// dispatch: dispatch_assert_queue.

////////////////////////
// MARK: Declarations //
////////////////////////

@_silgen_name("dispatch_assert_queue")
func dispatch_assertQueue(_ ptr: UnsafeRawPointer)

func checkIfOnMainQueue() {
  dispatch_assertQueue(getDispatchMain())
}

actor Custom {
}

@globalActor
struct CustomActor {
  static var shared: Custom {
    return Custom()
  }
}

/////////////////
// MARK: Tests //
/////////////////

let tests = TestSuite("RunOnMainActor")

tests.test("checkIfOnMainQueue does not crash on the main queue") { @MainActor () -> () in
  // Why do we crash if this is synchronous.
  expectCrashLater()
  checkIfOnMainQueue()
}

tests.test("checkIfOnMainQueue does not crash on the main queue") { @MainActor () async -> () in
  checkIfOnMainQueue()
}

tests.test("checkIfOnMainQueue crashes off the main queue") {
  expectCrashLater()
  await { @CustomActor in
    print("=> checkIfOnMainQueue crashes off the main queue")
    checkIfOnMainQueue()
  }()
}

tests.test("checkIfOnMainQueue crashes off the main queue 2") { @CustomActor () async -> () in
  expectCrashLater()
  print("=> checkIfOnMainQueue crashes off the main queue 2")
  checkIfOnMainQueue()
}

tests.test("checkIfOnMainQueue crashes using pure dispatch queue") { @CustomActor () async -> () in
  expectCrashLater()

  let queue = DispatchQueue(label: "")

  await withCheckedContinuation { cont in
    queue.async {
      checkIfOnMainQueue()
      cont.resume()
    }
  }
}

tests.test("RunOnMainActor on MainActor") { @MainActor () async -> () in
  // This is main actor isolated.
  _taskRunOnMainActor { @MainActor in
    print("=> RunOnMainActor on MainActor")
    checkIfOnMainQueue()
  }
}

tests.test("RunOnMainActor off MainActor") {
  await { @CustomActor in
    _taskRunOnMainActor { @MainActor in
      print("=> RunOnMainActor off MainActor")
      checkIfOnMainQueue()
    }
  }()
}

tests.test("RunOnMainActor off MainActor 2") { @CustomActor () async -> () in
  _taskRunOnMainActor {
    print("=> RunOnMainActor off MainActor 2")
    checkIfOnMainQueue()
  }
}

// This succeeds since assert understands that a child queue runs on the main
// queue.
tests.test("checkIfOnMainQueue in SubQueue from MainActor") { @CustomActor () async -> () in
  let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: DispatchQueue.main)

  print("=> checkIfOnMainQueue in SubQueue from MainActor start!")

  // We cannot use the checked continuation, since we are not going to come back
  // to the custom actor.
  await withCheckedContinuation { cont in
    childQueue.async {
      print("=> checkIfOnMainQueue in SubQueue from MainActor")
      checkIfOnMainQueue()
      cont.resume()
    }
  }
}

// This should not fail when backwards deployed since we use the backwards
// compatibility trick.
tests.test("taskRunOnMainActor in SubQueue from MainActor") { @CustomActor () async -> () in
  let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: DispatchQueue.main)

  await withCheckedContinuation { cont in
    childQueue.async {
      _taskRunOnMainActor { @MainActor () -> () in
        print("=> taskRunOnMainActor in SubQueue from MainActor")
        checkIfOnMainQueue()
        cont.resume()
      }
    }
  }
}

tests.test("taskRunOnMainActor in SubQueue off MainActor") { @CustomActor () async -> () in
  let d = DispatchQueue.init(label: "", qos: .background)
  let childQueue = DispatchQueue.init(label: "", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: d)

  await withCheckedContinuation { cont in
    childQueue.async {
      _taskRunOnMainActor { @MainActor in
        print("=> taskRunOnMainActor in SubQueue from MainActor")
        checkIfOnMainQueue()
        cont.resume()
      }
    }
  }
}

await runAllTestsAsync()