rlimit.mx raw

   1  // Copyright 2022 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build unix
   6  
   7  package syscall
   8  
   9  import (
  10  	"sync/atomic"
  11  )
  12  
  13  // origRlimitNofile, if non-nil, is the original soft RLIMIT_NOFILE.
  14  var origRlimitNofile atomic.Pointer[Rlimit]
  15  
  16  // Some systems set an artificially low soft limit on open file count, for compatibility
  17  // with code that uses select and its hard-coded maximum file descriptor
  18  // (limited by the size of fd_set).
  19  //
  20  // Go does not use select, so it should not be subject to these limits.
  21  // On some systems the limit is 256, which is very easy to run into,
  22  // even in simple programs like gofmt when they parallelize walking
  23  // a file tree.
  24  //
  25  // After a long discussion on go.dev/issue/46279, we decided the
  26  // best approach was for Go to raise the limit unconditionally for itself,
  27  // and then leave old software to set the limit back as needed.
  28  // Code that really wants Go to leave the limit alone can set the hard limit,
  29  // which Go of course has no choice but to respect.
  30  func init() {
  31  	var lim Rlimit
  32  	if err := Getrlimit(RLIMIT_NOFILE, &lim); err == nil && lim.Max > 0 && lim.Cur < lim.Max-1 {
  33  		origRlimitNofile.Store(&lim)
  34  		nlim := lim
  35  
  36  		// We set Cur to Max - 1 so that we are more likely to
  37  		// detect cases where another process uses prlimit
  38  		// to change our resource limits. The theory is that
  39  		// using prlimit to change to Cur == Max is more likely
  40  		// than using prlimit to change to Cur == Max - 1.
  41  		// The place we check for this is in exec_linux.go.
  42  		nlim.Cur = nlim.Max - 1
  43  
  44  		adjustFileLimit(&nlim)
  45  		setrlimit(RLIMIT_NOFILE, &nlim)
  46  	}
  47  }
  48  
  49  func Setrlimit(resource int, rlim *Rlimit) error {
  50  	if resource == RLIMIT_NOFILE {
  51  		// Store nil in origRlimitNofile to tell StartProcess
  52  		// to not adjust the rlimit in the child process.
  53  		origRlimitNofile.Store(nil)
  54  	}
  55  	return setrlimit(resource, rlim)
  56  }
  57