Pthread_Create Swift Sample

pthread_create swift sample

Faced the problem too. Here is short sample below. Hope it help someone further:

Swift 4

class ThreadContext {

var someValue: String = "Some value"
}

func doSomething(pointer: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? {

let pContext = pointer.bindMemory(to: ThreadContext.self, capacity: 1)
print("Hello world: \(pContext.pointee.someValue)")

return nil
}

var attibutes = UnsafeMutablePointer<pthread_attr_t>.allocate(capacity: 1)
guard 0 == pthread_attr_init(attibutes) else {

fatalError("unable to initialize attributes")
}

defer {

pthread_attr_destroy(attibutes)
}

guard 0 == pthread_attr_setdetachstate(attibutes, PTHREAD_CREATE_JOINABLE) else {

fatalError("unable to set detach state")
}

let pContext = UnsafeMutablePointer<ThreadContext>.allocate(capacity: 1)
var context = ThreadContext()
pContext.pointee = context

var thread: pthread_t? = nil
let result = pthread_create(&thread, attibutes, doSomething, pContext)

guard result == 0, let thread = thread else {

fatalError("unable to start pthread")
}

pthread_join(thread, nil)

Spawn thread with Swift entry point from within C function in iOS

You can access POSIX threading mechanisms in Swift. I have some examples of working with C in this project and this other hobby project. Hopefully they are useful to you.

When working with things like pthread_create you will want to pass in either a Swift function or closure as the function pointer argument. I attempted going from Swift => C and having C start the thread with a Swift function via @_cdecl and wasn't able to get it working. It might be possible but the context of how I had things setup I couldn't get it in this case.

The other thing to keep in mind is that once you are in C land you will need a way to get back. This is typically done through void* as your context pointer. From Swift you will likely want to pass in an UnsafePointer you are managing or use Unmanaged<T> to directly pass a class instance you have into C and back into Swift.

POSIX threading on ios

One potential issue would be how the storage for the passed in structure mystruct is created. The lifetime of that variable is very critical to its usage in the thread. For example, if the caller of detachnewthread had that declared on the stack and then returned before the thread finished, it would be undefined behavior. Likewise, if it were dynamically allocated, then it is necessary to make sure it is not freed before the thread is finished.

In response to the comment/question: The necessity of some kind of mutex depends on the usage. For the sake of discussion, I will assume it is dynamically allocated. If the calling thread fills in the contents of the structure prior to creating the "child" thread and can guarantee that it will not be freed until after the child thread exits, and the subsequent access is read/only, then you would not need a mutex to protect it. I can imagine that type of scenario if the structure contains information that the child thread needs for completing its task.

If, however, more than one thread will be accessing the contents of the structure and one or more threads will be changing the data (writing to the structure), then you probably do need a mutex to protect it.

Who creates and owns the call stack and how does call stack works in multithread?

XNU kernel does it. Swift threads are POSIX pthreads aka Mach threads. During program startup the XNU kernel parses Mach-O executable format and handles either modern LC_MAIN or legacy LC_UNIXTHREAD load command (among others). This is handled in kernel functions:

static
load_return_t
load_main(
struct entry_point_command *epc,
thread_t thread,
int64_t slide,
load_result_t *result
)

&

static
load_return_t
load_unixthread(
struct thread_command *tcp,
thread_t thread,
int64_t slide,
load_result_t *result
)

which do happen to be open source

LC_MAIN initialises the stack through thread_userstackdefault

LC_UNIXTHREAD through load_threadstack.

As @PeterCordes mentions in comments only when the kernel creates the main thread the started process itself can spawn child threads from it's own main thread either through some api like GCD or directly through syscall (bsdthread_create, not sure if any others). The syscall happens to have
user_addr_t stack as it's 3rd argument (i.e. rdx in x86-64 System V kernel ABI used by MacOS). Reference for MacOS syscalls

I haven't thoroughly investigated details of this particular stack argument, but I would imagine it's similar to thread_userstackdefault / load_threadstack approach.

I do believe your doubt about Swift runtime responsibility may arise due to frequent mentions of data structures (like Swift struct - no pun intended) being stored on the stack (which is btw implementation detail and not guaranteed feature of the runtime).

Update:

He's an example main.swift command line program ilustrating the idea.

import Foundation

struct testStruct {
var a: Int
}

class testClass {
}

func testLocalVariables() {
print("main thread function with local varablies")
var struct1 = testStruct(a: 5)
withUnsafeBytes(of: &struct1) { print($0) }
var classInstance = testClass()
print(NSString(format: "%p", unsafeBitCast(classInstance, to: Int.self)))
}
testLocalVariables()

print("Main thread", Thread.isMainThread)
var struct1 = testStruct(a: 5)
var struct1Copy = struct1

withUnsafeBytes(of: &struct1) { print($0) }
withUnsafeBytes(of: &struct1Copy) { print($0) }

var string = "testString"
var stringCopy = string

withUnsafeBytes(of: &string) { print($0) }
withUnsafeBytes(of: &stringCopy) { print($0) }

var classInstance = testClass()
var classInstanceAssignment = classInstance
var classInstance2 = testClass()

print(NSString(format: "%p", unsafeBitCast(classInstance, to: Int.self)))
print(NSString(format: "%p", unsafeBitCast(classInstanceAssignment, to: Int.self)))
print(NSString(format: "%p", unsafeBitCast(classInstance2, to: Int.self)))

DispatchQueue.global(qos: .background).async {
print("Child thread", Thread.isMainThread)
withUnsafeBytes(of: &struct1) { print($0) }
withUnsafeBytes(of: &struct1Copy) { print($0) }
withUnsafeBytes(of: &string) { print($0) }
withUnsafeBytes(of: &stringCopy) { print($0) }
print(NSString(format: "%p", unsafeBitCast(classInstance, to: Int.self)))
print(NSString(format: "%p", unsafeBitCast(classInstanceAssignment, to: Int.self)))
print(NSString(format: "%p", unsafeBitCast(classInstance2, to: Int.self)))
}

//Keep main thread alive indefinitely so that process doesn't exit
CFRunLoopRun()

My output looks like this:

main thread function with local varablies
UnsafeRawBufferPointer(start: 0x00007ffeefbfeff8, count: 8)
0x7fcd0940cd30
Main thread true
UnsafeRawBufferPointer(start: 0x000000010058a6f0, count: 8)
UnsafeRawBufferPointer(start: 0x000000010058a6f8, count: 8)
UnsafeRawBufferPointer(start: 0x000000010058a700, count: 16)
UnsafeRawBufferPointer(start: 0x000000010058a710, count: 16)
0x7fcd0940cd40
0x7fcd0940cd40
0x7fcd0940c900
Child thread false
UnsafeRawBufferPointer(start: 0x000000010058a6f0, count: 8)
UnsafeRawBufferPointer(start: 0x000000010058a6f8, count: 8)
UnsafeRawBufferPointer(start: 0x000000010058a700, count: 16)
UnsafeRawBufferPointer(start: 0x000000010058a710, count: 16)
0x7fcd0940cd40
0x7fcd0940cd40
0x7fcd0940c900

Now we can observe a couple of interesting things:

  1. Class instances clearly occupy a different part of memory than Structs
  2. Assigning a struct to a new variable makes a copy to a new memory address
  3. Assigning class instance just copies the pointer.
  4. Both main thread and child thread when referring to global Structs point to exactly same memory
  5. Strings do have a Struct container.

Update2 - proof of 4^
We can actually inspect the memory underneath:

x 0x10058a6f0 -c 8
0x10058a6f0: 05 00 00 00 00 00 00 00 ........
x 0x10058a6f8 -c 8
0x10058a6f8: 05 00 00 00 00 00 00 00 ........

So this definitely is the actual struct raw data i.e. the struct itself.

Update 3

I added a testLocalVariables() function, to distinguish between Swift Struct defined as global and local variables. In this case

x 0x00007ffeefbfeff8 -c 8
0x7ffeefbfeff8: 05 00 00 00 00 00 00 00 ........

it clearly lives on the thread stack.

Last but not least when in lldb I do:

re read rsp
rsp = 0x00007ffeefbfefc0 from main thread
re read rsp
rsp = 0x000070000291ea40 from child thread

it yields different value for each thread, so the thread stacks are clearly distinct.

Digging further
There's a handy memory region lldb command which sheds some light what's going on.

memory region 0x000000010058a6f0
[0x000000010053d000-0x000000010058b000) rw- __DATA

So global Structs sit in preallocated executable writeable __DATA memory page (same one where your global variables live). Same command for class 0x7fcd0940cd40 address isn't as spectacular (I reckon because that's a dynamically allocated heap). Analogously for thread stack address 0x7ffeefbfefc0 which clearly isn't a process memory region.

