| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| #if DEPLOYMENT_RUNTIME_OBJC || os(Linux) |
| import Foundation |
| import XCTest |
| #else |
| import SwiftFoundation |
| import SwiftXCTest |
| #endif |
| |
| import CoreFoundation |
| |
| class TestNSLock: XCTestCase { |
| static var allTests: [(String, (TestNSLock) -> () throws -> Void)] { |
| return [ |
| |
| ("test_lockWait", test_lockWait), |
| ("test_threadsAndLocks", test_threadsAndLocks), |
| |
| ] |
| } |
| |
| |
| func test_lockWait() { |
| let condition = NSCondition() |
| let lock = NSLock() |
| |
| func test(waitTime: CFTimeInterval, shouldLock: Bool) -> Bool { |
| let locked = lock.lock(before: Date.init(timeIntervalSinceNow: waitTime)) |
| if locked { |
| lock.unlock() |
| } |
| return locked == shouldLock |
| } |
| |
| let thread = Thread() { |
| condition.lock() |
| condition.signal() |
| condition.unlock() |
| |
| lock.lock() |
| Thread.sleep(forTimeInterval: 8) |
| lock.unlock() |
| } |
| condition.lock() |
| thread.start() |
| condition.wait() |
| condition.unlock() |
| |
| XCTAssertTrue(test(waitTime: 0, shouldLock: false)) |
| XCTAssertTrue(test(waitTime: -1, shouldLock: false)) |
| XCTAssertTrue(test(waitTime: 1, shouldLock: false)) |
| XCTAssertTrue(test(waitTime: 4, shouldLock: false)) |
| XCTAssertTrue(test(waitTime: 8, shouldLock: true)) |
| XCTAssertTrue(test(waitTime: -1, shouldLock: true)) |
| } |
| |
| |
| func test_threadsAndLocks() { |
| let condition = NSCondition() |
| let lock = NSLock() |
| let threadCount = 1000 |
| let endSeconds: Double = 10 |
| |
| let endTime = Date.init(timeIntervalSinceNow: endSeconds) |
| var threadsStarted = Array<Bool>(repeating: false, count: threadCount) |
| let arrayLock = NSLock() |
| |
| for t in 0..<threadCount { |
| let thread = Thread() { |
| arrayLock.lock() |
| threadsStarted[t] = true |
| arrayLock.unlock() |
| |
| condition.lock() |
| condition.wait() |
| condition.unlock() |
| for _ in 1...100 { |
| let r = (endSeconds * drand48()) / 100 |
| Thread.sleep(forTimeInterval: r) |
| if lock.lock(before: endTime) { |
| lock.unlock() |
| } |
| } |
| arrayLock.lock() |
| threadsStarted[t] = false |
| arrayLock.unlock() |
| } |
| thread.start() |
| } |
| |
| var totalThreads = 0 |
| repeat { |
| arrayLock.lock() |
| totalThreads = threadsStarted.filter {$0 == true }.count |
| arrayLock.unlock() |
| } while totalThreads < threadCount |
| XCTAssertEqual(totalThreads, threadCount) |
| |
| condition.lock() |
| condition.broadcast() |
| condition.unlock() |
| |
| Thread.sleep(until: endTime) |
| repeat { |
| arrayLock.lock() |
| totalThreads = threadsStarted.filter {$0 == false }.count |
| arrayLock.unlock() |
| } while totalThreads < threadCount |
| XCTAssertEqual(totalThreads, threadCount) |
| |
| let gotLock = lock.try() |
| XCTAssertTrue(gotLock) |
| if gotLock { |
| lock.unlock() |
| } |
| } |
| } |