sys_windows.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //go:build windows
  2. // +build windows
  3. package sys
  4. import (
  5. "errors"
  6. "sync"
  7. "syscall"
  8. "unsafe"
  9. "github.com/shirou/gopsutil/v4/net"
  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. modKernel32 = syscall.NewLazyDLL("kernel32.dll")
  34. procGetSystemTimes = modKernel32.NewProc("GetSystemTimes")
  35. cpuMu sync.Mutex
  36. lastIdle uint64
  37. lastKernel uint64
  38. lastUser uint64
  39. hasLast bool
  40. )
  41. type filetime struct {
  42. LowDateTime uint32
  43. HighDateTime uint32
  44. }
  45. // ftToUint64 converts a Windows FILETIME-like struct to a uint64 for
  46. // arithmetic and delta calculations used by CPUPercentRaw.
  47. func ftToUint64(ft filetime) uint64 {
  48. return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
  49. }
  50. // CPUPercentRaw returns the instantaneous total CPU utilization percentage using
  51. // Windows GetSystemTimes across all logical processors. The first call returns 0
  52. // as it initializes the baseline. Subsequent calls compute deltas.
  53. func CPUPercentRaw() (float64, error) {
  54. var idleFT, kernelFT, userFT filetime
  55. r1, _, e1 := procGetSystemTimes.Call(
  56. uintptr(unsafe.Pointer(&idleFT)),
  57. uintptr(unsafe.Pointer(&kernelFT)),
  58. uintptr(unsafe.Pointer(&userFT)),
  59. )
  60. if r1 == 0 { // failure
  61. if e1 != nil {
  62. return 0, e1
  63. }
  64. return 0, syscall.GetLastError()
  65. }
  66. idle := ftToUint64(idleFT)
  67. kernel := ftToUint64(kernelFT)
  68. user := ftToUint64(userFT)
  69. cpuMu.Lock()
  70. defer cpuMu.Unlock()
  71. if !hasLast {
  72. lastIdle = idle
  73. lastKernel = kernel
  74. lastUser = user
  75. hasLast = true
  76. return 0, nil
  77. }
  78. idleDelta := idle - lastIdle
  79. kernelDelta := kernel - lastKernel
  80. userDelta := user - lastUser
  81. // Update for next call
  82. lastIdle = idle
  83. lastKernel = kernel
  84. lastUser = user
  85. total := kernelDelta + userDelta
  86. if total == 0 {
  87. return 0, nil
  88. }
  89. // On Windows, kernel time includes idle time; busy = total - idle
  90. busy := total - idleDelta
  91. pct := float64(busy) / float64(total) * 100.0
  92. // lower bound not needed; ratios of uint64 are non-negative
  93. if pct > 100 {
  94. pct = 100
  95. }
  96. return pct, nil
  97. }