Fortunately there is one last tool to further go down the rabbit hole.

vmmap -v -purge pid which does confirm classes sit in MALLOC_ed heap and likewise a thread stack (at least for main thread) can be cross referenced to Stack.

Somewhat related question is also here.

HTH

How to get thread id of a pthread in linux c program?

pthread_self() function will give the thread id of current thread.

pthread_t pthread_self(void);

The pthread_self() function returns the Pthread handle of the calling thread. The pthread_self() function does NOT return the integral thread of the calling thread. You must use pthread_getthreadid_np() to return an integral identifier for the thread.

NOTE:

pthread_id_np_t   tid;
tid = pthread_getthreadid_np();

is significantly faster than these calls, but provides the same behavior.

pthread_id_np_t   tid;
pthread_t self;
self = pthread_self();
pthread_getunique_np(&self, &tid);

Using NSJSONSerialization with swift on ubuntu/linux

NSJSONSerialization is partly implemented (serialization is not yet implemented)

do it yourself, in accordance with your needs, and you will see, that it is the best investment and great way to understand Swift and its possibilities. you can also use one of the opensource libraries available around. SwiftyJSON is very popular, for an example

As mentioned by Sebastian Osiński, unfortunately it use NSJSONSerialization too.

you can check this very simple, but working example swift json. it is far away to be 'perfect', but as an inspiration it could help you, i hope so.



Related Topics



Leave a reply



Submit