sys-proctable 1.2.0 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -1
- data/{CHANGES → CHANGES.rdoc} +37 -0
- data/LICENSE +177 -0
- data/{MANIFEST → MANIFEST.rdoc} +3 -10
- data/README.md +158 -0
- data/Rakefile +1 -1
- data/benchmarks/bench_ips_ps.rb +63 -0
- data/lib/darwin/sys/proctable.rb +78 -35
- data/lib/linux/sys/proctable.rb +106 -97
- data/lib/sys/proctable/version.rb +1 -1
- data/spec/spec_helper.rb +22 -0
- data/spec/sys_proctable_all_spec.rb +2 -1
- data/spec/sys_proctable_darwin_spec.rb +5 -5
- data/spec/sys_proctable_linux_spec.rb +38 -9
- data/sys-proctable.gemspec +16 -6
- metadata +41 -34
- metadata.gz.sig +0 -0
- data/README +0 -120
- data/doc/top.txt +0 -47
data/lib/darwin/sys/proctable.rb
CHANGED
@@ -26,6 +26,11 @@ module Sys
|
|
26
26
|
MAXTHREADNAMESIZE = 64
|
27
27
|
PROC_PIDPATHINFO_MAXSIZE = MAXPATHLEN * 4
|
28
28
|
|
29
|
+
# JRuby on Mac
|
30
|
+
unless defined? FFI::StructLayout::CharArray
|
31
|
+
FFI::StructLayout::CharArray = FFI::StructLayout::CharArrayProxy
|
32
|
+
end
|
33
|
+
|
29
34
|
class ProcBsdInfo < FFI::Struct
|
30
35
|
layout(
|
31
36
|
:pbi_flags, :uint32_t,
|
@@ -174,66 +179,98 @@ module Sys
|
|
174
179
|
#
|
175
180
|
def self.ps(**kwargs)
|
176
181
|
pid = kwargs[:pid]
|
177
|
-
|
178
|
-
|
179
|
-
num = proc_listallpids(nil, 0)
|
180
|
-
ptr = FFI::MemoryPointer.new(:pid_t, num)
|
181
|
-
num = proc_listallpids(ptr, ptr.size)
|
182
|
-
|
183
|
-
raise SystemCallError.new('proc_listallpids', FFI.errno) if num == 0
|
184
|
-
|
185
|
-
pids = ptr.get_array_of_int32(0, num).sort
|
186
|
-
array = block_given? ? nil : []
|
182
|
+
thread_info = kwargs[:thread_info]
|
187
183
|
|
188
|
-
|
189
|
-
|
184
|
+
if pid
|
185
|
+
raise TypeError unless pid.is_a?(Numeric)
|
190
186
|
info = ProcTaskAllInfo.new
|
191
187
|
|
192
|
-
nb = proc_pidinfo(
|
188
|
+
nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, info, info.size)
|
193
189
|
|
194
190
|
if nb <= 0
|
195
191
|
if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno)
|
196
|
-
|
192
|
+
return # Either we don't have permission, or the pid no longer exists
|
197
193
|
else
|
198
194
|
raise SystemCallError.new('proc_pidinfo', FFI.errno)
|
199
195
|
end
|
200
196
|
end
|
201
197
|
|
202
|
-
|
203
|
-
next if nb != info.size
|
198
|
+
return nil if nb != info.size # Invalid data
|
204
199
|
|
205
200
|
struct = ProcTableStruct.new
|
206
201
|
|
207
202
|
# Pass by reference
|
208
|
-
get_cmd_args_and_env(
|
209
|
-
get_thread_info(
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
203
|
+
get_cmd_args_and_env(pid, struct)
|
204
|
+
get_thread_info(pid, struct, info[:ptinfo]) unless thread_info == false
|
205
|
+
apply_info_to_struct(info, struct)
|
206
|
+
|
207
|
+
struct.freeze
|
208
|
+
yield struct if block_given?
|
209
|
+
struct
|
210
|
+
else
|
211
|
+
num = proc_listallpids(nil, 0)
|
212
|
+
ptr = FFI::MemoryPointer.new(:pid_t, num)
|
213
|
+
num = proc_listallpids(ptr, ptr.size)
|
214
|
+
|
215
|
+
raise SystemCallError.new('proc_listallpids', FFI.errno) if num == 0
|
216
|
+
|
217
|
+
pids = ptr.get_array_of_int32(0, num).sort
|
218
|
+
array = block_given? ? nil : []
|
219
|
+
|
220
|
+
pids.each do |lpid|
|
221
|
+
next unless pid == lpid if pid
|
222
|
+
info = ProcTaskAllInfo.new
|
223
|
+
|
224
|
+
nb = proc_pidinfo(lpid, PROC_PIDTASKALLINFO, 0, info, info.size)
|
225
|
+
|
226
|
+
if nb <= 0
|
227
|
+
if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno)
|
228
|
+
next # Either we don't have permission, or the pid no longer exists
|
216
229
|
else
|
217
|
-
|
230
|
+
raise SystemCallError.new('proc_pidinfo', FFI.errno)
|
218
231
|
end
|
219
232
|
end
|
220
|
-
end
|
221
233
|
|
222
|
-
|
234
|
+
# Avoid potentially invalid data
|
235
|
+
next if nb != info.size
|
223
236
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
237
|
+
struct = ProcTableStruct.new
|
238
|
+
|
239
|
+
# Pass by reference
|
240
|
+
get_cmd_args_and_env(lpid, struct)
|
241
|
+
get_thread_info(lpid, struct, info[:ptinfo]) unless thread_info == false
|
242
|
+
apply_info_to_struct(info, struct)
|
243
|
+
|
244
|
+
struct.freeze
|
245
|
+
|
246
|
+
if block_given?
|
247
|
+
yield struct
|
248
|
+
else
|
249
|
+
array << struct
|
250
|
+
end
|
228
251
|
end
|
229
|
-
end
|
230
252
|
|
231
|
-
|
232
|
-
|
253
|
+
array
|
254
|
+
end
|
233
255
|
end
|
234
256
|
|
235
257
|
private
|
236
258
|
|
259
|
+
# Pass by reference method that updates the Ruby struct based on the FFI struct.
|
260
|
+
#
|
261
|
+
def self.apply_info_to_struct(info, struct)
|
262
|
+
# Chop the leading xx_ from the FFI struct members for our ruby struct.
|
263
|
+
info.members.each do |nested|
|
264
|
+
info[nested].members.each do |member|
|
265
|
+
if info[nested][member].is_a?(FFI::StructLayout::CharArray)
|
266
|
+
struct[PROC_STRUCT_FIELD_MAP[member]] = info[nested][member].to_s
|
267
|
+
else
|
268
|
+
struct[PROC_STRUCT_FIELD_MAP[member]] = info[nested][member]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
237
274
|
# Returns an array of ThreadInfo objects for the given pid.
|
238
275
|
#
|
239
276
|
def self.get_thread_info(pid, struct, ptinfo)
|
@@ -253,7 +290,13 @@ module Sys
|
|
253
290
|
|
254
291
|
0.upto(max-1) do |index|
|
255
292
|
tinfo = ProcThreadInfo.new
|
256
|
-
|
293
|
+
|
294
|
+
# Use read_array_of_uint64 for compatibility with JRuby if necessary.
|
295
|
+
if buf[index].respond_to?(:read_uint64)
|
296
|
+
nb = proc_pidinfo(pid, PROC_PIDTHREADINFO, buf[index].read_uint64, tinfo, tinfo.size)
|
297
|
+
else
|
298
|
+
nb = proc_pidinfo(pid, PROC_PIDTHREADINFO, buf[index].read_array_of_uint64(1).first, tinfo, tinfo.size)
|
299
|
+
end
|
257
300
|
|
258
301
|
if nb <= 0
|
259
302
|
if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno)
|
data/lib/linux/sys/proctable.rb
CHANGED
@@ -20,62 +20,67 @@ module Sys
|
|
20
20
|
@boot_time = IO.read("/proc/stat")[/btime.*/].split.last.to_i rescue nil
|
21
21
|
|
22
22
|
@fields = [
|
23
|
-
'cmdline',
|
24
|
-
'cwd',
|
25
|
-
'environ',
|
26
|
-
'exe',
|
27
|
-
'fd',
|
28
|
-
'root',
|
29
|
-
'pid',
|
30
|
-
'comm',
|
31
|
-
'state',
|
32
|
-
'ppid',
|
33
|
-
'pgrp',
|
34
|
-
'session',
|
35
|
-
'tty_nr',
|
36
|
-
'tpgid',
|
37
|
-
'flags',
|
38
|
-
'minflt',
|
39
|
-
'cminflt',
|
40
|
-
'majflt',
|
41
|
-
'cmajflt',
|
42
|
-
'utime',
|
43
|
-
'stime',
|
44
|
-
'cutime',
|
45
|
-
'cstime',
|
46
|
-
'priority',
|
47
|
-
'nice',
|
48
|
-
'
|
49
|
-
'
|
50
|
-
'
|
51
|
-
'
|
52
|
-
'
|
53
|
-
'
|
54
|
-
'
|
55
|
-
'
|
56
|
-
'
|
57
|
-
'
|
58
|
-
'
|
59
|
-
'
|
60
|
-
'
|
61
|
-
'
|
62
|
-
'
|
63
|
-
'
|
64
|
-
'
|
65
|
-
'
|
66
|
-
'
|
67
|
-
'
|
68
|
-
'
|
69
|
-
'
|
70
|
-
'
|
71
|
-
'
|
72
|
-
'
|
73
|
-
'
|
74
|
-
'
|
75
|
-
'
|
76
|
-
'
|
77
|
-
'
|
78
|
-
'
|
23
|
+
'cmdline', # Complete command line
|
24
|
+
'cwd', # Current working directory
|
25
|
+
'environ', # Environment
|
26
|
+
'exe', # Actual pathname of the executed command
|
27
|
+
'fd', # File descriptors open by process
|
28
|
+
'root', # Root directory of process
|
29
|
+
'pid', # Process ID
|
30
|
+
'comm', # Filename of executable
|
31
|
+
'state', # Single character state abbreviation
|
32
|
+
'ppid', # Parent process ID
|
33
|
+
'pgrp', # Process group
|
34
|
+
'session', # Session ID
|
35
|
+
'tty_nr', # TTY (terminal) associated with the process
|
36
|
+
'tpgid', # Group ID of the TTY
|
37
|
+
'flags', # Kernel flags
|
38
|
+
'minflt', # Number of minor faults
|
39
|
+
'cminflt', # Number of minor faults of waited-for children
|
40
|
+
'majflt', # Number of major faults
|
41
|
+
'cmajflt', # Number of major faults of waited-for children
|
42
|
+
'utime', # Number of user mode jiffies
|
43
|
+
'stime', # Number of kernel mode jiffies
|
44
|
+
'cutime', # Number of children's user mode jiffies
|
45
|
+
'cstime', # Number of children's kernel mode jiffies
|
46
|
+
'priority', # Nice value plus 15
|
47
|
+
'nice', # Nice value
|
48
|
+
'num_threads', # Number of threads in this process
|
49
|
+
'itrealvalue', # Time in jiffies before next SIGALRM
|
50
|
+
'starttime', # Time in jiffies since system boot
|
51
|
+
'vsize', # Virtual memory size in bytes
|
52
|
+
'rss', # Resident set size
|
53
|
+
'rlim', # Current limit on the rss in bytes (old)
|
54
|
+
'rsslim', # Current limit on the rss in bytes (current)
|
55
|
+
'startcode', # Address above which program text can run
|
56
|
+
'endcode', # Address below which program text can run
|
57
|
+
'startstack', # Address of the startstack
|
58
|
+
'kstkesp', # Kernel stack page address
|
59
|
+
'kstkeip', # Kernel instruction pointer
|
60
|
+
'signal', # Bitmap of pending signals
|
61
|
+
'blocked', # Bitmap of blocked signals
|
62
|
+
'sigignore', # Bitmap of ignored signals
|
63
|
+
'sigcatch', # Bitmap of caught signals
|
64
|
+
'wchan', # Channel in which the process is waiting
|
65
|
+
'nswap', # Number of pages swapped
|
66
|
+
'cnswap', # Cumulative nswap for child processes
|
67
|
+
'exit_signal', # Signal to be sent to parent when process dies
|
68
|
+
'processor', # CPU number last executed on
|
69
|
+
'rt_priority', # Real time scheduling priority
|
70
|
+
'policy', # Scheduling policy
|
71
|
+
'delayacct_blkio_ticks', # Aggregated block I/O delays
|
72
|
+
'guest_time', # Guest time of the process
|
73
|
+
'cguest_time', # Guest time of the process's children
|
74
|
+
'name', # Process name
|
75
|
+
'uid', # Real user ID
|
76
|
+
'euid', # Effective user ID
|
77
|
+
'gid', # Real group ID
|
78
|
+
'egid', # Effective group ID
|
79
|
+
'pctcpu', # Percent of CPU usage (custom field)
|
80
|
+
'pctmem', # Percent of Memory usage (custom field)
|
81
|
+
'nlwp', # Number of Light-Weight Processes associated with the process (threads)
|
82
|
+
'cgroup', # Control groups to which the process belongs
|
83
|
+
'smaps' # Process memory size for all mapped files
|
79
84
|
]
|
80
85
|
|
81
86
|
public
|
@@ -197,47 +202,51 @@ module Sys
|
|
197
202
|
|
198
203
|
stat = stat.split
|
199
204
|
|
200
|
-
struct.pid
|
201
|
-
struct.comm
|
202
|
-
struct.state
|
203
|
-
struct.ppid
|
204
|
-
struct.pgrp
|
205
|
-
struct.session
|
206
|
-
struct.tty_nr
|
207
|
-
struct.tpgid
|
208
|
-
struct.flags
|
209
|
-
struct.minflt
|
210
|
-
struct.cminflt
|
211
|
-
struct.majflt
|
212
|
-
struct.cmajflt
|
213
|
-
struct.utime
|
214
|
-
struct.stime
|
215
|
-
struct.cutime
|
216
|
-
struct.cstime
|
217
|
-
struct.priority
|
218
|
-
struct.nice
|
219
|
-
|
220
|
-
struct.itrealvalue
|
221
|
-
struct.starttime
|
222
|
-
struct.vsize
|
223
|
-
struct.rss
|
224
|
-
struct.rlim
|
225
|
-
struct.
|
226
|
-
struct.
|
227
|
-
struct.
|
228
|
-
struct.
|
229
|
-
struct.
|
230
|
-
struct.
|
231
|
-
struct.
|
232
|
-
struct.
|
233
|
-
struct.
|
234
|
-
struct.
|
235
|
-
struct.
|
236
|
-
struct.
|
237
|
-
struct.
|
238
|
-
struct.
|
239
|
-
struct.
|
240
|
-
struct.
|
205
|
+
struct.pid = stat[0].to_i
|
206
|
+
struct.comm = stat[1].tr('()','') # Remove parens
|
207
|
+
struct.state = stat[2]
|
208
|
+
struct.ppid = stat[3].to_i
|
209
|
+
struct.pgrp = stat[4].to_i
|
210
|
+
struct.session = stat[5].to_i
|
211
|
+
struct.tty_nr = stat[6].to_i
|
212
|
+
struct.tpgid = stat[7].to_i
|
213
|
+
struct.flags = stat[8].to_i
|
214
|
+
struct.minflt = stat[9].to_i
|
215
|
+
struct.cminflt = stat[10].to_i
|
216
|
+
struct.majflt = stat[11].to_i
|
217
|
+
struct.cmajflt = stat[12].to_i
|
218
|
+
struct.utime = stat[13].to_i
|
219
|
+
struct.stime = stat[14].to_i
|
220
|
+
struct.cutime = stat[15].to_i
|
221
|
+
struct.cstime = stat[16].to_i
|
222
|
+
struct.priority = stat[17].to_i
|
223
|
+
struct.nice = stat[18].to_i
|
224
|
+
struct.num_threads = stat[19].to_i
|
225
|
+
struct.itrealvalue = stat[20].to_i
|
226
|
+
struct.starttime = stat[21].to_i
|
227
|
+
struct.vsize = stat[22].to_i
|
228
|
+
struct.rss = stat[23].to_i
|
229
|
+
struct.rlim = stat[24].to_i # Old name for backwards compatibility
|
230
|
+
struct.rsslim = stat[24].to_i
|
231
|
+
struct.startcode = stat[25].to_i
|
232
|
+
struct.endcode = stat[26].to_i
|
233
|
+
struct.startstack = stat[27].to_i
|
234
|
+
struct.kstkesp = stat[28].to_i
|
235
|
+
struct.kstkeip = stat[29].to_i
|
236
|
+
struct.signal = stat[30].to_i
|
237
|
+
struct.blocked = stat[31].to_i
|
238
|
+
struct.sigignore = stat[32].to_i
|
239
|
+
struct.sigcatch = stat[33].to_i
|
240
|
+
struct.wchan = stat[34].to_i
|
241
|
+
struct.nswap = stat[35].to_i
|
242
|
+
struct.cnswap = stat[36].to_i
|
243
|
+
struct.exit_signal = stat[37].to_i
|
244
|
+
struct.processor = stat[38].to_i
|
245
|
+
struct.rt_priority = stat[39].to_i
|
246
|
+
struct.policy = stat[40].to_i
|
247
|
+
struct.delayacct_blkio_ticks = stat[41].to_i
|
248
|
+
struct.guest_time = stat[42].to_i
|
249
|
+
struct.cguest_time = stat[43].to_i
|
241
250
|
|
242
251
|
# Get /proc/<pid>/status information (name, uid, euid, gid, egid)
|
243
252
|
begin
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.filter_run_excluding :skip_jruby if RUBY_PLATFORM == 'java'
|
3
|
+
end
|
4
|
+
|
5
|
+
if RUBY_PLATFORM == 'java'
|
6
|
+
require 'ffi'
|
7
|
+
module Exec
|
8
|
+
extend FFI::Library
|
9
|
+
ffi_lib FFI::Library::LIBC
|
10
|
+
attach_function :fork, [], :int
|
11
|
+
end
|
12
|
+
|
13
|
+
def fork
|
14
|
+
pid = Exec.fork
|
15
|
+
if pid == 0
|
16
|
+
yield if block_given?
|
17
|
+
return nil
|
18
|
+
else
|
19
|
+
return pid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -16,7 +16,8 @@ describe Sys::ProcTable do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "has a VERSION constant set to the expected value" do
|
19
|
-
expect(Sys::ProcTable::VERSION).to eql('1.2.
|
19
|
+
expect(Sys::ProcTable::VERSION).to eql('1.2.5')
|
20
|
+
expect(Sys::ProcTable::VERSION).to be_frozen
|
20
21
|
end
|
21
22
|
|
22
23
|
it "defines a custom error class" do
|
@@ -87,30 +87,30 @@ describe Sys::ProcTable do
|
|
87
87
|
expect(subject.svgid).to eql(Process.gid)
|
88
88
|
end
|
89
89
|
|
90
|
-
it "contains a comm member and returns the expected value" do
|
90
|
+
it "contains a comm member and returns the expected value", :skip_jruby do
|
91
91
|
expect(subject).to respond_to(:comm)
|
92
92
|
expect(subject.comm).to be_kind_of(String)
|
93
93
|
expect(subject.comm).to eql('sleep')
|
94
94
|
end
|
95
95
|
|
96
|
-
it "contains a cmdline member and returns the expected value" do
|
96
|
+
it "contains a cmdline member and returns the expected value", :skip_jruby do
|
97
97
|
expect(subject).to respond_to(:cmdline)
|
98
98
|
expect(subject.cmdline).to be_kind_of(String)
|
99
99
|
expect(subject.cmdline).to eql('sleep 60')
|
100
100
|
end
|
101
101
|
|
102
|
-
it "returns a string with the expected arguments for the cmdline member" do
|
102
|
+
it "returns a string with the expected arguments for the cmdline member", :skip_jruby do
|
103
103
|
ptable = Sys::ProcTable.ps(pid: @pid2)
|
104
104
|
expect(ptable.cmdline).to eql('ruby -Ilib -e sleep \'120\'.to_i -- foo bar')
|
105
105
|
end
|
106
106
|
|
107
|
-
it "contains an exe member and returns the expected value" do
|
107
|
+
it "contains an exe member and returns the expected value", :skip_jruby do
|
108
108
|
expect(subject).to respond_to(:exe)
|
109
109
|
expect(subject.exe).to be_kind_of(String)
|
110
110
|
expect(subject.exe).to eql(`which sleep`.chomp)
|
111
111
|
end
|
112
112
|
|
113
|
-
it "contains an environ member and returns the expected value" do
|
113
|
+
it "contains an environ member and returns the expected value", :skip_jruby do
|
114
114
|
expect(subject).to respond_to(:environ)
|
115
115
|
expect(subject.environ).to be_kind_of(Hash)
|
116
116
|
expect(subject.environ['A']).to eql('B')
|