2015-08-15 15:20:58 +02:00
|
|
|
// Copyright (C) 2015 The Syncthing Authors.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
2017-02-09 07:52:18 +01:00
|
|
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
2015-08-15 15:20:58 +02:00
|
|
|
|
|
|
|
// +build !windows
|
|
|
|
|
|
|
|
package osutil
|
|
|
|
|
2019-12-03 07:26:22 +01:00
|
|
|
import (
|
|
|
|
"runtime"
|
|
|
|
"syscall"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
darwinOpenMax = 10240
|
|
|
|
)
|
2015-08-15 15:20:58 +02:00
|
|
|
|
2016-05-08 12:54:22 +02:00
|
|
|
// MaximizeOpenFileLimit tries to set the resource limit RLIMIT_NOFILE (number
|
2015-08-15 15:20:58 +02:00
|
|
|
// of open file descriptors) to the max (hard limit), if the current (soft
|
|
|
|
// limit) is below the max. Returns the new (though possibly unchanged) limit,
|
2016-01-17 12:53:56 +01:00
|
|
|
// or an error if it could not be changed.
|
2015-08-15 15:20:58 +02:00
|
|
|
func MaximizeOpenFileLimit() (int, error) {
|
|
|
|
// Get the current limit on number of open files.
|
|
|
|
var lim syscall.Rlimit
|
|
|
|
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're already at max, there's no need to try to raise the limit.
|
|
|
|
if lim.Cur >= lim.Max {
|
|
|
|
return int(lim.Cur), nil
|
|
|
|
}
|
|
|
|
|
2019-12-03 07:26:22 +01:00
|
|
|
// macOS doesn't like a soft limit greater then OPEN_MAX
|
|
|
|
// See also: man setrlimit
|
|
|
|
if runtime.GOOS == "darwin" && lim.Max > darwinOpenMax {
|
2021-03-20 16:32:36 +01:00
|
|
|
lim.Max = darwinOpenMax
|
2019-12-03 07:26:22 +01:00
|
|
|
}
|
|
|
|
|
2015-08-15 15:20:58 +02:00
|
|
|
// Try to increase the limit to the max.
|
|
|
|
oldLimit := lim.Cur
|
|
|
|
lim.Cur = lim.Max
|
|
|
|
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
|
|
|
|
return int(oldLimit), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the set succeeded, perform a new get to see what happened. We might
|
|
|
|
// have gotten a value lower than the one in lim.Max, if lim.Max was
|
2016-05-08 12:54:22 +02:00
|
|
|
// something that indicated "unlimited" (i.e. intmax).
|
2015-08-15 15:20:58 +02:00
|
|
|
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
|
|
|
|
// We don't really know the correct value here since Getrlimit
|
|
|
|
// mysteriously failed after working once... Shouldn't ever happen, I
|
|
|
|
// think.
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(lim.Cur), nil
|
|
|
|
}
|