3

I'm running into problems on my OS X machine that I can trace back to the number of open files allowed per process. If I look at the maxfiles option using launchctl's limit command (on my OS X El Cap machine)

$ launchctl limit
    cpu         unlimited      unlimited      
    filesize    unlimited      unlimited      
    data        unlimited      unlimited      
    stack       8388608        67104768       
    core        0              unlimited      
    rss         unlimited      unlimited      
    memlock     unlimited      unlimited      
    maxproc     709            1064           
    maxfiles    256            unlimited

There appears to be a soft limit of 256, and a hard limit of "unlimited". I'd like to change the soft limit to be something like 2048, and leave the hard limit untouched. When I look at limit's arguments

$ launchctl help limit
Usage: launchctl limit [<limit-name> [<both-limits> | <soft-limit> <hard-limit>]

It appears I can either set both limits to the same thing, or set a value for soft and hard. However, if I attempt to set a hard limit of unlimited.

$ sudo launchctl limit maxfiles 2048 unlimited

I end up with the curious value of 10240

$ launchctl limit
    cpu         unlimited      unlimited      
    filesize    unlimited      unlimited      
    data        unlimited      unlimited      
    stack       8388608        67104768       
    core        0              unlimited      
    rss         unlimited      unlimited      
    memlock     unlimited      unlimited      
    maxproc     709            1064           
    maxfiles    2048           10240          

What's going on here? Is it possible to set a value of unlimited? If not, is that a limitation of the launchctl limit command, or something on the system level? If the later, what are all those initial value of unlimited reporting? Or is this Apple being Apple?

For bonus points -- does anyone know why this limit is set so low in the first place?

2

This is something that XNU, FreeBSD, TrueOS, and OpenBSD all have in common. There is no way to unlimit the open file descriptors hard and soft limits. The various operating system kernels, whilst differing amongst themselves on the exact behaviour, simply do not permit setting the RLIMIT_NOFILES limits to RLIM_INFINITY with the setrlimit() function.

This is entirely undocumented in all of them.

The undocumented behaviour is that both the soft and the hard limits for the data segment, the stack segment, the maximum number of processes per user, and the maximum number of open file descriptors are all capped by the values of various sysctl kernel variables. The details, such as exactly which kernel variable is the cap for each limit, vary from operating system to operating system.

  • On XNU, privileged processes cannot set the open file descriptors limits higher than the value of the kern.maxfiles kernel variable; and unprivileged processes cannot set the open file descriptors limits higher than the value of the kern.maxfilesperproc kernel variable. Here is the code.
  • On FreeBSD and TrueOS, processes cannot set the open file descriptors limits higher than the value of the kern.maxfilesperproc kernel variable. Here is the code.
  • On OpenBSD, processes cannot set the open file descriptors limits higher than the value of the kern.maxfiles kernel variable. Here is the code.

In all of them, the cap is silent. The setrlimit() call does not return an error. It simply, and silently, sets a lower value for the limit than the value that the program requested. (XNU has a "POSIX mode" in which it raises an error if one attempts to raise the soft limit beyond the cap. But setting the hard limit, as you are doing, is silently capped like on the other operating systems.) If a program attempts to disable enforcement of a limit, on these operating systems what happens instead is that the limit continues to be enforced, at the level of the cap value.

Strictly speaking, this is thus a contravention of the Single Unix Specification, which requires a specific behaviour of RLIM_INFINITY and makes no provision for silently not providing that behaviour without an error return:

Specifying RLIM_INFINITY as any resource limit value on a successful call to setrlimit() inhibits enforcement of that resource limit.

The launchctl limit command, as the manual says, is simply a way of instructing the launchd process to call setrlimit() to set its own process resource limits. So what you are seeing is the launchd process starting with an unlimited hard limit on the number of open file descriptors, and then gaining a finite limit, the value of kern.maxfilesperproc, at the first attempt to set the hard open file descriptor limit to unlimited.

(Much the same happens on FreeBSD/TrueOS, with the open file descriptors hard limit that process #1 starts with being high and the process #1 program explicitly re-setting the hard limit to a lower finite value.)

(There is actually a quite nasty bug in GNOME Terminal where it ends up unable to start any terminal sessions, that can be triggered on these operating systems if the open file descriptors hard limit that the GNOME Terminal server process initially inherits from its parent happens to be higher than the current value of kern.maxfiles/kern.maxfilesperproc. The GNOME Terminal authors decided that a failure to set the hard limit to the same value that was initially read is a fatal error, without accounting for the fact that GNOME Terminal will have in the meantime triggered the XNU/BSD behaviour that silently lowers the hard limit, causing their code to end up trying to raise it, which is grounds for failure.)

10240 is simply the compiled-in initial value of the kern.maxfilesperproc kernel variable on XNU. It is, however, not quite this simple. At system bootstrap, when in "server performance mode", XNU will instead initialize this variable to 75000 times the scaling value.

  • Since at least Sierra (10.12.6), setrlimit now returns invalid argument when the requested limit is too high. See github.com/golang/go/issues/30401. – Jeff Allen Mar 7 at 16:28
  • No, that's simply the "POSIX mode" behaviour that I mentioned. – JdeBP Mar 11 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.