pproffd.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Package pproffd is for detecting resource leaks due to unclosed handles.
  2. package pproffd
  3. import (
  4. "io"
  5. "net"
  6. "os"
  7. "runtime/pprof"
  8. )
  9. const enabled = false
  10. var p *pprof.Profile
  11. func init() {
  12. if enabled {
  13. p = pprof.NewProfile("fds")
  14. }
  15. }
  16. type fd int
  17. func (me *fd) Closed() {
  18. p.Remove(me)
  19. }
  20. func add(skip int) (ret *fd) {
  21. ret = new(fd)
  22. p.Add(ret, skip+2)
  23. return
  24. }
  25. type closeWrapper struct {
  26. fd *fd
  27. c io.Closer
  28. }
  29. func (me closeWrapper) Close() error {
  30. me.fd.Closed()
  31. return me.c.Close()
  32. }
  33. func newCloseWrapper(c io.Closer) closeWrapper {
  34. return closeWrapper{
  35. fd: add(2),
  36. c: c,
  37. }
  38. }
  39. type wrappedNetConn struct {
  40. net.Conn
  41. closeWrapper
  42. }
  43. func (me wrappedNetConn) Close() error {
  44. return me.closeWrapper.Close()
  45. }
  46. // Tracks a net.Conn until Close() is explicitly called.
  47. func WrapNetConn(nc net.Conn) net.Conn {
  48. if !enabled {
  49. return nc
  50. }
  51. if nc == nil {
  52. return nil
  53. }
  54. return wrappedNetConn{
  55. nc,
  56. newCloseWrapper(nc),
  57. }
  58. }
  59. type OSFile interface {
  60. io.Reader
  61. io.Seeker
  62. io.Closer
  63. io.Writer
  64. Stat() (os.FileInfo, error)
  65. io.ReaderAt
  66. io.WriterAt
  67. }
  68. type wrappedOSFile struct {
  69. *os.File
  70. closeWrapper
  71. }
  72. func (me wrappedOSFile) Close() error {
  73. return me.closeWrapper.Close()
  74. }
  75. func WrapOSFile(f *os.File) OSFile {
  76. if !enabled {
  77. return f
  78. }
  79. return &wrappedOSFile{f, newCloseWrapper(f)}
  80. }