Nat! bio photo


Senior Mull

Twitter Github Twitch

mulle_objc: root objects and unloadable runtimes

Continued from mulle_objc: ivar layout with @property.

You want to write a plug-in for some C interface of another application. You figure out that you can solve the problem very easily in Objective-C, so why not do it ?

Examining a plug-in architecture

How would this look on Windows, where a plug-in is typically a DLL?

  1. The plug-in container would call LoadLibrary to load your DLL. When the DLL is loaded it will get a call to DllMain with DLL_PROCESS_ATTACH.
  2. The plug-in container will rendezvous with your code by looking up known functions via GetProcAddress and call them.
  3. Eventually your DLL may become ejected with FreeLibrary. You will get another call to DllMain, this time with DLL_PROCESS_DETACH for that.

A plug-in can be loaded and unloaded in succession - multiple times - by the same process.

Provisions in mulle_objc for loading and unloading Objective-C

When you are loading in Objective-C code, the code will immediately start to construct a runtime and class-hierarchy. Possibly instances will be created inside +load already. These hidden objects are almost impossible to get rid of in traditional ObjC runtimes. (1)

Then your code executes, which will create more instances. Not all of them will be reclaimable by enclosing NSAutoreleasePools. (2)

So when it comes to unloading, the runtime should get rid of all it’s classes and caches. Without classes, instances are useless and all of them should be removed too. (3)

MulleObjC maintains the whole object graph

If you create an object in mulle_objc, that is not owned by a NSAutoreleasePool it must be declared a root object. There are five different kind of root objects

Type Description
Threads MulleObjC maintains a list of NSThread objects. Threads are the holders of the NSAutoreleasePools.
Placeholders Placeholders of class clusters (like NSString) are also maintained separately. Class-cluster placeholders implement the MulleObjCClassCluster protocol, which implements the appropriate runtime mechanics.
Singletons Singletons (like +[NSNotificationCenter defaultCenter]) have their own runtime list. Singletons should implement the MulleObjCSingleton protocol.
Others All other root objects (like for instance NSApp) use the NSObject protocol methods -_becomeRootObject to announce their “rootness” and -_resignAsRootObject to reliquish it.

struct _mulle_objc_runtime is retain counted

When the retain count of the runtime reaches zero in _mulle_objc_release_runtime, the runtime will self destruct with _mulle_objc_runtime_dealloc. This function will untie the runtime from the current thread and free all resources.

struct _mulle_objc_runtime may be thread-local

If you define MULLE_OBJC_THREAD_LOCAL_RUNTIME when compiling all your code, the runtime will not be global but instead exist on a per-thread basis. This has the following consequences:

  1. Objects created by a thread refer to a different class system and can not be shared with objects of another thread.
  2. Calls that need the runtime are a lot slower, because the runtime has to be retrieved with mulle_thread_tss_get.

You should determine on a per-case basis, if this feature is useful to you. The runtime ensures, that you can not mix “global” runtime and “thread local” runtime code. The default is “global”.

Continue to mulle_objc: method searching and accidental override protection.

Post a comment

All comments are held for moderation; basic HTML formatting accepted.

E-mail: (not published)