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

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

How to set ulimit -n from a golang program?

问题

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

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

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

  1. package main
  2. import (
  3. "fmt"
  4. "syscall"
  5. )
  6. func main() {
  7. var rLimit syscall.Rlimit
  8. err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  9. if err != nil {
  10. fmt.Println("Error Getting Rlimit ", err)
  11. }
  12. fmt.Println(rLimit)
  13. rLimit.Max = 999999
  14. rLimit.Cur = 999999
  15. err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  16. if err != nil {
  17. fmt.Println("Error Setting Rlimit ", err)
  18. }
  19. err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  20. if err != nil {
  21. fmt.Println("Error Getting Rlimit ", err)
  22. }
  23. fmt.Println("Rlimit Final", rLimit)
  24. }

得到的输出是:

  1. george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit
  2. {4294963002032703 0}
  3. Error Setting Rlimit invalid argument
  4. Rlimit Final {4294963002032703 999999}
  5. george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit
  6. [sudo] password for george:
  7. {4294963002032703 0}
  8. Error Setting Rlimit invalid argument
  9. Rlimit Final {4294963002032703 999999}
  10. george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
  11. 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
  12. george@george-Not-Specified ~/work/odesk/progium/trial $

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

更新:

修复后可以工作。

  1. george@george-Not-Specified ~/work/odesk/progium/trial $ go build getRlimit.go
  2. george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit
  3. {1024 4096}
  4. Error Setting Rlimit operation not permitted
  5. Rlimit Final {1024 4096}
  6. george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit
  7. [sudo] password for george:
  8. {1024 4096}
  9. Rlimit Final {999999 999999}
  10. george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
  11. 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
  12. george@george-Not-Specified ~/work/odesk/progium/trial $ go version
  13. 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.

  1. package main
  2. import (
  3. "fmt"
  4. "syscall"
  5. )
  6. func main() {
  7. var rLimit syscall.Rlimit
  8. err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  9. if err != nil {
  10. fmt.Println("Error Getting Rlimit ", err)
  11. }
  12. fmt.Println(rLimit)
  13. rLimit.Max = 999999
  14. rLimit.Cur = 999999
  15. err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  16. if err != nil {
  17. fmt.Println("Error Setting Rlimit ", err)
  18. }
  19. err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  20. if err != nil {
  21. fmt.Println("Error Getting Rlimit ", err)
  22. }
  23. fmt.Println("Rlimit Final", rLimit)
  24. }

The output obtained was:

  1. george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit
  2. {4294963002032703 0}
  3. Error Setting Rlimit invalid argument
  4. Rlimit Final {4294963002032703 999999}
  5. george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit
  6. [sudo] password for george:
  7. {4294963002032703 0}
  8. Error Setting Rlimit invalid argument
  9. Rlimit Final {4294963002032703 999999}
  10. george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
  11. 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
  12. 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.

  1. george@george-Not-Specified ~/work/odesk/progium/trial $ go build getRlimit.go
  2. george@george-Not-Specified ~/work/odesk/progium/trial $ ./getRlimit
  3. {1024 4096}
  4. Error Setting Rlimit operation not permitted
  5. Rlimit Final {1024 4096}
  6. george@george-Not-Specified ~/work/odesk/progium/trial $ sudo ./getRlimit
  7. [sudo] password for george:
  8. {1024 4096}
  9. Rlimit Final {999999 999999}
  10. george@george-Not-Specified ~/work/odesk/progium/trial $ uname -a
  11. 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
  12. george@george-Not-Specified ~/work/odesk/progium/trial $ go version
  13. 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:

  1. package main
  2. import (
  3. "fmt"
  4. "syscall"
  5. )
  6. func main() {
  7. var rLimit syscall.Rlimit
  8. err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  9. if err != nil {
  10. fmt.Println("Error Getting Rlimit ", err)
  11. }
  12. fmt.Println(rLimit)
  13. rLimit.Max = 999999
  14. rLimit.Cur = 999999
  15. err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  16. if err != nil {
  17. fmt.Println("Error Setting Rlimit ", err)
  18. }
  19. err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  20. if err != nil {
  21. fmt.Println("Error Getting Rlimit ", err)
  22. }
  23. fmt.Println("Rlimit Final", rLimit)
  24. }

输出:

  1. $ uname -a
  2. 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
  3. $ go build rlimit.go
  4. $ ./rlimit
  5. {1024 4096}
  6. Error Setting Rlimit operation not permitted
  7. Rlimit Final {1024 4096}
  8. $ sudo ./rlimit
  9. [sudo] password for peterSO:
  10. {1024 4096}
  11. Rlimit Final {999999 999999}

更新:

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

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

  1. $ uname -a
  2. Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:46:08 UTC 2013 i686 i686 i686 GNU/Linux
  3. $ go version
  4. go version devel +ba52f6399462 Thu Jul 25 09:56:06 2013 -0400 linux/386
  5. $ ulimit -Sn
  6. 1024
  7. $ ulimit -Hn
  8. 4096
  9. $ go build rlimit.go
  10. $ ./rlimit
  11. {1024 4096}
  12. Error Setting Rlimit operation not permitted
  13. Rlimit Final {1024 4096}
  14. $ sudo ./rlimit
  15. [sudo] password for peterSO:
  16. {1024 4096}
  17. Rlimit Final {999999 999999}
  18. $
英文:

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:

  1. package main
  2. import (
  3. "fmt"
  4. "syscall"
  5. )
  6. func main() {
  7. var rLimit syscall.Rlimit
  8. err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  9. if err != nil {
  10. fmt.Println("Error Getting Rlimit ", err)
  11. }
  12. fmt.Println(rLimit)
  13. rLimit.Max = 999999
  14. rLimit.Cur = 999999
  15. err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  16. if err != nil {
  17. fmt.Println("Error Setting Rlimit ", err)
  18. }
  19. err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
  20. if err != nil {
  21. fmt.Println("Error Getting Rlimit ", err)
  22. }
  23. fmt.Println("Rlimit Final", rLimit)
  24. }

Output:

  1. $ uname -a
  2. 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
  3. $ go build rlimit.go
  4. $ ./rlimit
  5. {1024 4096}
  6. Error Setting Rlimit operation not permitted
  7. Rlimit Final {1024 4096}
  8. $ sudo ./rlimit
  9. [sudo] password for peterSO:
  10. {1024 4096}
  11. 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.

  1. $ uname -a
  2. Linux peterSO 3.8.0-26-generic #38-Ubuntu SMP Mon Jun 17 21:46:08 UTC 2013 i686 i686 i686 GNU/Linux
  3. $ go version
  4. go version devel +ba52f6399462 Thu Jul 25 09:56:06 2013 -0400 linux/386
  5. $ ulimit -Sn
  6. 1024
  7. $ ulimit -Hn
  8. 4096
  9. $ go build rlimit.go
  10. $ ./rlimit
  11. {1024 4096}
  12. Error Setting Rlimit operation not permitted
  13. Rlimit Final {1024 4096}
  14. $ sudo ./rlimit
  15. [sudo] password for peterSO:
  16. {1024 4096}
  17. Rlimit Final {999999 999999}
  18. $

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:

确定