@@ -0,0 +1,57 @@
1+//go:build unix
2+
3+// This file contains code inspired by Syncthing's rlimit implementation
4+// Syncthing is licensed under the Mozilla Public License Version 2.0
5+// See: https://github.com/syncthing/syncthing/blob/main/LICENSE
6+
7+package watcher
8+
9+import (
10+ "runtime"
11+ "syscall"
12+)
13+
14+const (
15+ // macOS has a specific limit for RLIMIT_NOFILE
16+ darwinOpenMax = 10240
17+)
18+
19+// MaximizeOpenFileLimit tries to set the resource limit RLIMIT_NOFILE (number
20+// of open file descriptors) to the max (hard limit), if the current (soft
21+// limit) is below the max. Returns the new (though possibly unchanged) limit,
22+// or an error if it could not be changed.
23+func MaximizeOpenFileLimit() (int, error) {
24+ // Get the current limit on number of open files.
25+ var lim syscall.Rlimit
26+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
27+ return 0, err
28+ }
29+
30+ // If we're already at max, there's no need to try to raise the limit.
31+ if lim.Cur >= lim.Max {
32+ return int(lim.Cur), nil
33+ }
34+
35+ // macOS doesn't like a soft limit greater than OPEN_MAX
36+ if runtime.GOOS == "darwin" && lim.Max > darwinOpenMax {
37+ lim.Max = darwinOpenMax
38+ }
39+
40+ // Try to increase the limit to the max.
41+ oldLimit := lim.Cur
42+ lim.Cur = lim.Max
43+ if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
44+ return int(oldLimit), err
45+ }
46+
47+ // If the set succeeded, perform a new get to see what happened. We might
48+ // have gotten a value lower than the one in lim.Max, if lim.Max was
49+ // something that indicated "unlimited" (i.e. intmax).
50+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
51+ // We don't really know the correct value here since Getrlimit
52+ // mysteriously failed after working once... Shouldn't ever happen.
53+ return 0, err
54+ }
55+
56+ return int(lim.Cur), nil
57+}