Skip to content

[NSThread] Implement main and isMainThread #748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ CF_EXPORT char *_Nullable *_Nonnull _CFEnviron(void);
CF_EXPORT void CFLog1(CFLogLevel lev, CFStringRef message);

CF_EXPORT Boolean _CFIsMainThread(void);
CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);

CF_EXPORT CFHashCode __CFHashDouble(double d);

Expand Down
36 changes: 25 additions & 11 deletions Foundation/NSThread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
//


#if os(OSX) || os(iOS)
#if os(macOS) || os(iOS)
import Darwin
#elseif os(Linux) || CYGWIN
#elseif os(Linux) || os(Android) || CYGWIN
import Glibc
private func pthread_main_thread_np() -> pthread_t {
return _CF_pthread_main_thread_np()
}
private func pthread_main_np() -> Int32 {
return _CFIsMainThread() ? 1 : 0
}
#endif

import CoreFoundation
Expand Down Expand Up @@ -57,18 +63,25 @@ private func NSThreadStart(_ context: UnsafeMutableRawPointer?) -> UnsafeMutable
}

open class Thread : NSObject {

static internal let _mainThread = Thread(thread: pthread_main_thread_np())
static internal var _currentThread = NSThreadSpecific<Thread>()
open class var current: Thread {
if isMainThread {
return _mainThread
}

return Thread._currentThread.get() {
return Thread(thread: pthread_self())
}
}

open class var isMainThread: Bool { NSUnimplemented() }
open class var isMainThread: Bool {
return pthread_main_np() != 0
}

// !!! NSThread's mainThread property is incorrectly exported as "main", which conflicts with its "main" method.
open class var mainThread: Thread { NSUnimplemented() }
open class var main: Thread {
return _mainThread
}

/// Alternative API for detached thread creation
/// - Experiment: This is a draft API currently under consideration for official import into Foundation as a suitable alternative to creation via selector
Expand Down Expand Up @@ -131,7 +144,7 @@ open class Thread : NSObject {
}

internal var _main: (Void) -> Void = {}
#if os(OSX) || os(iOS) || CYGWIN
#if os(macOS) || os(iOS) || CYGWIN
private var _thread: pthread_t? = nil
#elseif os(Linux) || os(Android)
private var _thread = pthread_t()
Expand Down Expand Up @@ -186,10 +199,11 @@ open class Thread : NSObject {
#endif
}

open func main() {
_main()
// FIXME: should be a function but conflicts with the `class var main` propery
open var main: (Void) -> Void {
return self._main
}

open var name: String? {
NSUnimplemented()
}
Expand Down Expand Up @@ -229,7 +243,7 @@ open class Thread : NSObject {
}

open var isMainThread: Bool {
NSUnimplemented()
return Thread._mainThread._thread == _thread
}

open func cancel() {
Expand Down
59 changes: 58 additions & 1 deletion TestFoundation/TestNSThread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,68 @@
class TestNSThread : XCTestCase {
static var allTests: [(String, (TestNSThread) -> () throws -> Void)] {
return [
("test_currentThread", test_currentThread ),
("test_mainThread", test_mainThread),
("test_mainThreadFirstAccess", test_mainThreadFirstAccess),
("test_currentThread", test_currentThread),
("test_threadStart", test_threadStart),
]
}

func test_mainThread() {
let main = Thread.main
XCTAssertNotNil(main)
XCTAssertTrue(main.isMainThread)
XCTAssertTrue(Thread.isMainThread)
XCTAssertEqual(Thread.current, Thread.main)

var started = false
let condition = NSCondition()

let thread = Thread() {
let current = Thread.current
XCTAssertNotEqual(main, current)
XCTAssertFalse(current.isMainThread)

condition.lock()
started = true
condition.broadcast()
condition.unlock()
}
thread.start()

condition.lock()
if !started {
condition.wait()
}
condition.unlock()
XCTAssertTrue(started)
}

func test_mainThreadFirstAccess() {
var started = false
let condition = NSCondition()

var main: Thread? = nil
let thread = Thread() {
main = Thread.main
XCTAssertNotEqual(main, Thread.current)

condition.lock()
started = true
condition.broadcast()
condition.unlock()
}
thread.start()

condition.lock()
if !started {
condition.wait()
}
condition.unlock()
XCTAssertTrue(started)
XCTAssertEqual(main, Thread.current)
}

func test_currentThread() {
let thread1 = Thread.current
let thread2 = Thread.current
Expand Down