mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Implements SE-0055: https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md - Add NULL as an extra inhabitant of Builtin.RawPointer (currently hardcoded to 0 rather than being target-dependent). - Import non-object pointers as Optional/IUO when nullable/null_unspecified (like everything else). - Change the type checker's *-to-pointer conversions to handle a layer of optional. - Use 'AutoreleasingUnsafeMutablePointer<NSError?>?' as the type of error parameters exported to Objective-C. - Drop NilLiteralConvertible conformance for all pointer types. - Update the standard library and then all the tests. I've decided to leave this commit only updating existing tests; any new tests will come in the following commits. (That may mean some additional implementation work to follow.) The other major piece that's missing here is migration. I'm hoping we get a lot of that with Swift 1.1's work for optional object references, but I still need to investigate.
119 lines
2.9 KiB
Swift
119 lines
2.9 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import SwiftPrivatePthreadExtras
|
|
#if os(OSX) || os(iOS)
|
|
import Darwin
|
|
#elseif os(Linux)
|
|
import Glibc
|
|
#endif
|
|
|
|
|
|
var StringTestSuite = TestSuite("String")
|
|
|
|
extension String {
|
|
var bufferID: UInt {
|
|
return unsafeBitCast(_core._owner, to: UInt.self)
|
|
}
|
|
var capacityInBytes: Int {
|
|
return _core.nativeBuffer!.capacity
|
|
}
|
|
}
|
|
|
|
// Swift.String has an optimization that allows us to append to a shared string
|
|
// buffer. Make sure that it works correctly when two threads try to append to
|
|
// different non-shared strings that point to the same shared buffer.
|
|
|
|
enum ThreadID {
|
|
case Primary
|
|
case Secondary
|
|
}
|
|
|
|
var barrierVar: UnsafeMutablePointer<_stdlib_pthread_barrier_t>? = nil
|
|
var sharedString: String = ""
|
|
var secondaryString: String = ""
|
|
|
|
func barrier() {
|
|
var ret = _stdlib_pthread_barrier_wait(barrierVar!)
|
|
expectTrue(ret == 0 || ret == _stdlib_PTHREAD_BARRIER_SERIAL_THREAD)
|
|
}
|
|
|
|
func sliceConcurrentAppendThread(_ tid: ThreadID) {
|
|
for i in 0..<100 {
|
|
barrier()
|
|
if tid == .Primary {
|
|
// Get a fresh buffer.
|
|
sharedString = ""
|
|
sharedString.append("abc")
|
|
sharedString.reserveCapacity(16)
|
|
expectLE(16, sharedString.capacityInBytes)
|
|
}
|
|
|
|
barrier()
|
|
|
|
// Get a private string.
|
|
var privateString = sharedString
|
|
|
|
barrier()
|
|
|
|
// Append to the private string.
|
|
if tid == .Primary {
|
|
privateString.append("def")
|
|
} else {
|
|
privateString.append("ghi")
|
|
}
|
|
|
|
barrier()
|
|
|
|
// Verify that contents look good.
|
|
if tid == .Primary {
|
|
expectEqual("abcdef", privateString)
|
|
} else {
|
|
expectEqual("abcghi", privateString)
|
|
}
|
|
expectEqual("abc", sharedString)
|
|
|
|
// Verify that only one thread took ownership of the buffer.
|
|
if tid == .Secondary {
|
|
secondaryString = privateString
|
|
}
|
|
barrier()
|
|
if tid == .Primary {
|
|
expectTrue(
|
|
(privateString.bufferID == sharedString.bufferID) !=
|
|
(secondaryString.bufferID == sharedString.bufferID))
|
|
}
|
|
}
|
|
}
|
|
|
|
StringTestSuite.test("SliceConcurrentAppend") {
|
|
barrierVar = UnsafeMutablePointer(allocatingCapacity: 1)
|
|
barrierVar!.initialize(with: _stdlib_pthread_barrier_t())
|
|
var ret = _stdlib_pthread_barrier_init(barrierVar!, nil, 2)
|
|
expectEqual(0, ret)
|
|
|
|
let (createRet1, tid1) = _stdlib_pthread_create_block(
|
|
nil, sliceConcurrentAppendThread, .Primary)
|
|
let (createRet2, tid2) = _stdlib_pthread_create_block(
|
|
nil, sliceConcurrentAppendThread, .Secondary)
|
|
|
|
expectEqual(0, createRet1)
|
|
expectEqual(0, createRet2)
|
|
|
|
let (joinRet1, _) = _stdlib_pthread_join(tid1!, Void.self)
|
|
let (joinRet2, _) = _stdlib_pthread_join(tid2!, Void.self)
|
|
|
|
expectEqual(0, joinRet1)
|
|
expectEqual(0, joinRet2)
|
|
|
|
ret = _stdlib_pthread_barrier_destroy(barrierVar!)
|
|
expectEqual(0, ret)
|
|
|
|
barrierVar!.deinitialize()
|
|
barrierVar!.deallocateCapacity(1)
|
|
}
|
|
|
|
runAllTests()
|
|
|