如何从golang程序中设置ulimit -n?

huangapple go评论107阅读模式
英文:

How to set ulimit -n from a golang program?

问题

我的目的是在一个golang程序中设置ulimit -n,这样我就不必全局设置,而是在程序中限制它。

找到了相同的系统调用setrlimit和getrlimit。(http://linux.die.net/man/2/setrlimit)

但是当我尝试一个相同的示例程序时,我得到了一个错误,说设置值无效。

package main

import (
	"fmt"
	"syscall"
)

func main() {
	var rLimit syscall.Rlimit

	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)

	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println(rLimit)

	rLimit.Max = 999999
	rLimit.Cur = 999999

	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Setting Rlimit ", err)
	}

	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println("Rlimit Final", rLimit)
}

得到的输出是:

george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{4294963002032703 0}
Error Setting Rlimit  invalid argument
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit 
[sudo] password for george: 
{4294963002032703 0}
Error Setting Rlimit  invalid argument 
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ 

所以我能够得到rlimit
设置限制失败并返回错误。
尽管它失败了,但当我再次获取值时,MAX值已经改变,但CUR值保持不变。
这个错误可能是由于我的内核有问题还是程序有问题?我在哪里可以找到更多信息,如何处理这样的问题?

更新:

修复后可以工作。

george@george-Not-Specified ~/work/odesk/progium/trial $ go build getRlimit.go 
george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit                                                                                               
[sudo] password for george: 
{1024 4096}
Rlimit Final {999999 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012    i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ go version
go version devel +7c42cfa28e24 Tue Jul 30 14:22:14 2013 +1000 linux/386
英文:

My purspose was to set ulimit -n from within a golang program so that I do not have to set it globally but restrict it within the program.

Found systemcalls setrlimit and get rlimit for the same. (http://linux.die.net/man/2/setrlimit)

But when I tried a sample program for the same I was getting an error saying invalid argument while setting the value.

package main

import (
	"fmt"
	"syscall"
)

func main() {
	var rLimit syscall.Rlimit

	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)

	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println(rLimit)

	rLimit.Max = 999999
	rLimit.Cur = 999999

	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Setting Rlimit ", err)
	}

	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println("Rlimit Final", rLimit)
}

The output obtained was:

george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{4294963002032703 0}
Error Setting Rlimit  invalid argument
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit 
[sudo] password for george: 
{4294963002032703 0}
Error Setting Rlimit  invalid argument 
Rlimit Final {4294963002032703 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ 

So I was able to get the rlimit
Setting the limit failed and returned an error.
Even though it failed the MAX value got changed when I took the value again but CUR value remains the same.
Can this error be due to some issue with my kernel or is it a bad program? Where can I find more information and how to deal with an issue like this?

Update:

Works after the fix has been made.

george@george-Not-Specified ~/work/odesk/progium/trial $ go build getRlimit.go 
george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit 
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit                                                                                               
[sudo] password for george: 
{1024 4096}
Rlimit Final {999999 999999}
george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
Linux george-Not-Specified 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012    i686 i686 i686 GNU/Linux
george@george-Not-Specified ~/work/odesk/progium/trial $ go version
go version devel +7c42cfa28e24 Tue Jul 30 14:22:14 2013 +1000 linux/386

答案1

得分: 33

它按预期工作。

> setrlimit(2).
>
> 软限制是内核对应资源强制执行的值。硬限制作为软限制的上限:非特权进程只能将其软限制设置为从0到硬限制的范围内的值,并(不可逆地)降低其硬限制。特权进程(在Linux下:具有CAP_SYS_RESOURCE能力的进程)可以对任一限制值进行任意更改。

rlimit.go:

package main

import (
	"fmt"
	"syscall"
)

func main() {
	var rLimit syscall.Rlimit
	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println(rLimit)
	rLimit.Max = 999999
	rLimit.Cur = 999999
	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Setting Rlimit ", err)
	}
	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println("Rlimit Final", rLimit)
}

输出:

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:43:33 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO:
{1024 4096}
Rlimit Final {999999 999999}

更新:

我成功地在linux/amd64上运行了rlimit.go,但你在linux/386上失败了。GetrlimitSetrlimit在Linux 32位发行版中存在Go的错误。这些错误已经修复。

使用Go的default分支tip(包括错误修复),运行以下命令,并使用结果更新你的问题。

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:46:08 UTC 2013 i686 i686 i686 GNU/Linux
$ go version
go version devel +ba52f6399462 Thu Jul 25 09:56:06 2013 -0400 linux/386
$ ulimit -Sn
1024
$ ulimit -Hn
4096
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO: 
{1024 4096}
Rlimit Final {999999 999999}
$ 
英文:

It works as expected.

> setrlimit(2).
>
> The soft limit is the value that the kernel enforces for the
> corresponding resource. The hard limit acts as a ceiling for the soft
> limit: an unprivileged process may only set its soft limit to a value
> in the range from 0 up to the hard limit, and (irreversibly) lower its
> hard limit. A privileged process (under Linux: one with the
> CAP_SYS_RESOURCE capability) may make arbitrary changes to either
> limit value.

rlimit.go:

package main

import (
	"fmt"
	"syscall"
)

func main() {
	var rLimit syscall.Rlimit
	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println(rLimit)
	rLimit.Max = 999999
	rLimit.Cur = 999999
	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Setting Rlimit ", err)
	}
	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
	if err != nil {
		fmt.Println("Error Getting Rlimit ", err)
	}
	fmt.Println("Rlimit Final", rLimit)
}

Output:

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:43:33 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO:
{1024 4096}
Rlimit Final {999999 999999}

UPDATE:

I successfully ran rlimit.go for linux/amd64, you failed for linux/386. There were a Go bugs in Getrlimit and Setrlimit for Linux 32-bit distributions. These bugs have been fixed.

Using the Go default branch tip (to include the bug fixes), run the following, and update your question with the results.

$ uname -a
Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:46:08 UTC 2013 i686 i686 i686 GNU/Linux
$ go version
go version devel +ba52f6399462 Thu Jul 25 09:56:06 2013 -0400 linux/386
$ ulimit -Sn
1024
$ ulimit -Hn
4096
$ go build rlimit.go
$ ./rlimit
{1024 4096}
Error Setting Rlimit  operation not permitted
Rlimit Final {1024 4096}
$ sudo ./rlimit
[sudo] password for peterSO: 
{1024 4096}
Rlimit Final {999999 999999}
$ 

huangapple
  • 本文由 发表于 2013年7月24日 01:37:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/17817204.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定