Recently I stumbled upon a problem related to maximum number of open files and maximum number of processes per user. This would be a quick one in my homeland known as Linux, but proved to be quite a feat of tinkering on OSX El Capitan. What would be a 30 seconds thing on linux turned into a day of googling, linux nostalgia and cursing Apple and the day decided to give up on linux.

By default my macbook pro had these as defaults:

Dejans-MacBook-Pro:~ deki$ ulimit -a  
core file size          (blocks, -c) 0  
data seg size           (kbytes, -d) unlimited  
file size               (blocks, -f) unlimited  
max locked memory       (kbytes, -l) unlimited  
max memory size         (kbytes, -m) unlimited  
open files                      (-n) 256  
pipe size            (512 bytes, -p) 1  
stack size              (kbytes, -s) 8192  
cpu time               (seconds, -t) unlimited  
max user processes              (-u) 709  
virtual memory          (kbytes, -v) unlimited  
Dejans-MacBook-Pro:~ deki$  

Now if you attempt to open 1000 websocket clients, like I foolishly did, you will be surprised with the outcome. Long story short, number of open files (256) and number of max user processes as well, (in my specific case) were the culprit. First thing I tried, coming from Linux land was to set the values using ulimit. This failed miserably with not allowed message. Some google foo revealed that this has been changing a lot between different versions of OSX, and one should try with launchctl limit, which surprise, surprise did not work either.
Both attempts resulted in one big fat FAIL. After even more serious googling, someone explained the need for two new files, one for maxfiles and the other for maxproc, and those will be then used by launchctl to set system wide limits after reboot.

The files in question:

  1. /Library/LaunchDaemons/limit.maxfiles.plist
  2. /Library/LaunchDaemons/limit.maxproc.plist

Content of the files should be as shown bellow:

<?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>Label</key>
    <string>limit.maxfiles</string>
    <key>ProgramArguments</key>
    <array>
      <string>launchctl</string>
      <string>limit</string>
      <string>maxfiles</string>
      <string>524288</string>
      <string>524288</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
  </dict>
</plist>  

and the second one for maxproc as shown:

<?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>Label</key>
        <string>limit.maxproc</string>
      <key>ProgramArguments</key>
        <array>
          <string>launchctl</string>
          <string>limit</string>
          <string>maxproc</string>
          <string>2048</string>
          <string>2048</string>
        </array>
      <key>RunAtLoad</key>
        <true />
      <key>ServiceIPC</key>
        <false />
    </dict>
  </plist>

Crazy as it sounds, files created, reboot and nothing. Still sucking diesel. After day or so of even more intensive googling, I have learned that Apple believes MacbookPro will be used by hipsters, Justin Bieber and Rihanna sort of people, and not the developers sort, so they have provided utility called csrutil which prevents setting values other then those Apple sees as consistent, without telling you anything, just silently ignoring your settings.

Right....Now what?

Updated thanks to Gilles Celli:

As it turns out this one can work even without disabling csr on osx, the way to do it: Change ownership of the above files to root:wheel and it reload them with:

# sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist
# sudo launchctl load -w /Library/LaunchDaemons/limit.maxproc.plist

After reload it should work.

So how do you turn csrutil off? Google says sudo csrutil disable... Ummm, not so easy, can only be done in Recovery Mode. So, reboot, hold command + R to enter Recovery Mode, once there open terminal and do csrutil disable... Finally a breakthrough...disabled.

Another reboot and my shiny two plist files take effect giving me:

Dejans-MacBook-Pro:~ deki$ ulimit -a  
core file size          (blocks, -c) 0  
data seg size           (kbytes, -d) unlimited  
file size               (blocks, -f) unlimited  
max locked memory       (kbytes, -l) unlimited  
max memory size         (kbytes, -m) unlimited  
open files                      (-n) 524288  
pipe size            (512 bytes, -p) 1  
stack size              (kbytes, -s) 8192  
cpu time               (seconds, -t) unlimited  
max user processes              (-u) 2048  
virtual memory          (kbytes, -v) unlimited  
Dejans-MacBook-Pro:~ deki$