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
7package syscall
8
9import (
10	"sync/atomic"
11)
12
13// origRlimitNofile, if non-nil, is the original soft RLIMIT_NOFILE.
14var 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.
30func init() {
31	var lim Rlimit
32	if err := Getrlimit(RLIMIT_NOFILE, &lim); err == nil && lim.Cur != lim.Max {
33		origRlimitNofile.Store(&lim)
34		nlim := lim
35		nlim.Cur = nlim.Max
36		adjustFileLimit(&nlim)
37		setrlimit(RLIMIT_NOFILE, &nlim)
38	}
39}
40
41func Setrlimit(resource int, rlim *Rlimit) error {
42	if resource == RLIMIT_NOFILE {
43		// Store nil in origRlimitNofile to tell StartProcess
44		// to not adjust the rlimit in the child process.
45		origRlimitNofile.Store(nil)
46	}
47	return setrlimit(resource, rlim)
48}
49