Merge pull request #1279 from spevans/pr_thread_name
diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c
index 70597d1..5aefe20 100644
--- a/CoreFoundation/Base.subproj/CFPlatform.c
+++ b/CoreFoundation/Base.subproj/CFPlatform.c
@@ -1316,15 +1316,18 @@
return thread;
}
-CF_SWIFT_EXPORT void _CFThreadSetName(const char *_Nullable name) {
+CF_SWIFT_EXPORT int _CFThreadSetName(pthread_t thread, const char *_Nonnull name) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
- pthread_setname_np(name);
+ if (pthread_equal(pthread_self(), thread)) {
+ return pthread_setname_np(name);
+ }
+ return EINVAL;
#elif DEPLOYMENT_TARGET_LINUX
- pthread_setname_np(pthread_self(), name);
+ return pthread_setname_np(thread, name);
#endif
}
-CF_SWIFT_EXPORT int _CFThreadGetName(char *buf, int length) {
+CF_SWIFT_EXPORT int _CFThreadGetName(char *_Nonnull buf, int length) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
return pthread_getname_np(pthread_self(), buf, length);
#elif DEPLOYMENT_TARGET_ANDROID
diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
index 2651cd8..57e2f12 100644
--- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
+++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
@@ -316,8 +316,8 @@
CF_EXPORT _CFThreadRef _CFThreadCreate(const _CFThreadAttributes attrs, void *_Nullable (* _Nonnull startfn)(void *_Nullable), void *restrict _Nullable context);
-CF_SWIFT_EXPORT void _CFThreadSetName(const char *_Nullable name);
-CF_SWIFT_EXPORT int _CFThreadGetName(char *buf, int length);
+CF_SWIFT_EXPORT int _CFThreadSetName(pthread_t thread, const char *_Nonnull name);
+CF_SWIFT_EXPORT int _CFThreadGetName(char *_Nonnull buf, int length);
CF_EXPORT Boolean _CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char theChar);
CF_EXPORT CFCharacterSetRef _CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet);
diff --git a/Foundation/Thread.swift b/Foundation/Thread.swift
index dae27cd..1489969 100644
--- a/Foundation/Thread.swift
+++ b/Foundation/Thread.swift
@@ -43,6 +43,9 @@
private func NSThreadStart(_ context: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? {
let thread: Thread = NSObject.unretainedReference(context!)
Thread._currentThread.set(thread)
+ if let name = thread.name {
+ _CFThreadSetName(pthread_self(), name)
+ }
thread._status = .executing
thread.main()
thread._status = .finished
@@ -141,11 +144,12 @@
}
internal var _main: () -> Void = {}
-#if os(OSX) || os(iOS) || CYGWIN
- private var _thread: pthread_t? = nil
-#elseif os(Linux) || os(Android)
+#if os(Android)
private var _thread = pthread_t()
+#else
+ private var _thread: pthread_t? = nil
#endif
+
#if CYGWIN
internal var _attr : pthread_attr_t? = nil
#else
@@ -202,8 +206,8 @@
open var name: String? {
didSet {
- if _thread == Thread.current._thread {
- _CFThreadSetName(name)
+ if let thread = _thread {
+ _CFThreadSetName(thread, name ?? "" )
}
}
}
diff --git a/TestFoundation/TestThread.swift b/TestFoundation/TestThread.swift
index f5b224b..6f09c8d 100644
--- a/TestFoundation/TestThread.swift
+++ b/TestFoundation/TestThread.swift
@@ -59,34 +59,70 @@
}
func test_threadName() {
- let thread = Thread()
- XCTAssertNil(thread.name)
- func getPThreadName() -> String? {
- var buf = [Int8](repeating: 0, count: 16)
+ // Compare the name set in pthreads()
+ func compareThreadName(to name: String) {
+ var buf = [Int8](repeating: 0, count: 128)
+#if os(OSX) || os(iOS)
+ // Dont use _CF functions on macOS as it will break testing with Darwin's native Foundation.
+ let r = pthread_getname_np(pthread_self(), &buf, buf.count)
+#else
let r = _CFThreadGetName(&buf, Int32(buf.count))
-
- guard r == 0 else {
- return nil
+#endif
+ if r == 0 {
+ XCTAssertEqual(String(cString: buf), name)
+ } else {
+ XCTFail("Cant get thread name")
}
- return String(cString: buf)
}
+ // No name is set initially
+ XCTAssertNil(Thread.current.name)
+
+#if os(Linux) // Linux sets the initial thread name to the process name.
+ compareThreadName(to: "TestFoundation")
+#else
+ compareThreadName(to: "")
+#endif
+ Thread.current.name = "mainThread"
+ XCTAssertEqual(Thread.mainThread.name, "mainThread")
+
+ let condition = NSCondition()
+ condition.lock()
+
let thread2 = Thread() {
- Thread.current.name = "Thread2"
- XCTAssertEqual(Thread.current.name, "Thread2")
- XCTAssertEqual(Thread.current.name, getPThreadName())
- }
+ XCTAssertEqual(Thread.current.name, "Thread2-1")
+ compareThreadName(to: "Thread2-1")
+ Thread.current.name = "Thread2-2"
+ XCTAssertEqual(Thread.current.name, "Thread2-2")
+ compareThreadName(to: "Thread2-2")
+
+ Thread.current.name = "12345678901234567890"
+ XCTAssertEqual(Thread.current.name, "12345678901234567890")
+#if os(OSX) || os(iOS)
+ compareThreadName(to: "12345678901234567890")
+#elseif os(Linux)
+ // pthread_setname_np() only allows 15 characters on Linux, so setting it fails
+ // and the previous name will still be there.
+ compareThreadName(to: "Thread2-2")
+#endif
+ condition.lock()
+ condition.signal()
+ condition.unlock()
+ }
+ thread2.name = "Thread2-1"
thread2.start()
- Thread.current.name = "CurrentThread"
- XCTAssertEqual(Thread.current.name, getPThreadName())
+ // Allow 1 second for thread2 to finish
+ XCTAssertTrue(condition.wait(until: Date(timeIntervalSinceNow: 1)))
+ condition.unlock()
+ XCTAssertEqual(Thread.current.name, "mainThread")
+ XCTAssertEqual(Thread.mainThread.name, "mainThread")
let thread3 = Thread()
thread3.name = "Thread3"
XCTAssertEqual(thread3.name, "Thread3")
- XCTAssertNotEqual(thread3.name, getPThreadName())
}
func test_mainThread() {