sys_windows.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. //go:build windows
  2. package sys
  3. import (
  4. "errors"
  5. "sync"
  6. "syscall"
  7. "unsafe"
  8. "github.com/shirou/gopsutil/v4/net"
  9. "golang.org/x/sys/windows"
  10. )
  11. var SIGUSR1 = syscall.Signal(0)
  12. // GetConnectionCount returns the number of active connections for the specified protocol ("tcp" or "udp").
  13. func GetConnectionCount(proto string) (int, error) {
  14. if proto != "tcp" && proto != "udp" {
  15. return 0, errors.New("invalid protocol")
  16. }
  17. stats, err := net.Connections(proto)
  18. if err != nil {
  19. return 0, err
  20. }
  21. return len(stats), nil
  22. }
  23. // GetTCPCount returns the number of active TCP connections.
  24. func GetTCPCount() (int, error) {
  25. return GetConnectionCount("tcp")
  26. }
  27. // GetUDPCount returns the number of active UDP connections.
  28. func GetUDPCount() (int, error) {
  29. return GetConnectionCount("udp")
  30. }
  31. // --- CPU Utilization (Windows native) ---
  32. var (
  33. // NewLazySystemDLL forces the load from %SystemRoot%\System32 so a
  34. // kernel32.dll planted next to the binary can't hijack the call.
  35. modKernel32 = windows.NewLazySystemDLL("kernel32.dll")
  36. procGetSystemTimes = modKernel32.NewProc("GetSystemTimes")
  37. cpuMu sync.Mutex
  38. lastIdle uint64
  39. lastKernel uint64
  40. lastUser uint64
  41. hasLast bool
  42. )
  43. func ftToUint64(ft windows.Filetime) uint64 {
  44. return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
  45. }
  46. // CPUPercentRaw returns instantaneous total CPU utilization across all
  47. // logical processors via Windows GetSystemTimes. The first call returns 0
  48. // while it initializes the baseline; subsequent calls compute deltas.
  49. func CPUPercentRaw() (float64, error) {
  50. var idleFT, kernelFT, userFT windows.Filetime
  51. r1, _, e1 := procGetSystemTimes.Call(
  52. uintptr(unsafe.Pointer(&idleFT)),
  53. uintptr(unsafe.Pointer(&kernelFT)),
  54. uintptr(unsafe.Pointer(&userFT)),
  55. )
  56. if r1 == 0 {
  57. var errno syscall.Errno
  58. if errors.As(e1, &errno) && errno != 0 {
  59. return 0, errno
  60. }
  61. return 0, errors.New("GetSystemTimes failed")
  62. }
  63. idle := ftToUint64(idleFT)
  64. kernel := ftToUint64(kernelFT)
  65. user := ftToUint64(userFT)
  66. cpuMu.Lock()
  67. defer cpuMu.Unlock()
  68. if !hasLast {
  69. lastIdle = idle
  70. lastKernel = kernel
  71. lastUser = user
  72. hasLast = true
  73. return 0, nil
  74. }
  75. idleDelta := idle - lastIdle
  76. kernelDelta := kernel - lastKernel
  77. userDelta := user - lastUser
  78. lastIdle = idle
  79. lastKernel = kernel
  80. lastUser = user
  81. total := kernelDelta + userDelta
  82. if total == 0 {
  83. return 0, nil
  84. }
  85. // kernel time includes idle on Windows; busy = total - idle
  86. busy := total - idleDelta
  87. pct := float64(busy) / float64(total) * 100.0
  88. if pct > 100 {
  89. pct = 100
  90. }
  91. return pct, nil
  92. }