sys-proctable 0.8.0-sparc-solaris-2.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,453 @@
1
+ ########################################################################
2
+ # sunos.rb
3
+ #
4
+ # A pure Ruby version of sys-proctable for SunOS 5.8 or later.
5
+ ########################################################################
6
+
7
+ # The Sys module serves as a namespace only.
8
+ module Sys
9
+
10
+ # The ProcTable class encapsulates process table information.
11
+ class ProcTable
12
+ # There is no constructor
13
+ private_class_method :new
14
+
15
+ # The version of the sys-proctable library
16
+ VERSION = '0.8.0'
17
+
18
+ private
19
+
20
+ PRNODEV = -1 # non-existent device
21
+
22
+ @fields = [
23
+ :flag, # process flags (deprecated)
24
+ :nlwp, # number of active lwp's in the process
25
+ :pid, # unique process id
26
+ :ppid, # process id of parent
27
+ :pgid, # pid of session leader
28
+ :sid, # session id
29
+ :uid, # real user id
30
+ :euid, # effective user id
31
+ :gid, # real group id
32
+ :egid, # effective group id
33
+ :addr, # address of the process
34
+ :size, # size of process in kbytes
35
+ :rssize, # resident set size in kbytes
36
+ :ttydev, # tty device (or PRNODEV)
37
+ :pctcpu, # % of recent cpu used by all lwp's
38
+ :pctmem, # % of system memory used by process
39
+ :start, # absolute process start time
40
+ :time, # usr + sys cpu time for this process
41
+ :ctime, # usr + sys cpu time for reaped children
42
+ :fname, # name of the exec'd file
43
+ :psargs, # initial characters argument list - same as cmdline
44
+ :wstat, # if a zombie, the wait status
45
+ :argc, # initial argument count
46
+ :argv, # address of initial argument vector
47
+ :envp, # address of initial environment vector
48
+ :dmodel, # data model of the process
49
+ :taskid, # task id
50
+ :projid, # project id
51
+ :nzomb, # number of zombie lwp's in the process
52
+ :poolid, # pool id
53
+ :zoneid, # zone id
54
+ :contract, # process contract
55
+ :lwpid, # lwp id
56
+ :wchan, # wait address for sleeping lwp
57
+ :stype, # synchronization event type
58
+ :state, # numeric lwp state
59
+ :sname, # printable character for state
60
+ :nice, # nice for cpu usage
61
+ :syscall, # system call number (if in syscall)
62
+ :pri, # priority
63
+ :clname, # scheduling class name
64
+ :name, # name of system lwp
65
+ :onpro, # processor which last ran thsi lwp
66
+ :bindpro, # processor to which lwp is bound
67
+ :bindpset, # processor set to which lwp is bound
68
+ :count, # number of contributing lwp's
69
+ :tstamp, # current time stamp
70
+ :create, # process/lwp creation time stamp
71
+ :term, # process/lwp termination time stamp
72
+ :rtime, # total lwp real (elapsed) time
73
+ :utime, # user level cpu time
74
+ :stime, # system call cpu time
75
+ :ttime, # other system trap cpu time
76
+ :tftime, # text page fault sleep time
77
+ :dftime, # text page fault sleep time
78
+ :kftime, # kernel page fault sleep time
79
+ :ltime, # user lock wait sleep time
80
+ :slptime, # all other sleep time
81
+ :wtime, # wait-cpu (latency) time
82
+ :stoptime, # stopped time
83
+ :minf, # minor page faults
84
+ :majf, # major page faults
85
+ :nswap, # swaps
86
+ :inblk, # input blocks
87
+ :oublk, # output blocks
88
+ :msnd, # messages sent
89
+ :mrcv, # messages received
90
+ :sigs, # signals received
91
+ :vctx, # voluntary context switches
92
+ :ictx, # involuntary context switches
93
+ :sysc, # system calls
94
+ :ioch, # chars read and written
95
+ :path, # array of symbolic link paths from /proc/<pid>/pid
96
+ :contracts, # array symbolic link paths from /proc/<pid>/contracts
97
+ :fd, # array of used file descriptors
98
+ :cmd_args, # array of command line arguments
99
+ :environ, # hash of environment associated with the process,
100
+ :cmdline # joined cmd_args if present, otherwise psargs
101
+ ]
102
+
103
+ @psinfo_pack_directive = [
104
+ 'i', # pr_flag
105
+ 'i', # pr_nlwp
106
+ 'i', # pr_pid
107
+ 'i', # pr_ppid
108
+ 'i', # pr_pgid
109
+ 'i', # pr_sid
110
+ 'i', # pr_uid
111
+ 'i', # pr_euid
112
+ 'i', # pr_gid
113
+ 'i', # pr_egid
114
+ 'L', # pr_addr
115
+ 'L', # pr_size
116
+ 'L', # pr_rssize
117
+ 'L', # pr_pad1
118
+ 'i', # pr_ttydev
119
+ 'S', # pr_pctcpu
120
+ 'S', # pr_pctmem
121
+ 'LL', # pr_start
122
+ 'LL', # pr_time
123
+ 'LL', # pr_ctime
124
+ 'A16', # pr_gname[PRFNSZ]
125
+ 'A80', # pr_psargs[PRARGSZ]
126
+ 'i', # pr_wstat
127
+ 'i', # pr_argc
128
+ 'L', # pr_argv
129
+ 'L', # pr_envp
130
+ 'C', # pr_dmodel
131
+ 'A3', # pr_pad2[3]
132
+ 'i', # pr_taskid
133
+ 'i', # pr_projid
134
+ 'i', # pr_nzomb
135
+ 'i', # pr_poolid
136
+ 'i', # pr_zoneid
137
+ 'i', # pr_contract
138
+ 'i', # pr_filler
139
+ # --- LWPSINFO ---
140
+ 'i', # pr_flag
141
+ 'i', # pr_lwpid
142
+ 'L', # pr_addr
143
+ 'L', # pr_wchan
144
+ 'C', # pr_stype
145
+ 'C', # pr_state
146
+ 'A', # pr_sname
147
+ 'C', # pr_nice
148
+ 's', # pr_syscall
149
+ 'C', # pr_oldpri
150
+ 'C', # pr_cpu
151
+ 'i', # pr_pri
152
+ 'S', # pr_pctcpu
153
+ 'S', # pr_pad
154
+ 'LL', # pr_start
155
+ 'LL', # pr_time
156
+ 'A8', # pr_clname[PRCLSZ]
157
+ 'A16', # pr_name[PRFNSZ]
158
+ 'i', # pr_onpro
159
+ 'i', # pr_bindpro
160
+ 'i', # pr_bindpset
161
+ ].join
162
+
163
+ @prusage_pack_directive = [
164
+ 'i', # pr_lwpid
165
+ 'i', # pr_count
166
+ 'L2', # pr_tstamp
167
+ 'L2', # pr_create
168
+ 'L2', # pr_term
169
+ 'L2', # pr_rtime
170
+ 'L2', # pr_utime
171
+ 'L2', # pr_stime
172
+ 'L2', # pr_ttime
173
+ 'L2', # pr_tftime
174
+ 'L2', # pr_dftime
175
+ 'L2', # pr_kftime
176
+ 'L2', # pr_ltime
177
+ 'L2', # pr_slptime
178
+ 'L2', # pr_wtime
179
+ 'L2', # pr_stoptime
180
+ 'L12', # pr_filltime
181
+ 'L', # pr_minf
182
+ 'L', # pr_majf
183
+ 'L', # pr_nswap
184
+ 'L', # pr_inblk
185
+ 'L', # pr_oublk
186
+ 'L', # pr_msnd
187
+ 'L', # pr_mrcv
188
+ 'L', # pr_sigs
189
+ 'L', # pr_vctx
190
+ 'L', # pr_ictx
191
+ 'L', # pr_sysc
192
+ 'L', # pr_ioch
193
+ ].join
194
+
195
+ public
196
+
197
+ ProcTableStruct = Struct.new("ProcTableStruct", *@fields)
198
+
199
+ # In block form, yields a ProcTableStruct for each process entry that you
200
+ # have rights to. This method returns an array of ProcTableStruct's in
201
+ # non-block form.
202
+ #
203
+ # If a +pid+ is provided, then only a single ProcTableStruct is yielded or
204
+ # returned, or nil if no process information is found for that +pid+.
205
+ #
206
+ # Example:
207
+ #
208
+ # # Iterate over all processes
209
+ # ProcTable.ps do |proc_info|
210
+ # p proc_info
211
+ # end
212
+ #
213
+ # # Print process table information for only pid 1001
214
+ # p ProcTable.ps(1001)
215
+ #
216
+ def self.ps(pid = nil)
217
+ raise TypeError unless pid.is_a?(Fixnum) if pid
218
+
219
+ array = block_given? ? nil : []
220
+ struct = nil
221
+
222
+ Dir.foreach("/proc") do |file|
223
+ next if file =~ /\D/ # Skip non-numeric entries under /proc
224
+
225
+ # Only return information for a given pid, if provided
226
+ if pid
227
+ next unless file.to_i == pid
228
+ end
229
+
230
+ # Skip over any entries we don't have permissions to read
231
+ next unless File.readable?("/proc/#{file}/psinfo")
232
+
233
+ psinfo = IO.read("/proc/#{file}/psinfo")
234
+
235
+ psinfo_array = psinfo.unpack(@psinfo_pack_directive)
236
+
237
+ struct = ProcTableStruct.new
238
+
239
+ struct.flag = psinfo_array[0] # pr_flag
240
+ struct.nlwp = psinfo_array[1] # pr_nlwp
241
+ struct.pid = psinfo_array[2] # pr_pid
242
+ struct.ppid = psinfo_array[3] # pr_ppid
243
+ struct.pgid = psinfo_array[4] # pr_pgid
244
+ struct.sid = psinfo_array[5] # pr_sid
245
+ struct.uid = psinfo_array[6] # pr_uid
246
+ struct.euid = psinfo_array[7] # pr_euid
247
+ struct.gid = psinfo_array[8] # pr_gid
248
+ struct.egid = psinfo_array[9] # pr_egid
249
+ struct.addr = psinfo_array[10] # pr_addr
250
+ struct.size = psinfo_array[11] * 1024 # pr_size (in bytes)
251
+ struct.rssize = psinfo_array[12] * 1024 # pr_rssize (in bytes)
252
+
253
+ # skip pr_pad1
254
+
255
+ struct.ttydev = psinfo_array[14] # pr_ttydev
256
+ struct.pctcpu = (psinfo_array[15] * 100).to_f / 0x8000 # pr_pctcpu
257
+ struct.pctmem = (psinfo_array[16] * 100).to_f / 0x8000 # pr_pctmem
258
+
259
+ struct.start = Time.at(psinfo_array[17]) # pr_start (tv_sec)
260
+ struct.time = psinfo_array[19] # pr_time (tv_sec)
261
+ struct.ctime = psinfo_array[21] # pr_ctime (tv_sec)
262
+
263
+ struct.fname = psinfo_array[23] # pr_fname
264
+ struct.psargs = psinfo_array[24] # pr_psargs
265
+ struct.wstat = psinfo_array[25] # pr_wstat
266
+ struct.argc = psinfo_array[26] # pr_argc
267
+ struct.argv = psinfo_array[27] # pr_argv
268
+ struct.envp = psinfo_array[28] # pr_envp
269
+ struct.dmodel = psinfo_array[29] # pr_dmodel
270
+
271
+ # skip pr_pad2
272
+
273
+ struct.taskid = psinfo_array[31] # pr_taskid
274
+ struct.projid = psinfo_array[32] # pr_projid
275
+ struct.nzomb = psinfo_array[33] # pr_nzomb
276
+ struct.poolid = psinfo_array[34] # pr_poolid
277
+ struct.zoneid = psinfo_array[35] # pr_zoneid
278
+ struct.contract = psinfo_array[36] # pr_contract
279
+
280
+ # skip pr_filler
281
+
282
+ ### LWPSINFO struct info
283
+
284
+ # skip pr_flag
285
+
286
+ struct.lwpid = psinfo_array[39] # pr_lwpid
287
+
288
+ # skip pr_addr
289
+
290
+ struct.wchan = psinfo_array[41] # pr_wchan
291
+ struct.stype = psinfo_array[42] # pr_stype
292
+ struct.state = psinfo_array[43] # pr_state
293
+ struct.sname = psinfo_array[44] # pr_sname
294
+ struct.nice = psinfo_array[45] # pr_nice
295
+ struct.syscall = psinfo_array[46] # pr_syscall
296
+
297
+ # skip pr_oldpri
298
+ # skip pr_cpu
299
+
300
+ struct.pri = psinfo_array[49] # pr_pri
301
+
302
+ # skip pr_pctcpu
303
+ # skip pr_pad
304
+ # skip pr_start
305
+ # skip pr_time
306
+
307
+ struct.clname = psinfo_array[56] # pr_clname
308
+ struct.name = psinfo_array[57] # pr_name
309
+ struct.onpro = psinfo_array[58] # pr_onpro
310
+ struct.bindpro = psinfo_array[59] # pr_bindpro
311
+ struct.bindpset = psinfo_array[60] # pr_bindpset
312
+
313
+ # Get the full command line out of /proc/<pid>/as.
314
+ begin
315
+ File.open("/proc/#{file}/as") do |fd|
316
+ fd.sysseek(struct.argv, IO::SEEK_SET)
317
+ address = fd.sysread(struct.argc * 4).unpack("L")[0]
318
+
319
+ struct.cmd_args = []
320
+
321
+ 0.upto(struct.argc - 1){ |i|
322
+ fd.sysseek(address, IO::SEEK_SET)
323
+ data = fd.sysread(128)[/^[^\0]*/] # Null strip
324
+ struct.cmd_args << data
325
+ address += data.length + 1 # Add 1 for the space
326
+ }
327
+
328
+ # Get the environment hash associated with the process.
329
+ struct.environ = {}
330
+
331
+ fd.sysseek(struct.envp, IO::SEEK_SET)
332
+
333
+ env_address = fd.sysread(128).unpack("L")[0]
334
+
335
+ # TODO: Optimization potential here.
336
+ loop do
337
+ fd.sysseek(env_address, IO::SEEK_SET)
338
+ data = fd.sysread(1024)[/^[^\0]*/] # Null strip
339
+ break if data.empty?
340
+ key, value = data.split('=')
341
+ struct.environ[key] = value
342
+ env_address += data.length + 1 # Add 1 for the space
343
+ end
344
+ end
345
+ rescue Errno::EACCES, Errno::EOVERFLOW, EOFError
346
+ # Skip this if we don't have proper permissions, if there's
347
+ # no associated environment, or if there's a largefile issue.
348
+ end
349
+
350
+ ### struct prusage
351
+
352
+ begin
353
+ prusage = 0.chr * 512
354
+ prusage = IO.read("/proc/#{file}/usage")
355
+
356
+ prusage_array = prusage.unpack(@prusage_pack_directive)
357
+
358
+ # skip pr_lwpid
359
+ struct.count = prusage_array[1]
360
+ struct.tstamp = prusage_array[2]
361
+ struct.create = prusage_array[4]
362
+ struct.term = prusage_array[6]
363
+ struct.rtime = prusage_array[8]
364
+ struct.utime = prusage_array[10]
365
+ struct.stime = prusage_array[12]
366
+ struct.ttime = prusage_array[14]
367
+ struct.tftime = prusage_array[16]
368
+ struct.dftime = prusage_array[18]
369
+ struct.kftime = prusage_array[20]
370
+ struct.ltime = prusage_array[22]
371
+ struct.slptime = prusage_array[24]
372
+ struct.wtime = prusage_array[26]
373
+ struct.stoptime = prusage_array[28]
374
+ # skip filltime
375
+ struct.minf = prusage_array[42]
376
+ struct.majf = prusage_array[43]
377
+ struct.nswap = prusage_array[44]
378
+ struct.inblk = prusage_array[45]
379
+ struct.oublk = prusage_array[46]
380
+ struct.msnd = prusage_array[47]
381
+ struct.mrcv = prusage_array[48]
382
+ struct.sigs = prusage_array[49]
383
+ struct.vctx = prusage_array[50]
384
+ struct.ictx = prusage_array[51]
385
+ struct.sysc = prusage_array[52]
386
+ struct.ioch = prusage_array[53]
387
+ rescue Errno::EACCES
388
+ # Do nothing if we lack permissions. Just move on.
389
+ end
390
+
391
+ # Information from /proc/<pid>/path. This is represented as a hash,
392
+ # with the symbolic link name as the key, and the file it links to
393
+ # as the value, or nil if it cannot be found.
394
+ #--
395
+ # Note that cwd information can be gathered from here, too.
396
+ struct.path = {}
397
+
398
+ Dir["/proc/#{file}/path/*"].each{ |entry|
399
+ link = File.readlink(entry) rescue nil
400
+ struct.path[File.basename(entry)] = link
401
+ }
402
+
403
+ # Information from /proc/<pid>/contracts. This is represented as
404
+ # a hash, with the symbolic link name as the key, and the file
405
+ # it links to as the value.
406
+ struct.contracts = {}
407
+
408
+ Dir["/proc/#{file}/contracts/*"].each{ |entry|
409
+ link = File.readlink(entry) rescue nil
410
+ struct.contracts[File.basename(entry)] = link
411
+ }
412
+
413
+ # Information from /proc/<pid>/fd. This returns an array of
414
+ # numeric file descriptors used by the process.
415
+ struct.fd = Dir["/proc/#{file}/fd/*"].map{ |f| File.basename(f).to_i }
416
+
417
+ # Use the cmd_args as the cmdline if available. Otherwise use
418
+ # the psargs. This struct member is provided to provide a measure
419
+ # of consistency with the other platform implementations.
420
+ if struct.cmd_args && struct.cmd_args.length > 0
421
+ struct.cmdline = struct.cmd_args.join(' ')
422
+ else
423
+ struct.cmdline = struct.psargs
424
+ end
425
+
426
+ # This is read-only data
427
+ struct.freeze
428
+
429
+ if block_given?
430
+ yield struct
431
+ else
432
+ array << struct
433
+ end
434
+ end
435
+
436
+ pid ? struct : array
437
+ end
438
+
439
+ # Returns an array of fields that each ProcTableStruct will contain. This
440
+ # may be useful if you want to know in advance what fields are available
441
+ # without having to perform at least one read of the /proc table.
442
+ #
443
+ # Example:
444
+ #
445
+ # Sys::ProcTable.fields.each{ |field|
446
+ # puts "Field: #{field}"
447
+ # }
448
+ #
449
+ def self.fields
450
+ @fields.map{ |f| f.to_s }
451
+ end
452
+ end
453
+ end
data/lib/sys/top.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'sys/proctable'
2
+ require 'rbconfig'
3
+
4
+ # The Sys module serves as a namespace only
5
+ module Sys
6
+
7
+ # The Top class serves as a toplevel name for the 'top' method.
8
+ class Top
9
+
10
+ # The version of the sys-top library
11
+ VERSION = '1.0.2'
12
+
13
+ # Returns an array of Struct::ProcTableStruct elements containing up
14
+ # to +num+ elements, sorted by +field+. The default number of elements
15
+ # is 10, while the default field is 'pctcpu'.
16
+ #
17
+ # Exception: the default sort field is 'pid' on Linux and Windows.
18
+ #
19
+ def self.top(num=10, field='pctcpu')
20
+ field = field.to_s if field.is_a?(Symbol)
21
+
22
+ # Sort by pid on Windows by default
23
+ if Config::CONFIG['host_os'].match('mswin') && field == 'pctcpu'
24
+ field = 'pid'
25
+ end
26
+
27
+ # Linux does not have a pctcpu field yet
28
+ if Config::CONFIG['host_os'].match('linux') && field == 'pctcpu'
29
+ field = 'pid'
30
+ end
31
+
32
+ Sys::ProcTable.ps.sort_by{ |obj| obj.send(field) || '' }[0..num-1]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,80 @@
1
+ #######################################################################
2
+ # test_sys_proctable_all.rb
3
+ #
4
+ # Test suite for methods common to all platforms. Generally speaking
5
+ # you should run this test case using the 'rake test' task.
6
+ #######################################################################
7
+ require 'rubygems'
8
+ gem 'test-unit'
9
+
10
+ require 'test/unit'
11
+ require 'sys/proctable'
12
+ require 'rbconfig'
13
+ require 'test/test_sys_top'
14
+ include Sys
15
+
16
+ class TC_ProcTable_All < Test::Unit::TestCase
17
+ def self.startup
18
+ @@windows = Config::CONFIG['host_os'].match('mswin')
19
+ end
20
+
21
+ def setup
22
+ @pid = @@windows ? 0 : 1
23
+ end
24
+
25
+ def test_version
26
+ assert_equal('0.8.0', ProcTable::VERSION)
27
+ end
28
+
29
+ def test_fields
30
+ assert_respond_to(ProcTable, :fields)
31
+ assert_nothing_raised{ ProcTable.fields }
32
+ assert_kind_of(Array, ProcTable.fields)
33
+ assert_kind_of(String, ProcTable.fields.first)
34
+ end
35
+
36
+ def test_ps
37
+ assert_respond_to(ProcTable, :ps)
38
+ assert_nothing_raised{ ProcTable.ps }
39
+ assert_nothing_raised{ ProcTable.ps{} }
40
+ end
41
+
42
+ def test_ps_with_pid
43
+ assert_nothing_raised{ ProcTable.ps(0) }
44
+ end
45
+
46
+ def test_ps_with_explicit_nil
47
+ assert_nothing_raised{ ProcTable.ps(nil) }
48
+ assert_kind_of(Array, ProcTable.ps(nil))
49
+ end
50
+
51
+ def test_ps_return_value
52
+ assert_kind_of(Array, ProcTable.ps)
53
+ assert_kind_of(Struct::ProcTableStruct, ProcTable.ps(@pid))
54
+ assert_equal(nil, ProcTable.ps(999999999))
55
+ assert_equal(nil, ProcTable.ps(999999999){})
56
+ assert_equal(nil, ProcTable.ps{})
57
+ end
58
+
59
+ def test_ps_returned_struct_is_frozen
60
+ assert_true(ProcTable.ps.first.frozen?)
61
+ end
62
+
63
+ def test_ps_expected_errors
64
+ assert_raises(TypeError){ ProcTable.ps('vim') }
65
+ omit_if(@@windows, 'ArgumentError check skipped on MS Windows')
66
+ assert_raises(ArgumentError){ ProcTable.ps(0, 'localhost') }
67
+ end
68
+
69
+ def test_new_not_allowed
70
+ assert_raise(NoMethodError){ Sys::ProcTable.new }
71
+ end
72
+
73
+ def teardown
74
+ @pid = nil
75
+ end
76
+
77
+ def self.teardown
78
+ @@windows = nil
79
+ end
80
+ end