99 "encoding/binary"
1010 "os"
1111 "strings"
12+ "sync"
1213
1314 "github.com/shirou/gopsutil/v4/internal/common"
1415)
@@ -29,14 +30,39 @@ func getInvoker() common.Invoker {
2930 return invoke
3031}
3132
32- func HostIDWithContext (ctx context.Context ) (string , error ) {
33- out , err := getInvoker ().CommandWithContext (ctx , "uname" , "-u" )
34- if err != nil {
35- return "" , err
36- }
33+ // Static host information is cached because these values (hardware ID,
34+ // platform name, OS version, kernel version, architecture) do not change
35+ // at runtime. Caching avoids spawning subprocesses on repeated queries.
36+ var (
37+ hostIDOnce sync.Once
38+ hostIDVal string
39+ hostIDErr error
40+
41+ platformOnce sync.Once
42+ platformVal string
43+ familyVal string
44+ versionVal string
45+ platformErr error
46+
47+ kernelVerOnce sync.Once
48+ kernelVerVal string
49+ kernelVerErr error
50+
51+ kernelArchOnce sync.Once
52+ kernelArchVal string
53+ kernelArchErr error
54+ )
3755
38- // The command always returns an extra newline, so we make use of Split() to get only the first line
39- return strings .Split (string (out ), "\n " )[0 ], nil
56+ func HostIDWithContext (ctx context.Context ) (string , error ) {
57+ hostIDOnce .Do (func () {
58+ out , err := getInvoker ().CommandWithContext (ctx , "uname" , "-u" )
59+ if err != nil {
60+ hostIDErr = err
61+ return
62+ }
63+ hostIDVal = strings .Split (string (out ), "\n " )[0 ]
64+ })
65+ return hostIDVal , hostIDErr
4066}
4167
4268func BootTimeWithContext (ctx context.Context ) (btime uint64 , err error ) {
@@ -104,46 +130,54 @@ func UsersWithContext(_ context.Context) ([]UserStat, error) {
104130 return ret , nil
105131}
106132
107- // Much of this function could be static. However, to be future proofed, I've made it call the OS for the information in all instances.
133+ // PlatformInformationWithContext returns the platform name, family, and OS
134+ // version. These are immutable system identifiers cached after first query.
108135func PlatformInformationWithContext (ctx context.Context ) (platform , family , version string , err error ) {
109- // Set the platform (which should always, and only be, "AIX") from `uname -s`
110- out , err := getInvoker ().CommandWithContext (ctx , "uname" , "-s" )
111- if err != nil {
112- return "" , "" , "" , err
113- }
114- platform = strings .TrimRight (string (out ), "\n " )
115-
116- // Set the family
117- family = strings .TrimRight (string (out ), "\n " )
118-
119- // Set the version
120- out , err = getInvoker ().CommandWithContext (ctx , "oslevel" )
121- if err != nil {
122- return "" , "" , "" , err
123- }
124- version = strings .TrimRight (string (out ), "\n " )
136+ platformOnce .Do (func () {
137+ out , err := getInvoker ().CommandWithContext (ctx , "uname" , "-s" )
138+ if err != nil {
139+ platformErr = err
140+ return
141+ }
142+ platformVal = strings .TrimRight (string (out ), "\n " )
143+ familyVal = platformVal
125144
126- return platform , family , version , nil
145+ out , err = getInvoker ().CommandWithContext (ctx , "oslevel" )
146+ if err != nil {
147+ platformErr = err
148+ return
149+ }
150+ versionVal = strings .TrimRight (string (out ), "\n " )
151+ })
152+ return platformVal , familyVal , versionVal , platformErr
127153}
128154
155+ // KernelVersionWithContext returns the kernel version (e.g., "7300-03-00-2446").
156+ // This is an immutable system identifier cached after first query.
129157func KernelVersionWithContext (ctx context.Context ) (version string , err error ) {
130- out , err := getInvoker ().CommandWithContext (ctx , "oslevel" , "-s" )
131- if err != nil {
132- return "" , err
133- }
134- version = strings .TrimRight (string (out ), "\n " )
135-
136- return version , nil
158+ kernelVerOnce .Do (func () {
159+ out , err := getInvoker ().CommandWithContext (ctx , "oslevel" , "-s" )
160+ if err != nil {
161+ kernelVerErr = err
162+ return
163+ }
164+ kernelVerVal = strings .TrimRight (string (out ), "\n " )
165+ })
166+ return kernelVerVal , kernelVerErr
137167}
138168
169+ // KernelArch returns the hardware architecture (e.g., "64").
170+ // This is an immutable system identifier cached after first query.
139171func KernelArch () (arch string , err error ) {
140- out , err := getInvoker ().Command ("bootinfo" , "-y" )
141- if err != nil {
142- return "" , err
143- }
144- arch = strings .TrimRight (string (out ), "\n " )
145-
146- return arch , nil
172+ kernelArchOnce .Do (func () {
173+ out , err := getInvoker ().Command ("bootinfo" , "-y" )
174+ if err != nil {
175+ kernelArchErr = err
176+ return
177+ }
178+ kernelArchVal = strings .TrimRight (string (out ), "\n " )
179+ })
180+ return kernelArchVal , kernelArchErr
147181}
148182
149183func VirtualizationWithContext (ctx context.Context ) (string , string , error ) {
0 commit comments