OS X limits max threads, max threads per process and max processes based on total physical memory (and whether serverperfmode is set in boot-args)
see xnu osfmk/kern/startup.c : scale_setup()
For testing, sometimes we may need more threads than these limits allow.
The limits are exposed via sysctl but only as a read only value.
We can however alter the limits using a kernel extension.
This involves writing to kernel private symbols using a method given by Evan Lojewski at
ref: http://lists.apple.com/archives/darwin-kernel/2010/Jul/msg00017.html
For per process max thread limit we have to set the global variable task_threadmax and task_max
see xnu osfmk/kern/startup.c : scale_setup()
clang -I/usr/include/ -F/System/Library/Frameworks/ -framework System -lstdc++ kextsymboltool.c -o kextsymboltool
nm -gj /mach_kernel > allsymbols
echo "_task_threadmax" > ${NAME}.exports
echo "_task_max" >> ${NAME}.exports
kextsymboltool -arch x86_64 -import allsymbols -export ${NAME}.exports -output ${NAME}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>MissingSymbols</string>
<key>CFBundleGetInfoString</key>
<string>MissingSymbols</string>
<key>CFBundleIdentifier</key>
<string>com.abc.xyz.MissingSymbols</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Symbols for Raise Thread limit</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>10.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>10.0.0</string>
<key>OSBundleCompatibleVersion</key>
<string>8.0.0</string>
<key>OSBundleRequired</key>
<string>Root</string>
<key>OSKernelResource</key>
<true/>
<key>OSBundleAllowUserLoad</key>
<true/>
</dict>
</plist>
#include <mach/mach_types.h>
kern_return_t RaiseMaxThreads_start(kmod_info_t * ki, void *d);
kern_return_t RaiseMaxThreads_stop(kmod_info_t *ki, void *d);
extern int task_threadmax;
extern int task_max;
static int task_threadmax_old = 0;
static int task_max_old = 0;
kern_return_t RaiseMaxThreads_start(kmod_info_t * ki, void *d)
{
task_threadmax_old = task_threadmax;
task_max_old = task_max;
task_max = task_threadmax = 20000;
return KERN_SUCCESS;
}
kern_return_t RaiseMaxThreads_stop(kmod_info_t *ki, void *d)
{
if (task_threadmax_old != 0) {
task_threadmax = task_threadmax_old;
task_max = task_max_old;
}
return KERN_SUCCESS;
}
see xnu osfmk/kern/startup.c : scale_setup()
For testing, sometimes we may need more threads than these limits allow.
The limits are exposed via sysctl but only as a read only value.
We can however alter the limits using a kernel extension.
This involves writing to kernel private symbols using a method given by Evan Lojewski at
ref: http://lists.apple.com/archives/darwin-kernel/2010/Jul/msg00017.html
For per process max thread limit we have to set the global variable task_threadmax and task_max
see xnu osfmk/kern/startup.c : scale_setup()
- First build kextsymboltool (xnu/SETUP/kextsymboltool)
clang -I/usr/include/ -F/System/Library/Frameworks/ -framework System -lstdc++ kextsymboltool.c -o kextsymboltool
- Then create helper kext binary having private symbols
nm -gj /mach_kernel > allsymbols
echo "_task_threadmax" > ${NAME}.exports
echo "_task_max" >> ${NAME}.exports
kextsymboltool -arch x86_64 -import allsymbols -export ${NAME}.exports -output ${NAME}
- Create a plugin Kext
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>MissingSymbols</string>
<key>CFBundleGetInfoString</key>
<string>MissingSymbols</string>
<key>CFBundleIdentifier</key>
<string>com.abc.xyz.MissingSymbols</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Symbols for Raise Thread limit</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>10.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>10.0.0</string>
<key>OSBundleCompatibleVersion</key>
<string>8.0.0</string>
<key>OSBundleRequired</key>
<string>Root</string>
<key>OSKernelResource</key>
<true/>
<key>OSBundleAllowUserLoad</key>
<true/>
</dict>
</plist>
- Create main Kext (RaiseMaxThreads.kext) that overrides the limits
#include <mach/mach_types.h>
kern_return_t RaiseMaxThreads_start(kmod_info_t * ki, void *d);
kern_return_t RaiseMaxThreads_stop(kmod_info_t *ki, void *d);
extern int task_threadmax;
extern int task_max;
static int task_threadmax_old = 0;
static int task_max_old = 0;
kern_return_t RaiseMaxThreads_start(kmod_info_t * ki, void *d)
{
task_threadmax_old = task_threadmax;
task_max_old = task_max;
task_max = task_threadmax = 20000;
return KERN_SUCCESS;
}
kern_return_t RaiseMaxThreads_stop(kmod_info_t *ki, void *d)
{
if (task_threadmax_old != 0) {
task_threadmax = task_threadmax_old;
task_max = task_max_old;
}
return KERN_SUCCESS;
}
- Copy the MissingSymbols.kext to
- Add com.abc.xyz.MissingSymbols to the OSBundleLibraries in Info.plist for RaiseMaxThreads.kext
- Load the kext and test using