https://github.com/opensource-apple/objc4/blob/master/runtim...
Basically, issue a syscall that acquires the PC of all threads. When none of the PCs are in the critical section, then you can garbage collect old objects.
https://github.com/opensource-apple/objc4/blob/master/runtim...
Basically, issue a syscall that acquires the PC of all threads. When none of the PCs are in the critical section, then you can garbage collect old objects.
#define PC_SENTINEL 1
unsigned int count = x86_THREAD_STATE64_COUNT;
kern_return_t okay = thread_get_state (thread, x86_THREAD_STATE64, (thread_state_t)&state, &count);
return (okay == KERN_SUCCESS) ? state.__rip : PC_SENTINEL;
https://github.com/opensource-apple/objc4/blob/master/runtim...If you have a lot of threads running, this could get really expensive. I presume it works, but this doesn't seem like an efficient approach unless your "writes" are extremely rare relative to the number reads and number of threads.
I haven't been able to find source for thread_get_state(), though. I don't think there is any way to get the current PC from a core without an interrupt? I presume it at least reads the PC for sleeping threads without needing to wake them?
There was talk at some point of adding a single syscall that got all the PCs of all the threads at once to cut down on the overhead, but it looks like that still hasn't happened.
What's going on here is something like this:
1. objc_msgSend is Obj-C's method dispatcher, and it depends on method caches to make method lookup faster.
2. Sometimes the method caches become out of date. For instance, maybe the method cache filled up and the Obj-C runtime needs to allocate a larger method cache.
3. This old method cache has to be GC'd at some point, so it's added to a freelist.
4. This GC function (the "write" you're talking about) for these caches runs once the size of outdated method caches grows beyond a certain threshold (garbage_threshold in the code). So it shouldn't run too often. The GC function works by checking if any thread is currently within objc_msgSend. If no function is in objc_msgSend, then the runtime is sure that none of the method caches on the free list is in use.
5. It is definitely optimized for reads. The "read" in this case is literally a method dispatch so it happens all the time, and it's important for the read to be lock-free.