blob: 81c6d771eac3390ec073e9e9b3b66dbf77e11b14 [file] [log] [blame]
// RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out
// RUN: %target-run %t.out | %FileCheck %s
// REQUIRES: stress_test
// UNSUPPORTED: nonatomic_rc
import SwiftPrivate
import StdlibUnittest
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
import Glibc
#elseif os(Windows)
import MSVCRT
#else
#error("Unsupported platform")
#endif
_setTestSuiteFailedCallback() { print("abort()") }
struct RaceTest1 : RaceTestWithPerTrialData {
static var shouldPass: Bool = true
static var iterationCountdown: _stdlib_AtomicInt = _stdlib_AtomicInt(8)
class RaceData {
init() {}
}
typealias ThreadLocalData = Void
typealias Observation = Observation1UInt
func makeRaceData() -> RaceData {
return RaceData()
}
func makeThreadLocalData() -> Void {
return Void()
}
func thread1(
_ raceData: RaceData, _ threadLocalData: inout ThreadLocalData
) -> Observation {
switch RaceTest1.iterationCountdown.fetchAndAdd(-1) {
case 0:
return Observation(0x1)
case 1:
return Observation(RaceTest1.shouldPass ? 0x1 : 0xffff)
case 1, 2:
return Observation(0x2)
case 3, 4, 5:
return Observation(RaceTest1.shouldPass ? 0x2 : 0xfffe)
default:
return Observation(0x1)
}
}
func evaluateObservations(
_ observations: [Observation],
_ sink: (RaceTestObservationEvaluation) -> Void
) {
for observation in observations {
switch observation {
case Observation(0x1):
sink(.pass)
case Observation(0x2):
sink(.passInteresting(String(describing: observation)))
case Observation(0xffff):
sink(.failure)
case Observation(0xfffe):
sink(.failureInteresting(String(describing: observation)))
default:
fatalError("should not happen")
}
}
}
}
var RaceTestSuite = TestSuite("Race")
RaceTestSuite.test("passes") {
RaceTest1.shouldPass = true
RaceTest1.iterationCountdown = _stdlib_AtomicInt(8)
runRaceTest(RaceTest1.self, trials: 10)
}
// CHECK: [ RUN ] Race.passes
// CHECK: stdout>>> Pass: {{.*}} times
// CHECK: stdout>>> Pass (2): 4 times
// CHECK: stdout>>> Failure: 0 times
// CHECK: [ OK ] Race.passes
RaceTestSuite.test("fails") {
RaceTest1.shouldPass = false
RaceTest1.iterationCountdown = _stdlib_AtomicInt(8)
runRaceTest(RaceTest1.self, trials: 10)
}
// CHECK: [ RUN ] Race.fails
// REQUIRES: executable_test
// CHECK: stdout>>> Pass: {{.*}} times
// CHECK: stdout>>> Pass (2): 1 times
// CHECK: stdout>>> Failure: 1 times
// CHECK: stdout>>> Failure (65534): 3 times
// CHECK: [ FAIL ] Race.fails
RaceTestSuite.test("closure") {
let count = _stdlib_AtomicInt(0)
runRaceTest(trials: 10) {
_ = count.fetchAndAdd(1)
}
expectNotEqual(0, count.load())
}
// CHECK: [ RUN ] Race.closure
// CHECK: [ OK ] Race.closure
RaceTestSuite.test("timeout-zero") {
// Zero timeout is still expected to run at least one trial.
let count = _stdlib_AtomicInt(0)
runRaceTest(trials: 2000000000, timeoutInSeconds: 0) {
_ = count.fetchAndAdd(1)
}
expectGT(count.load(), 0)
}
// CHECK: [ RUN ] Race.timeout-zero
// CHECK: [ OK ] Race.timeout-zero
func -(_ lhs: timeval, _ rhs: timeval) -> timeval {
var result = timeval(tv_sec: 0, tv_usec: 0)
result.tv_sec = lhs.tv_sec - rhs.tv_sec
result.tv_usec = lhs.tv_usec - rhs.tv_usec
if result.tv_usec < 0 {
result.tv_usec += 1000000
result.tv_sec -= 1
}
return result
}
func gettimeofday() -> timeval {
var result = timeval(tv_sec: 0, tv_usec: 0)
gettimeofday(&result, nil)
return result
}
RaceTestSuite.test("timeout-small") {
// Verify that the timeout fires after the correct number of seconds.
// If the timeout fails to fire then this test will run for a very long time.
var startTime: timeval
var endTime: timeval
let timeout = 5
let count = _stdlib_AtomicInt(0)
startTime = gettimeofday()
runRaceTest(trials: 2000000000, timeoutInSeconds: timeout) {
_ = count.fetchAndAdd(1)
}
endTime = gettimeofday()
expectGT(count.load(), 0)
// Test should have run to the timeout.
// Test should not have run too long after the timeout.
let duration = endTime - startTime
expectGE(duration.tv_sec, timeout)
expectLT(duration.tv_sec, timeout*100) // large to avoid spurious failures
}
// CHECK: [ RUN ] Race.timeout-small
// CHECK: [ OK ] Race.timeout-small
RaceTestSuite.test("timeout-big") {
// Verify that a short test with a long timeout completes before the timeout.
var startTime: timeval
var endTime: timeval
let timeout = 10000
let count = _stdlib_AtomicInt(0)
startTime = gettimeofday()
runRaceTest(trials: 10, timeoutInSeconds: timeout) {
_ = count.fetchAndAdd(1)
}
endTime = gettimeofday()
expectGT(count.load(), 0)
// Test should have stopped long before the timeout.
let duration = endTime - startTime
expectLT(duration.tv_sec, timeout / 2)
}
// CHECK: [ RUN ] Race.timeout-big
// CHECK: [ OK ] Race.timeout-big
runAllTests()
// CHECK: Race: Some tests failed, aborting