win32-job 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +5 -2
- data/MANIFEST +12 -12
- data/README +5 -6
- data/Rakefile +31 -31
- data/examples/example_job.rb +29 -29
- data/lib/win32/job.rb +8 -28
- data/lib/win32/job/constants.rb +64 -64
- data/lib/win32/job/helper.rb +26 -26
- data/lib/win32/job/structs.rb +175 -175
- data/test/test_win32_job.rb +130 -126
- data/win32-job.gemspec +28 -28
- metadata +9 -9
- data/win32-job-0.1.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b05ef073cbab8e2e228f1bbe4dc4691d42d7e161
|
4
|
+
data.tar.gz: e8b44cab6624612b066f785e9895851384c3e963
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad0a9b6601e876eb373e710fa900d2033ff45e2ab06a5dc1f18438ecf2dd9a71fff549e4eeb621a1c8c82d23bbed258d9c5aba8845d2732187e0f8604055dfe1
|
7
|
+
data.tar.gz: 977ff9aadaa433efa20a15637f51bdf13c2b2e72aea844543cf9a5aed99d43c2343d6a52145d7a883830be18729db76d86a7ed31c791dcdfa69ba826f9c05e09
|
data/CHANGES
CHANGED
data/MANIFEST
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
* CHANGES
|
2
|
-
* MANIFEST
|
3
|
-
* Rakefile
|
4
|
-
* README
|
5
|
-
* win32-job.gemspec
|
6
|
-
* examples\example_job.rb
|
7
|
-
* lib\win32\job.rb
|
8
|
-
* lib\win32\job\constants.rb
|
9
|
-
* lib\win32\job\functions.rb
|
10
|
-
* lib\win32\job\helper.rb
|
11
|
-
* lib\win32\job\structs.rb
|
12
|
-
* test\test_win32_job.rb
|
1
|
+
* CHANGES
|
2
|
+
* MANIFEST
|
3
|
+
* Rakefile
|
4
|
+
* README
|
5
|
+
* win32-job.gemspec
|
6
|
+
* examples\example_job.rb
|
7
|
+
* lib\win32\job.rb
|
8
|
+
* lib\win32\job\constants.rb
|
9
|
+
* lib\win32\job\functions.rb
|
10
|
+
* lib\win32\job\helper.rb
|
11
|
+
* lib\win32\job\structs.rb
|
12
|
+
* test\test_win32_job.rb
|
data/README
CHANGED
@@ -5,7 +5,8 @@
|
|
5
5
|
gem install win32-job
|
6
6
|
|
7
7
|
== Prerequisites
|
8
|
-
ffi
|
8
|
+
* ffi
|
9
|
+
* Ruby 1.9.3 or later
|
9
10
|
|
10
11
|
== Synopsis
|
11
12
|
require 'win32/job'
|
@@ -25,9 +26,6 @@
|
|
25
26
|
|
26
27
|
job.close
|
27
28
|
|
28
|
-
== Future Plans
|
29
|
-
Add a wait method that waits for all processes to complete.
|
30
|
-
|
31
29
|
== Known Issues
|
32
30
|
None known.
|
33
31
|
|
@@ -38,7 +36,7 @@
|
|
38
36
|
Artistic 2.0
|
39
37
|
|
40
38
|
== Copyright
|
41
|
-
(C) 2003-
|
39
|
+
(C) 2003-2014 Daniel J. Berger
|
42
40
|
All Rights Reserved
|
43
41
|
|
44
42
|
== Warranty
|
@@ -46,5 +44,6 @@
|
|
46
44
|
implied warranties, including, without limitation, the implied
|
47
45
|
warranties of merchantability and fitness for a particular purpose.
|
48
46
|
|
49
|
-
==
|
47
|
+
== Authors
|
50
48
|
Daniel J. Berger
|
49
|
+
Park Heesob
|
data/Rakefile
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/clean'
|
3
|
-
require 'rake/testtask'
|
4
|
-
|
5
|
-
CLEAN.include("**/*.gem", "**/*.rbc", "**/*.rbx")
|
6
|
-
|
7
|
-
namespace :gem do
|
8
|
-
desc 'Create the win32-job gem'
|
9
|
-
task :create do
|
10
|
-
spec = eval(IO.read('win32-job.gemspec'))
|
11
|
-
if Gem::VERSION < "2.0"
|
12
|
-
Gem::Builder.new(spec).build
|
13
|
-
else
|
14
|
-
require 'rubygems/package'
|
15
|
-
Gem::Package.build(spec)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
desc 'Install the win32-job gem'
|
20
|
-
task :install => [:create] do
|
21
|
-
file = Dir["*.gem"].first
|
22
|
-
sh "gem install #{file}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
Rake::TestTask.new do |t|
|
27
|
-
t.verbose = true
|
28
|
-
t.warning = true
|
29
|
-
end
|
30
|
-
|
31
|
-
task :default => :test
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
CLEAN.include("**/*.gem", "**/*.rbc", "**/*.rbx")
|
6
|
+
|
7
|
+
namespace :gem do
|
8
|
+
desc 'Create the win32-job gem'
|
9
|
+
task :create do
|
10
|
+
spec = eval(IO.read('win32-job.gemspec'))
|
11
|
+
if Gem::VERSION < "2.0"
|
12
|
+
Gem::Builder.new(spec).build
|
13
|
+
else
|
14
|
+
require 'rubygems/package'
|
15
|
+
Gem::Package.build(spec)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'Install the win32-job gem'
|
20
|
+
task :install => [:create] do
|
21
|
+
file = Dir["*.gem"].first
|
22
|
+
sh "gem install #{file}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::TestTask.new do |t|
|
27
|
+
t.verbose = true
|
28
|
+
t.warning = true
|
29
|
+
end
|
30
|
+
|
31
|
+
task :default => :test
|
data/examples/example_job.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
#######################################################################
|
2
|
-
# example_job.rb
|
3
|
-
#
|
4
|
-
# Simple example script for futzing with Windows Jobs. This will fire
|
5
|
-
# up two instances of notepad and add them to the job, then close
|
6
|
-
# them.
|
7
|
-
#######################################################################
|
8
|
-
require 'win32/job'
|
9
|
-
include Win32
|
10
|
-
|
11
|
-
pid1 = Process.spawn("notepad.exe")
|
12
|
-
pid2 = Process.spawn("notepad.exe")
|
13
|
-
sleep 0.5
|
14
|
-
|
15
|
-
j = Job.new('test')
|
16
|
-
|
17
|
-
j.configure_limit(
|
18
|
-
:breakaway_ok => true,
|
19
|
-
:kill_on_job_close => true,
|
20
|
-
:process_memory => 1024 * 8,
|
21
|
-
:process_time => 1000
|
22
|
-
)
|
23
|
-
|
24
|
-
j.add_process(pid1)
|
25
|
-
j.add_process(pid2)
|
26
|
-
|
27
|
-
sleep 0.5
|
28
|
-
|
29
|
-
j.close # Notepad instances should terminate here, too.
|
1
|
+
#######################################################################
|
2
|
+
# example_job.rb
|
3
|
+
#
|
4
|
+
# Simple example script for futzing with Windows Jobs. This will fire
|
5
|
+
# up two instances of notepad and add them to the job, then close
|
6
|
+
# them.
|
7
|
+
#######################################################################
|
8
|
+
require 'win32/job'
|
9
|
+
include Win32
|
10
|
+
|
11
|
+
pid1 = Process.spawn("notepad.exe")
|
12
|
+
pid2 = Process.spawn("notepad.exe")
|
13
|
+
sleep 0.5
|
14
|
+
|
15
|
+
j = Job.new('test')
|
16
|
+
|
17
|
+
j.configure_limit(
|
18
|
+
:breakaway_ok => true,
|
19
|
+
:kill_on_job_close => true,
|
20
|
+
:process_memory => 1024 * 8,
|
21
|
+
:process_time => 1000
|
22
|
+
)
|
23
|
+
|
24
|
+
j.add_process(pid1)
|
25
|
+
j.add_process(pid2)
|
26
|
+
|
27
|
+
sleep 0.5
|
28
|
+
|
29
|
+
j.close # Notepad instances should terminate here, too.
|
data/lib/win32/job.rb
CHANGED
@@ -14,7 +14,7 @@ module Win32
|
|
14
14
|
extend Windows::Functions
|
15
15
|
|
16
16
|
# The version of the win32-job library
|
17
|
-
VERSION = '0.1.
|
17
|
+
VERSION = '0.1.1'
|
18
18
|
|
19
19
|
private
|
20
20
|
|
@@ -448,10 +448,6 @@ module Win32
|
|
448
448
|
#--
|
449
449
|
# See http://blogs.msdn.com/b/oldnewthing/archive/2013/04/05/10407778.aspx
|
450
450
|
#
|
451
|
-
# TODO: Fix. I'm not sure this approach is feasible without the processes
|
452
|
-
# having been created in a suspended state.
|
453
|
-
#
|
454
|
-
=begin
|
455
451
|
def wait
|
456
452
|
io_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
|
457
453
|
|
@@ -472,31 +468,15 @@ module Win32
|
|
472
468
|
|
473
469
|
FFI.raise_windows_error('SetInformationJobObject', FFI.errno) unless bool
|
474
470
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
FFI.raise_windows_error('OpenProcess', FFI.errno) unless handle
|
479
|
-
|
480
|
-
# BUG: I get access denied errors here.
|
481
|
-
unless AssignProcessToJobObject(@job_handle, handle)
|
482
|
-
FFI.raise_windows_error('AssignProcessToJobObject', FFI.errno)
|
483
|
-
end
|
484
|
-
|
485
|
-
# TODO: Do I need to get the thread handle and explicitly close it?
|
471
|
+
olap = FFI::MemoryPointer.new(Overlapped)
|
472
|
+
bytes = FFI::MemoryPointer.new(:ulong)
|
473
|
+
ckey = FFI::MemoryPointer.new(:uintptr_t)
|
486
474
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
ckey = FFI::MemoryPointer.new(:uintptr_t)
|
492
|
-
|
493
|
-
while GetQueuedCompletionPort(io_port, bytes, ckey, olap, INFINITE) &&
|
494
|
-
!(ckey.read_pointer.to_i == @job_handle && ccode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
|
495
|
-
sleep 0.1
|
496
|
-
end
|
497
|
-
}
|
475
|
+
while GetQueuedCompletionStatus(io_port, bytes, ckey, olap, INFINITE) &&
|
476
|
+
!(ckey.read_pointer.to_i == @job_handle && bytes.read_ulong == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
|
477
|
+
sleep 0.1
|
478
|
+
end
|
498
479
|
end
|
499
|
-
=end
|
500
480
|
|
501
481
|
private
|
502
482
|
|
data/lib/win32/job/constants.rb
CHANGED
@@ -1,64 +1,64 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Windows
|
4
|
-
module Constants
|
5
|
-
private
|
6
|
-
|
7
|
-
JobObjectBasicAccountingInformation = 1
|
8
|
-
JobObjectBasicLimitInformation = 2
|
9
|
-
JobObjectBasicProcessIdList = 3
|
10
|
-
JobObjectBasicUIRestrictions = 4
|
11
|
-
JobObjectSecurityLimitInformation = 5
|
12
|
-
JobObjectEndOfJobTimeInformation = 6
|
13
|
-
JobObjectAssociateCompletionPortInformation = 7
|
14
|
-
JobObjectBasicAndIoAccountingInformation = 8
|
15
|
-
JobObjectExtendedLimitInformation = 9
|
16
|
-
JobObjectGroupInformation = 11
|
17
|
-
JobObjectNotificationLimitInformation = 12
|
18
|
-
JobObjectLimitViolationInformation = 13
|
19
|
-
JobObjectGroupInformationEx = 14
|
20
|
-
JobObjectCpuRateControlInformation = 15
|
21
|
-
|
22
|
-
PROCESS_ALL_ACCESS = 0x1F0FFF
|
23
|
-
PROCESS_SET_QUOTA = 0x0100
|
24
|
-
PROCESS_TERMINATE = 0x0001
|
25
|
-
SYNCHRONIZE = 0x00100000
|
26
|
-
|
27
|
-
INFINITE = 0xFFFFFFFF
|
28
|
-
|
29
|
-
INVALID_HANDLE_VALUE = FFI::Pointer.new(-1).address
|
30
|
-
|
31
|
-
JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008
|
32
|
-
JOB_OBJECT_LIMIT_AFFINITY = 0x00000010
|
33
|
-
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
|
34
|
-
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400
|
35
|
-
JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200
|
36
|
-
JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004
|
37
|
-
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
|
38
|
-
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040
|
39
|
-
JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020
|
40
|
-
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100
|
41
|
-
JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002
|
42
|
-
JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080
|
43
|
-
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
|
44
|
-
JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000
|
45
|
-
JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001
|
46
|
-
|
47
|
-
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4
|
48
|
-
|
49
|
-
WAIT_ABANDONED = 0x00000080
|
50
|
-
WAIT_IO_COMPLETION = 0x000000C0
|
51
|
-
WAIT_OBJECT_0 = 0x00000000
|
52
|
-
WAIT_TIMEOUT = 0x00000102
|
53
|
-
WAIT_FAILED = 0xFFFFFFFF
|
54
|
-
|
55
|
-
public
|
56
|
-
|
57
|
-
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000
|
58
|
-
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
|
59
|
-
HIGH_PRIORITY_CLASS = 0x00000080
|
60
|
-
IDLE_PRIORITY_CLASS = 0x00000040
|
61
|
-
NORMAL_PRIORITY_CLASS = 0x00000020
|
62
|
-
REALTIME_PRIORITY_CLASS = 0x00000100
|
63
|
-
end
|
64
|
-
end
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Windows
|
4
|
+
module Constants
|
5
|
+
private
|
6
|
+
|
7
|
+
JobObjectBasicAccountingInformation = 1
|
8
|
+
JobObjectBasicLimitInformation = 2
|
9
|
+
JobObjectBasicProcessIdList = 3
|
10
|
+
JobObjectBasicUIRestrictions = 4
|
11
|
+
JobObjectSecurityLimitInformation = 5
|
12
|
+
JobObjectEndOfJobTimeInformation = 6
|
13
|
+
JobObjectAssociateCompletionPortInformation = 7
|
14
|
+
JobObjectBasicAndIoAccountingInformation = 8
|
15
|
+
JobObjectExtendedLimitInformation = 9
|
16
|
+
JobObjectGroupInformation = 11
|
17
|
+
JobObjectNotificationLimitInformation = 12
|
18
|
+
JobObjectLimitViolationInformation = 13
|
19
|
+
JobObjectGroupInformationEx = 14
|
20
|
+
JobObjectCpuRateControlInformation = 15
|
21
|
+
|
22
|
+
PROCESS_ALL_ACCESS = 0x1F0FFF
|
23
|
+
PROCESS_SET_QUOTA = 0x0100
|
24
|
+
PROCESS_TERMINATE = 0x0001
|
25
|
+
SYNCHRONIZE = 0x00100000
|
26
|
+
|
27
|
+
INFINITE = 0xFFFFFFFF
|
28
|
+
|
29
|
+
INVALID_HANDLE_VALUE = FFI::Pointer.new(-1).address
|
30
|
+
|
31
|
+
JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008
|
32
|
+
JOB_OBJECT_LIMIT_AFFINITY = 0x00000010
|
33
|
+
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
|
34
|
+
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400
|
35
|
+
JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200
|
36
|
+
JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004
|
37
|
+
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
|
38
|
+
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040
|
39
|
+
JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020
|
40
|
+
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100
|
41
|
+
JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002
|
42
|
+
JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080
|
43
|
+
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
|
44
|
+
JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000
|
45
|
+
JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001
|
46
|
+
|
47
|
+
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4
|
48
|
+
|
49
|
+
WAIT_ABANDONED = 0x00000080
|
50
|
+
WAIT_IO_COMPLETION = 0x000000C0
|
51
|
+
WAIT_OBJECT_0 = 0x00000000
|
52
|
+
WAIT_TIMEOUT = 0x00000102
|
53
|
+
WAIT_FAILED = 0xFFFFFFFF
|
54
|
+
|
55
|
+
public
|
56
|
+
|
57
|
+
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000
|
58
|
+
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
|
59
|
+
HIGH_PRIORITY_CLASS = 0x00000080
|
60
|
+
IDLE_PRIORITY_CLASS = 0x00000040
|
61
|
+
NORMAL_PRIORITY_CLASS = 0x00000020
|
62
|
+
REALTIME_PRIORITY_CLASS = 0x00000100
|
63
|
+
end
|
64
|
+
end
|
data/lib/win32/job/helper.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module FFI
|
4
|
-
extend FFI::Library
|
5
|
-
|
6
|
-
ffi_lib :kernel32
|
7
|
-
|
8
|
-
attach_function :FormatMessage, :FormatMessageA,
|
9
|
-
[:ulong, :pointer, :ulong, :ulong, :pointer, :ulong, :pointer], :ulong
|
10
|
-
|
11
|
-
def win_error(function, err=FFI.errno)
|
12
|
-
flags = 0x00001000 | 0x00000200
|
13
|
-
buf = FFI::MemoryPointer.new(:char, 1024)
|
14
|
-
|
15
|
-
FormatMessage(flags, nil, err , 0x0409, buf, 1024, nil)
|
16
|
-
|
17
|
-
function + ': ' + buf.read_string.strip
|
18
|
-
end
|
19
|
-
|
20
|
-
def raise_windows_error(function, err=FFI.errno)
|
21
|
-
raise SystemCallError.new(win_error(function, err), err)
|
22
|
-
end
|
23
|
-
|
24
|
-
module_function :win_error
|
25
|
-
module_function :raise_windows_error
|
26
|
-
end
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
extend FFI::Library
|
5
|
+
|
6
|
+
ffi_lib :kernel32
|
7
|
+
|
8
|
+
attach_function :FormatMessage, :FormatMessageA,
|
9
|
+
[:ulong, :pointer, :ulong, :ulong, :pointer, :ulong, :pointer], :ulong
|
10
|
+
|
11
|
+
def win_error(function, err=FFI.errno)
|
12
|
+
flags = 0x00001000 | 0x00000200
|
13
|
+
buf = FFI::MemoryPointer.new(:char, 1024)
|
14
|
+
|
15
|
+
FormatMessage(flags, nil, err , 0x0409, buf, 1024, nil)
|
16
|
+
|
17
|
+
function + ': ' + buf.read_string.strip
|
18
|
+
end
|
19
|
+
|
20
|
+
def raise_windows_error(function, err=FFI.errno)
|
21
|
+
raise SystemCallError.new(win_error(function, err), err)
|
22
|
+
end
|
23
|
+
|
24
|
+
module_function :win_error
|
25
|
+
module_function :raise_windows_error
|
26
|
+
end
|
data/lib/win32/job/structs.rb
CHANGED
@@ -1,175 +1,175 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Windows
|
4
|
-
module Structs
|
5
|
-
extend FFI::Library
|
6
|
-
|
7
|
-
typedef :uintptr_t, :handle
|
8
|
-
typedef :ulong, :dword
|
9
|
-
typedef :ushort, :word
|
10
|
-
|
11
|
-
class LARGE_INTEGER < FFI::Union
|
12
|
-
layout(:QuadPart, :long_long)
|
13
|
-
end
|
14
|
-
|
15
|
-
class JOBOBJECT_BASIC_PROCESS_ID_LIST < FFI::Struct
|
16
|
-
layout(
|
17
|
-
:NumberOfAssignedProcesses, :ulong,
|
18
|
-
:NumberOfProcessIdsInList, :ulong,
|
19
|
-
:ProcessIdList, [:uintptr_t, 100] # Limit 100 processes per job (?)
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
|
-
class JOBOBJECT_BASIC_ACCOUNTING_INFORMATION < FFI::Struct
|
24
|
-
layout(
|
25
|
-
:TotalUserTime, LARGE_INTEGER,
|
26
|
-
:TotalKernelTime, LARGE_INTEGER,
|
27
|
-
:ThisPeriodTotalUserTime, LARGE_INTEGER,
|
28
|
-
:ThisPeriodTotalKernelTime, LARGE_INTEGER,
|
29
|
-
:TotalPageFaultCount, :ulong,
|
30
|
-
:TotalProcesses, :ulong,
|
31
|
-
:ActiveProcesses, :ulong,
|
32
|
-
:TotalTerminatedProcesses, :ulong
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
|
-
class IO_COUNTERS < FFI::Struct
|
37
|
-
layout(
|
38
|
-
:ReadOperationCount, :ulong_long,
|
39
|
-
:WriteOperationCount, :ulong_long,
|
40
|
-
:OtherOperationCount, :ulong_long,
|
41
|
-
:ReadTransferCount, :ulong_long,
|
42
|
-
:WriteTransferCount, :ulong_long,
|
43
|
-
:OtherTransferCount, :ulong_long
|
44
|
-
)
|
45
|
-
end
|
46
|
-
|
47
|
-
class JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION < FFI::Struct
|
48
|
-
layout(
|
49
|
-
:BasicInfo, JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,
|
50
|
-
:IoInfo, IO_COUNTERS
|
51
|
-
)
|
52
|
-
end
|
53
|
-
|
54
|
-
class JOBOBJECT_BASIC_LIMIT_INFORMATION < FFI::Struct
|
55
|
-
layout(
|
56
|
-
:PerProcessUserTimeLimit, LARGE_INTEGER,
|
57
|
-
:PerJobUserTimeLimit, LARGE_INTEGER,
|
58
|
-
:LimitFlags, :ulong,
|
59
|
-
:MinimumWorkingSetSize, :size_t,
|
60
|
-
:MaximumWorkingSetSize, :size_t,
|
61
|
-
:ActiveProcessLimit, :ulong,
|
62
|
-
:Affinity, :uintptr_t,
|
63
|
-
:PriorityClass, :ulong,
|
64
|
-
:SchedulingClass, :ulong
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
class JOBOBJECT_EXTENDED_LIMIT_INFORMATION < FFI::Struct
|
69
|
-
layout(
|
70
|
-
:BasicLimitInformation, JOBOBJECT_BASIC_LIMIT_INFORMATION,
|
71
|
-
:IoInfo, IO_COUNTERS,
|
72
|
-
:ProcessMemoryLimit, :size_t,
|
73
|
-
:JobMemoryLimit, :size_t,
|
74
|
-
:PeakProcessMemoryUsed, :size_t,
|
75
|
-
:PeakJobMemoryUsed, :size_t
|
76
|
-
)
|
77
|
-
end
|
78
|
-
|
79
|
-
class JOBOBJECT_ASSOCIATE_COMPLETION_PORT < FFI::Struct
|
80
|
-
layout(:CompletionKey, :uintptr_t, :CompletionPort, :handle)
|
81
|
-
end
|
82
|
-
|
83
|
-
class SECURITY_ATTRIBUTES < FFI::Struct
|
84
|
-
layout(
|
85
|
-
:nLength, :ulong,
|
86
|
-
:lpSecurityDescriptor, :pointer,
|
87
|
-
:bInheritHandle, :bool
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
class PROCESS_INFORMATION < FFI::Struct
|
92
|
-
layout(
|
93
|
-
:hProcess, :handle,
|
94
|
-
:hThread, :handle,
|
95
|
-
:dwProcessId, :dword,
|
96
|
-
:dwThreadId, :dword
|
97
|
-
)
|
98
|
-
end
|
99
|
-
|
100
|
-
class STARTUPINFO < FFI::Struct
|
101
|
-
layout(
|
102
|
-
:cb, :ulong,
|
103
|
-
:lpReserved, :string,
|
104
|
-
:lpDesktop, :string,
|
105
|
-
:lpTitle, :string,
|
106
|
-
:dwX, :dword,
|
107
|
-
:dwY, :dword,
|
108
|
-
:dwXSize, :dword,
|
109
|
-
:dwYSize, :dword,
|
110
|
-
:dwXCountChars, :dword,
|
111
|
-
:dwYCountChars, :dword,
|
112
|
-
:dwFillAttribute, :dword,
|
113
|
-
:dwFlags, :dword,
|
114
|
-
:wShowWindow, :word,
|
115
|
-
:cbReserved2, :word,
|
116
|
-
:lpReserved2, :pointer,
|
117
|
-
:hStdInput, :handle,
|
118
|
-
:hStdOutput, :handle,
|
119
|
-
:hStdError, :handle
|
120
|
-
)
|
121
|
-
end
|
122
|
-
|
123
|
-
# I'm assuming the anonymous struct for the internal union here.
|
124
|
-
class Overlapped < FFI::Struct
|
125
|
-
layout(
|
126
|
-
:Internal, :ulong,
|
127
|
-
:InternalHigh, :ulong,
|
128
|
-
:Offset, :ulong,
|
129
|
-
:OffsetHigh, :ulong,
|
130
|
-
:hEvent, :ulong
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Ruby Structs
|
135
|
-
|
136
|
-
AccountInfo = Struct.new('AccountInfo',
|
137
|
-
:total_user_time,
|
138
|
-
:total_kernel_time,
|
139
|
-
:this_period_total_user_time,
|
140
|
-
:this_period_total_kernel_time,
|
141
|
-
:total_page_fault_count,
|
142
|
-
:total_processes,
|
143
|
-
:active_processes,
|
144
|
-
:total_terminated_processes,
|
145
|
-
:read_operation_count,
|
146
|
-
:write_operation_count,
|
147
|
-
:other_operation_count,
|
148
|
-
:read_transfer_count,
|
149
|
-
:write_transfer_count,
|
150
|
-
:other_transfer_count
|
151
|
-
)
|
152
|
-
|
153
|
-
LimitInfo = Struct.new('LimitInfo',
|
154
|
-
:per_process_user_time_limit,
|
155
|
-
:per_job_user_time_limit,
|
156
|
-
:limit_flags,
|
157
|
-
:minimum_working_set_size,
|
158
|
-
:maximum_working_set_size,
|
159
|
-
:active_process_limit,
|
160
|
-
:affinity,
|
161
|
-
:priority_class,
|
162
|
-
:scheduling_class,
|
163
|
-
:read_operation_count,
|
164
|
-
:write_operation_count,
|
165
|
-
:other_operation_count,
|
166
|
-
:read_transfer_count,
|
167
|
-
:write_transfer_count,
|
168
|
-
:other_transfer_count,
|
169
|
-
:process_memory_limit,
|
170
|
-
:job_memory_limit,
|
171
|
-
:peak_process_memory_used,
|
172
|
-
:peek_job_memory_used
|
173
|
-
)
|
174
|
-
end
|
175
|
-
end
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Windows
|
4
|
+
module Structs
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
typedef :uintptr_t, :handle
|
8
|
+
typedef :ulong, :dword
|
9
|
+
typedef :ushort, :word
|
10
|
+
|
11
|
+
class LARGE_INTEGER < FFI::Union
|
12
|
+
layout(:QuadPart, :long_long)
|
13
|
+
end
|
14
|
+
|
15
|
+
class JOBOBJECT_BASIC_PROCESS_ID_LIST < FFI::Struct
|
16
|
+
layout(
|
17
|
+
:NumberOfAssignedProcesses, :ulong,
|
18
|
+
:NumberOfProcessIdsInList, :ulong,
|
19
|
+
:ProcessIdList, [:uintptr_t, 100] # Limit 100 processes per job (?)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
class JOBOBJECT_BASIC_ACCOUNTING_INFORMATION < FFI::Struct
|
24
|
+
layout(
|
25
|
+
:TotalUserTime, LARGE_INTEGER,
|
26
|
+
:TotalKernelTime, LARGE_INTEGER,
|
27
|
+
:ThisPeriodTotalUserTime, LARGE_INTEGER,
|
28
|
+
:ThisPeriodTotalKernelTime, LARGE_INTEGER,
|
29
|
+
:TotalPageFaultCount, :ulong,
|
30
|
+
:TotalProcesses, :ulong,
|
31
|
+
:ActiveProcesses, :ulong,
|
32
|
+
:TotalTerminatedProcesses, :ulong
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
class IO_COUNTERS < FFI::Struct
|
37
|
+
layout(
|
38
|
+
:ReadOperationCount, :ulong_long,
|
39
|
+
:WriteOperationCount, :ulong_long,
|
40
|
+
:OtherOperationCount, :ulong_long,
|
41
|
+
:ReadTransferCount, :ulong_long,
|
42
|
+
:WriteTransferCount, :ulong_long,
|
43
|
+
:OtherTransferCount, :ulong_long
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
class JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION < FFI::Struct
|
48
|
+
layout(
|
49
|
+
:BasicInfo, JOBOBJECT_BASIC_ACCOUNTING_INFORMATION,
|
50
|
+
:IoInfo, IO_COUNTERS
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
class JOBOBJECT_BASIC_LIMIT_INFORMATION < FFI::Struct
|
55
|
+
layout(
|
56
|
+
:PerProcessUserTimeLimit, LARGE_INTEGER,
|
57
|
+
:PerJobUserTimeLimit, LARGE_INTEGER,
|
58
|
+
:LimitFlags, :ulong,
|
59
|
+
:MinimumWorkingSetSize, :size_t,
|
60
|
+
:MaximumWorkingSetSize, :size_t,
|
61
|
+
:ActiveProcessLimit, :ulong,
|
62
|
+
:Affinity, :uintptr_t,
|
63
|
+
:PriorityClass, :ulong,
|
64
|
+
:SchedulingClass, :ulong
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
class JOBOBJECT_EXTENDED_LIMIT_INFORMATION < FFI::Struct
|
69
|
+
layout(
|
70
|
+
:BasicLimitInformation, JOBOBJECT_BASIC_LIMIT_INFORMATION,
|
71
|
+
:IoInfo, IO_COUNTERS,
|
72
|
+
:ProcessMemoryLimit, :size_t,
|
73
|
+
:JobMemoryLimit, :size_t,
|
74
|
+
:PeakProcessMemoryUsed, :size_t,
|
75
|
+
:PeakJobMemoryUsed, :size_t
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
class JOBOBJECT_ASSOCIATE_COMPLETION_PORT < FFI::Struct
|
80
|
+
layout(:CompletionKey, :uintptr_t, :CompletionPort, :handle)
|
81
|
+
end
|
82
|
+
|
83
|
+
class SECURITY_ATTRIBUTES < FFI::Struct
|
84
|
+
layout(
|
85
|
+
:nLength, :ulong,
|
86
|
+
:lpSecurityDescriptor, :pointer,
|
87
|
+
:bInheritHandle, :bool
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
class PROCESS_INFORMATION < FFI::Struct
|
92
|
+
layout(
|
93
|
+
:hProcess, :handle,
|
94
|
+
:hThread, :handle,
|
95
|
+
:dwProcessId, :dword,
|
96
|
+
:dwThreadId, :dword
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
class STARTUPINFO < FFI::Struct
|
101
|
+
layout(
|
102
|
+
:cb, :ulong,
|
103
|
+
:lpReserved, :string,
|
104
|
+
:lpDesktop, :string,
|
105
|
+
:lpTitle, :string,
|
106
|
+
:dwX, :dword,
|
107
|
+
:dwY, :dword,
|
108
|
+
:dwXSize, :dword,
|
109
|
+
:dwYSize, :dword,
|
110
|
+
:dwXCountChars, :dword,
|
111
|
+
:dwYCountChars, :dword,
|
112
|
+
:dwFillAttribute, :dword,
|
113
|
+
:dwFlags, :dword,
|
114
|
+
:wShowWindow, :word,
|
115
|
+
:cbReserved2, :word,
|
116
|
+
:lpReserved2, :pointer,
|
117
|
+
:hStdInput, :handle,
|
118
|
+
:hStdOutput, :handle,
|
119
|
+
:hStdError, :handle
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
# I'm assuming the anonymous struct for the internal union here.
|
124
|
+
class Overlapped < FFI::Struct
|
125
|
+
layout(
|
126
|
+
:Internal, :ulong,
|
127
|
+
:InternalHigh, :ulong,
|
128
|
+
:Offset, :ulong,
|
129
|
+
:OffsetHigh, :ulong,
|
130
|
+
:hEvent, :ulong
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Ruby Structs
|
135
|
+
|
136
|
+
AccountInfo = Struct.new('AccountInfo',
|
137
|
+
:total_user_time,
|
138
|
+
:total_kernel_time,
|
139
|
+
:this_period_total_user_time,
|
140
|
+
:this_period_total_kernel_time,
|
141
|
+
:total_page_fault_count,
|
142
|
+
:total_processes,
|
143
|
+
:active_processes,
|
144
|
+
:total_terminated_processes,
|
145
|
+
:read_operation_count,
|
146
|
+
:write_operation_count,
|
147
|
+
:other_operation_count,
|
148
|
+
:read_transfer_count,
|
149
|
+
:write_transfer_count,
|
150
|
+
:other_transfer_count
|
151
|
+
)
|
152
|
+
|
153
|
+
LimitInfo = Struct.new('LimitInfo',
|
154
|
+
:per_process_user_time_limit,
|
155
|
+
:per_job_user_time_limit,
|
156
|
+
:limit_flags,
|
157
|
+
:minimum_working_set_size,
|
158
|
+
:maximum_working_set_size,
|
159
|
+
:active_process_limit,
|
160
|
+
:affinity,
|
161
|
+
:priority_class,
|
162
|
+
:scheduling_class,
|
163
|
+
:read_operation_count,
|
164
|
+
:write_operation_count,
|
165
|
+
:other_operation_count,
|
166
|
+
:read_transfer_count,
|
167
|
+
:write_transfer_count,
|
168
|
+
:other_transfer_count,
|
169
|
+
:process_memory_limit,
|
170
|
+
:job_memory_limit,
|
171
|
+
:peak_process_memory_used,
|
172
|
+
:peek_job_memory_used
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
data/test/test_win32_job.rb
CHANGED
@@ -1,126 +1,130 @@
|
|
1
|
-
#######################################################################
|
2
|
-
# test_win32_job.rb
|
3
|
-
#
|
4
|
-
# Test suite for the win32-job library. You should run these tests
|
5
|
-
# via the "rake test" command.
|
6
|
-
#######################################################################
|
7
|
-
require 'test-unit'
|
8
|
-
require 'win32/job'
|
9
|
-
|
10
|
-
class TC_Win32_Job < Test::Unit::TestCase
|
11
|
-
def setup
|
12
|
-
@name = 'ruby_xxxxxx'
|
13
|
-
@job = Win32::Job.new(@name)
|
14
|
-
@pid = Process.spawn('notepad')
|
15
|
-
end
|
16
|
-
|
17
|
-
test "version number is what we expect" do
|
18
|
-
assert_equal('0.1.
|
19
|
-
end
|
20
|
-
|
21
|
-
test "constructor argument may be omitted" do
|
22
|
-
assert_nothing_raised{ Win32::Job.new }
|
23
|
-
end
|
24
|
-
|
25
|
-
test "constructor accepts a name for the job" do
|
26
|
-
assert_nothing_raised{ Win32::Job.new(@name) }
|
27
|
-
end
|
28
|
-
|
29
|
-
test "argument to constructor must be a string" do
|
30
|
-
assert_raise(TypeError){ Win32::Job.new(1) }
|
31
|
-
end
|
32
|
-
|
33
|
-
test "job_name basic functionality" do
|
34
|
-
assert_respond_to(@job, :job_name)
|
35
|
-
assert_nothing_raised{ @job.job_name }
|
36
|
-
assert_kind_of(String, @job.job_name)
|
37
|
-
end
|
38
|
-
|
39
|
-
test "job_name is read-only" do
|
40
|
-
assert_raise(NoMethodError){ @job.job_name = 'foo' }
|
41
|
-
end
|
42
|
-
|
43
|
-
test "name is an alias for job_name" do
|
44
|
-
assert_alias_method(@job, :name, :job_name)
|
45
|
-
end
|
46
|
-
|
47
|
-
test "close basic functionality" do
|
48
|
-
assert_respond_to(@job, :close)
|
49
|
-
assert_nothing_raised{ @job.close }
|
50
|
-
end
|
51
|
-
|
52
|
-
test "calling close multiple times has no effect" do
|
53
|
-
assert_nothing_raised{ @job.close }
|
54
|
-
assert_nothing_raised{ @job.close }
|
55
|
-
assert_nothing_raised{ @job.close }
|
56
|
-
end
|
57
|
-
|
58
|
-
test "close method does not accept any arguments" do
|
59
|
-
assert_raise(ArgumentError){ @job.close(1) }
|
60
|
-
end
|
61
|
-
|
62
|
-
test "add_process basic functionality" do
|
63
|
-
assert_respond_to(@job, :add_process)
|
64
|
-
end
|
65
|
-
|
66
|
-
test "add_process works as expected" do
|
67
|
-
assert_nothing_raised{ @job.add_process(@pid) }
|
68
|
-
end
|
69
|
-
|
70
|
-
test "add process requires a single argument" do
|
71
|
-
assert_raise(ArgumentError){ @job.add_process }
|
72
|
-
end
|
73
|
-
|
74
|
-
test "kill basic functionality" do
|
75
|
-
assert_respond_to(@job, :kill)
|
76
|
-
end
|
77
|
-
|
78
|
-
test "kill works as expected" do
|
79
|
-
@job.add_process(@pid)
|
80
|
-
assert_equal(@pid, @job.process_list.first)
|
81
|
-
assert_nothing_raised{ @job.kill }
|
82
|
-
assert_true(@job.process_list.empty?)
|
83
|
-
end
|
84
|
-
|
85
|
-
test "terminate is an alias for kill" do
|
86
|
-
assert_alias_method(@job, :kill, :terminate)
|
87
|
-
end
|
88
|
-
|
89
|
-
test "configure_limit basic functionality" do
|
90
|
-
assert_nothing_raised{ @job.configure_limit }
|
91
|
-
end
|
92
|
-
|
93
|
-
test "configure_limit works as expected" do
|
94
|
-
assert_nothing_raised{
|
95
|
-
@job.configure_limit(
|
96
|
-
:breakaway_ok => true,
|
97
|
-
:kill_on_job_close => true,
|
98
|
-
:process_memory => 1024 * 8,
|
99
|
-
:process_time => 1000
|
100
|
-
)
|
101
|
-
}
|
102
|
-
end
|
103
|
-
|
104
|
-
test "configure_limit raises an error if it detects an invalid option" do
|
105
|
-
assert_raise(ArgumentError){ @job.configure_limit(:bogus => 1) }
|
106
|
-
end
|
107
|
-
|
108
|
-
test "
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
assert_not_nil(Win32::Job::
|
114
|
-
assert_not_nil(Win32::Job::
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
@
|
125
|
-
|
126
|
-
|
1
|
+
#######################################################################
|
2
|
+
# test_win32_job.rb
|
3
|
+
#
|
4
|
+
# Test suite for the win32-job library. You should run these tests
|
5
|
+
# via the "rake test" command.
|
6
|
+
#######################################################################
|
7
|
+
require 'test-unit'
|
8
|
+
require 'win32/job'
|
9
|
+
|
10
|
+
class TC_Win32_Job < Test::Unit::TestCase
|
11
|
+
def setup
|
12
|
+
@name = 'ruby_xxxxxx'
|
13
|
+
@job = Win32::Job.new(@name)
|
14
|
+
@pid = Process.spawn('notepad')
|
15
|
+
end
|
16
|
+
|
17
|
+
test "version number is what we expect" do
|
18
|
+
assert_equal('0.1.1', Win32::Job::VERSION)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "constructor argument may be omitted" do
|
22
|
+
assert_nothing_raised{ Win32::Job.new }
|
23
|
+
end
|
24
|
+
|
25
|
+
test "constructor accepts a name for the job" do
|
26
|
+
assert_nothing_raised{ Win32::Job.new(@name) }
|
27
|
+
end
|
28
|
+
|
29
|
+
test "argument to constructor must be a string" do
|
30
|
+
assert_raise(TypeError){ Win32::Job.new(1) }
|
31
|
+
end
|
32
|
+
|
33
|
+
test "job_name basic functionality" do
|
34
|
+
assert_respond_to(@job, :job_name)
|
35
|
+
assert_nothing_raised{ @job.job_name }
|
36
|
+
assert_kind_of(String, @job.job_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
test "job_name is read-only" do
|
40
|
+
assert_raise(NoMethodError){ @job.job_name = 'foo' }
|
41
|
+
end
|
42
|
+
|
43
|
+
test "name is an alias for job_name" do
|
44
|
+
assert_alias_method(@job, :name, :job_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "close basic functionality" do
|
48
|
+
assert_respond_to(@job, :close)
|
49
|
+
assert_nothing_raised{ @job.close }
|
50
|
+
end
|
51
|
+
|
52
|
+
test "calling close multiple times has no effect" do
|
53
|
+
assert_nothing_raised{ @job.close }
|
54
|
+
assert_nothing_raised{ @job.close }
|
55
|
+
assert_nothing_raised{ @job.close }
|
56
|
+
end
|
57
|
+
|
58
|
+
test "close method does not accept any arguments" do
|
59
|
+
assert_raise(ArgumentError){ @job.close(1) }
|
60
|
+
end
|
61
|
+
|
62
|
+
test "add_process basic functionality" do
|
63
|
+
assert_respond_to(@job, :add_process)
|
64
|
+
end
|
65
|
+
|
66
|
+
test "add_process works as expected" do
|
67
|
+
assert_nothing_raised{ @job.add_process(@pid) }
|
68
|
+
end
|
69
|
+
|
70
|
+
test "add process requires a single argument" do
|
71
|
+
assert_raise(ArgumentError){ @job.add_process }
|
72
|
+
end
|
73
|
+
|
74
|
+
test "kill basic functionality" do
|
75
|
+
assert_respond_to(@job, :kill)
|
76
|
+
end
|
77
|
+
|
78
|
+
test "kill works as expected" do
|
79
|
+
@job.add_process(@pid)
|
80
|
+
assert_equal(@pid, @job.process_list.first)
|
81
|
+
assert_nothing_raised{ @job.kill }
|
82
|
+
assert_true(@job.process_list.empty?)
|
83
|
+
end
|
84
|
+
|
85
|
+
test "terminate is an alias for kill" do
|
86
|
+
assert_alias_method(@job, :kill, :terminate)
|
87
|
+
end
|
88
|
+
|
89
|
+
test "configure_limit basic functionality" do
|
90
|
+
assert_nothing_raised{ @job.configure_limit }
|
91
|
+
end
|
92
|
+
|
93
|
+
test "configure_limit works as expected" do
|
94
|
+
assert_nothing_raised{
|
95
|
+
@job.configure_limit(
|
96
|
+
:breakaway_ok => true,
|
97
|
+
:kill_on_job_close => true,
|
98
|
+
:process_memory => 1024 * 8,
|
99
|
+
:process_time => 1000
|
100
|
+
)
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
test "configure_limit raises an error if it detects an invalid option" do
|
105
|
+
assert_raise(ArgumentError){ @job.configure_limit(:bogus => 1) }
|
106
|
+
end
|
107
|
+
|
108
|
+
test "wait method basic functionality" do
|
109
|
+
assert_respond_to(@job, :wait)
|
110
|
+
end
|
111
|
+
|
112
|
+
test "priority constants are defined" do
|
113
|
+
assert_not_nil(Win32::Job::ABOVE_NORMAL_PRIORITY_CLASS)
|
114
|
+
assert_not_nil(Win32::Job::BELOW_NORMAL_PRIORITY_CLASS)
|
115
|
+
assert_not_nil(Win32::Job::HIGH_PRIORITY_CLASS)
|
116
|
+
assert_not_nil(Win32::Job::IDLE_PRIORITY_CLASS)
|
117
|
+
assert_not_nil(Win32::Job::NORMAL_PRIORITY_CLASS)
|
118
|
+
assert_not_nil(Win32::Job::REALTIME_PRIORITY_CLASS)
|
119
|
+
end
|
120
|
+
|
121
|
+
def teardown
|
122
|
+
@name = nil
|
123
|
+
|
124
|
+
@job.close
|
125
|
+
@job = nil
|
126
|
+
|
127
|
+
Process.kill(9, @pid) rescue nil
|
128
|
+
@pid = nil
|
129
|
+
end
|
130
|
+
end
|
data/win32-job.gemspec
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
Gem::Specification.new do |spec|
|
4
|
-
spec.name = 'win32-job'
|
5
|
-
spec.version = '0.1.
|
6
|
-
spec.
|
7
|
-
spec.license = 'Artistic 2.0'
|
8
|
-
spec.email = 'djberg96@gmail.com'
|
9
|
-
spec.homepage = 'http://github.com/djberg96/win32-job'
|
10
|
-
spec.summary = 'Interface for Windows jobs (process groups)'
|
11
|
-
spec.test_file = 'test/test_win32_job.rb'
|
12
|
-
spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
|
13
|
-
|
14
|
-
spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
|
15
|
-
spec.rubyforge_project = 'win32utils'
|
16
|
-
spec.required_ruby_version = '> 1.9.
|
17
|
-
|
18
|
-
spec.add_dependency('ffi')
|
19
|
-
|
20
|
-
spec.add_development_dependency('rake')
|
21
|
-
spec.add_development_dependency('test-unit')
|
22
|
-
|
23
|
-
spec.description = <<-EOF
|
24
|
-
The win32-job library provides an interface for jobs (process groups)
|
25
|
-
on MS Windows. This allows you to apply various limits and behavior to
|
26
|
-
groups of processes on Windows.
|
27
|
-
EOF
|
28
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'win32-job'
|
5
|
+
spec.version = '0.1.1'
|
6
|
+
spec.authors = ['Daniel J. Berger', 'Park Heesob']
|
7
|
+
spec.license = 'Artistic 2.0'
|
8
|
+
spec.email = 'djberg96@gmail.com'
|
9
|
+
spec.homepage = 'http://github.com/djberg96/win32-job'
|
10
|
+
spec.summary = 'Interface for Windows jobs (process groups)'
|
11
|
+
spec.test_file = 'test/test_win32_job.rb'
|
12
|
+
spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
|
13
|
+
|
14
|
+
spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
|
15
|
+
spec.rubyforge_project = 'win32utils'
|
16
|
+
spec.required_ruby_version = '> 1.9.3'
|
17
|
+
|
18
|
+
spec.add_dependency('ffi')
|
19
|
+
|
20
|
+
spec.add_development_dependency('rake')
|
21
|
+
spec.add_development_dependency('test-unit')
|
22
|
+
|
23
|
+
spec.description = <<-EOF
|
24
|
+
The win32-job library provides an interface for jobs (process groups)
|
25
|
+
on MS Windows. This allows you to apply various limits and behavior to
|
26
|
+
groups of processes on Windows.
|
27
|
+
EOF
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
8
|
+
- Park Heesob
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
12
|
+
date: 2014-02-05 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: ffi
|
@@ -65,17 +66,16 @@ extra_rdoc_files:
|
|
65
66
|
- MANIFEST
|
66
67
|
files:
|
67
68
|
- CHANGES
|
69
|
+
- MANIFEST
|
70
|
+
- README
|
71
|
+
- Rakefile
|
68
72
|
- examples/example_job.rb
|
73
|
+
- lib/win32/job.rb
|
69
74
|
- lib/win32/job/constants.rb
|
70
75
|
- lib/win32/job/functions.rb
|
71
76
|
- lib/win32/job/helper.rb
|
72
77
|
- lib/win32/job/structs.rb
|
73
|
-
- lib/win32/job.rb
|
74
|
-
- MANIFEST
|
75
|
-
- Rakefile
|
76
|
-
- README
|
77
78
|
- test/test_win32_job.rb
|
78
|
-
- win32-job-0.1.0.gem
|
79
79
|
- win32-job.gemspec
|
80
80
|
homepage: http://github.com/djberg96/win32-job
|
81
81
|
licenses:
|
@@ -89,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
89
|
requirements:
|
90
90
|
- - '>'
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 1.9.
|
92
|
+
version: 1.9.3
|
93
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - '>='
|
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
97
|
version: '0'
|
98
98
|
requirements: []
|
99
99
|
rubyforge_project: win32utils
|
100
|
-
rubygems_version: 2.
|
100
|
+
rubygems_version: 2.2.1
|
101
101
|
signing_key:
|
102
102
|
specification_version: 4
|
103
103
|
summary: Interface for Windows jobs (process groups)
|
data/win32-job-0.1.0.gem
DELETED
Binary file
|