proc-wait3 1.5.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.
- data/CHANGES +61 -0
- data/README +53 -0
- data/doc/wait3.txt +154 -0
- data/extconf.rb +54 -0
- data/lib/proc/wait3.c +908 -0
- data/test/tc_wait3.rb +199 -0
- metadata +51 -0
data/CHANGES
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
== 1.5.1 - 13-Jul-2006
|
2
|
+
* Fixed bugs with improper values being set for some of the rlimit constants.
|
3
|
+
* Cleaned up a few warnings related to signed-ness for the RLIM_xxx constants.
|
4
|
+
* Now only sets the various rlimit constants if they're not already defined
|
5
|
+
(which Ruby now defines, as of 1.8.5).
|
6
|
+
* Some internal cleanup.
|
7
|
+
* Created a gemspec and added a gem to RubyForge.
|
8
|
+
|
9
|
+
== 1.5.0 - 12-Jun-2006
|
10
|
+
* Removed the '?' character from the various struct members, since Ruby
|
11
|
+
no longer (properly) handles them.
|
12
|
+
* Fixed a 64 bit bug related to rb_struct_define.
|
13
|
+
* Added some more tests.
|
14
|
+
|
15
|
+
== 1.4.3 - 28-Jun-2005
|
16
|
+
* Added more #ifdef checks for some of the process flags which, it turns
|
17
|
+
out, are not defined in earlier versions of Linux.
|
18
|
+
|
19
|
+
== 1.4.2 - 14-Jun-2005
|
20
|
+
* Fixed a syntax error that could cause the build to fail.
|
21
|
+
* Removed some (but not all) possible warnings from gcc -Wall.
|
22
|
+
|
23
|
+
== 1.4.1 - 13-Jun-2005
|
24
|
+
* Added support for the Linux 2.6.9+ kernel (by adding more preprocessor
|
25
|
+
constant checks, which may help with other platforms as well).
|
26
|
+
* Moved project to RubyForge.
|
27
|
+
* Modified test suite - some tests now skipped on Linux.
|
28
|
+
* Removed the wait3.rd file.
|
29
|
+
* Minor fix for the test_waitid.rb sample program.
|
30
|
+
|
31
|
+
== 1.4.0 - 16-Feb-2005
|
32
|
+
* Added the getrusage method.
|
33
|
+
* Added test cases and documentation for getrusage.
|
34
|
+
* Renamed a couple test files in the examples directory.
|
35
|
+
|
36
|
+
== 1.3.0 - 14-Feb-2005
|
37
|
+
* Added the pause and sigsend methods.
|
38
|
+
* I had to modify the process type constants to include the "P_", because
|
39
|
+
Ruby already has Process::GID and Process::UID defined. That makes this
|
40
|
+
release incompatible with previous versions.
|
41
|
+
* Updated tests and documentation.
|
42
|
+
|
43
|
+
== 1.2.0 - 7-Feb-2005
|
44
|
+
* Added the Proc.waitid method (for those platforms that support it).
|
45
|
+
* Made the wait3.c file more rdoc friendly.
|
46
|
+
* Added a test_waitid.rb file in the examples directory.
|
47
|
+
|
48
|
+
== 1.1.1 - 10-Jan-2005
|
49
|
+
* Eliminated some (harmless) warnings that cropped up in 1.8.2
|
50
|
+
* Moved the "examples" directory to the toplevel directory.
|
51
|
+
* Made docs slightly more rdoc friendly
|
52
|
+
|
53
|
+
== 1.1.0 - 14-Sep-2004
|
54
|
+
* Modified setup and source to handle the possibility that wait3() might
|
55
|
+
be defined while wait4() is not (e.g. HPUX).
|
56
|
+
* Modified the test scripts in the examples directory to play nice on HPUX
|
57
|
+
and Darwin.
|
58
|
+
* Added this file (oops).
|
59
|
+
|
60
|
+
== 1.0.0 - 13-Sep-2004
|
61
|
+
- Initial release
|
data/README
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
== Description
|
2
|
+
Adds the wait3, wait4, waitid, pause, sigsend, and getrusage methods to
|
3
|
+
the Process module.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
ruby extconf.rb
|
7
|
+
make
|
8
|
+
ruby test/tc_wait3.rb (optional)
|
9
|
+
make site-install
|
10
|
+
|
11
|
+
== Tested Platforms
|
12
|
+
* Solaris 9
|
13
|
+
* Solaris 10
|
14
|
+
* Linux 2.4.7 (RedHat)
|
15
|
+
* Linux 2.6.11 (Suse)
|
16
|
+
* Linux 2.6.8.1 (Mandriva)
|
17
|
+
* FreeBSD 4.9
|
18
|
+
|
19
|
+
== Warnings
|
20
|
+
Linux users who compile with gcc -Wall will notice a few warnings. These
|
21
|
+
are harmless (and unavoidable atm).
|
22
|
+
|
23
|
+
== Applying the mkmf.diff patch
|
24
|
+
In order to install this package, you will need to patch your mkmf.rb file with
|
25
|
+
the provided diff file. This is necessary because I need a way to determine
|
26
|
+
if certain idtype_t enum (const) values are defined. The patch adds a
|
27
|
+
"have_const" method (and does nothing else). See ruby-core:4422 and related
|
28
|
+
threads for more information. Also available as ruby-Patches-1486 on the
|
29
|
+
RubyForge project page for Ruby.
|
30
|
+
|
31
|
+
To apply the patch, simply run "ruby patch.rb". Note that you may need to be
|
32
|
+
root to apply the patch.
|
33
|
+
|
34
|
+
== Integration with Ruby's process.c
|
35
|
+
I considered simply providing a patch to the core process.c file, but I
|
36
|
+
decided against it for two reasons. First, I wanted to get something
|
37
|
+
out more quickly rather than waiting for approval from the core developers who,
|
38
|
+
based on an earlier post, seem somewhat gun-shy about integrating support
|
39
|
+
for wait3() and wait4() based, I think, on portability concerns.
|
40
|
+
|
41
|
+
Second, and more importantly, I don't like the cProcStatus class. The
|
42
|
+
extra inspection code seems like an awful lot of work for very little gain.
|
43
|
+
The overloaded methods are also overkill, and do nothing but save me the
|
44
|
+
trouble of typing the word "status", since all they're for is comparing or
|
45
|
+
operating on the status attribute.
|
46
|
+
|
47
|
+
That being said, I would be willing to write a patch for process.c if there's
|
48
|
+
enough support for it. If you'd like to see that, please log a comment and/or
|
49
|
+
feature request on the project page at
|
50
|
+
http://www.rubyforge.org/projects/shards.
|
51
|
+
|
52
|
+
== Additional Documentation
|
53
|
+
Please see the doc/wait3.txt file for detailed documentation.
|
data/doc/wait3.txt
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
== Description
|
2
|
+
Adds the wait3, wait4, waitid, pause, sigsend, and getrusage methods to
|
3
|
+
the Process module.
|
4
|
+
|
5
|
+
== Synopsis
|
6
|
+
require "proc/wait3"
|
7
|
+
|
8
|
+
pid = fork{ sleep 1; exit 2 }
|
9
|
+
p Time.now
|
10
|
+
Process.wait3
|
11
|
+
p $?
|
12
|
+
|
13
|
+
== Module Methods
|
14
|
+
Proc.pause(signals=nil)
|
15
|
+
Pauses the current process. If the process receives any of the signals
|
16
|
+
you pass as arguments it will return from the pause and continue with
|
17
|
+
the execution of your code. Otherwise, it will exit.
|
18
|
+
|
19
|
+
Note that you must leave out the 'SIG' prefix for the signal name, e.g.
|
20
|
+
use 'INT', not 'SIGINT'.
|
21
|
+
|
22
|
+
Returns the result of the pause() function, which should always be -1.
|
23
|
+
|
24
|
+
Process.sigsend(idtype, id, signal=0)
|
25
|
+
Sends a signal of type "idtype" to a process or process group "id". This
|
26
|
+
is more versatile method of sending signals to processes than Process.kill.
|
27
|
+
|
28
|
+
For a list of valid idtype values, see the "Process type constants" below.
|
29
|
+
Not supported on all platforms.
|
30
|
+
|
31
|
+
Proc.wait3(flags=0)
|
32
|
+
Delays its caller until a signal is received or one of its child processes
|
33
|
+
terminates or stops due to tracing.
|
34
|
+
|
35
|
+
The return value is a ProcStat structure. The special global $? is also
|
36
|
+
set. Raises a SystemError if there are no child processes.
|
37
|
+
|
38
|
+
Proc.wait4(pid, flags=0)
|
39
|
+
Waits for the given child process to exit. Returns a ProcStat structure.
|
40
|
+
Also sets the $? special global variable.
|
41
|
+
|
42
|
+
Proc.waitid(id_type, id_num=nil, options=nil)
|
43
|
+
Suspends the calling process until one of its children changes state,
|
44
|
+
returning immediately if a child process changed state prior to the call.
|
45
|
+
The state of a child process will change if it terminates, stops because
|
46
|
+
of a signal, becomes trapped or reaches a breakpoint.
|
47
|
+
|
48
|
+
The id_num corresponds to a pid or pgid, depending on the value of id_type,
|
49
|
+
which may be Process::P_PID, Process::P_PGID or Process::P_ALL. If
|
50
|
+
Process::P_ALL, then the id_num is ignored.
|
51
|
+
|
52
|
+
The options argument is used to specify which state changes are to be
|
53
|
+
waited for. It is constructed from the bitwise-OR of one or more of the
|
54
|
+
following constants:
|
55
|
+
|
56
|
+
Process::WCONTINUED
|
57
|
+
Process::WEXITED
|
58
|
+
Process::WNOHANG
|
59
|
+
Process::WNOWAIT
|
60
|
+
Process::WSTOPPED
|
61
|
+
Process::WTRAPPED (not supported on all platforms)
|
62
|
+
|
63
|
+
If Process::WNOHANG is set as an option, this method will return
|
64
|
+
immediately, whether or not a child has changed state.
|
65
|
+
|
66
|
+
Calling this method with an +id_type+ of Process::P_ALL and the options set
|
67
|
+
to 'Process::EXITED | Process::WTRAPPED' is equivalent to calling
|
68
|
+
Process.wait.
|
69
|
+
|
70
|
+
Returns a Proc::SigInfo struct and sets $?.
|
71
|
+
|
72
|
+
Not supported on all platforms.
|
73
|
+
|
74
|
+
== Constants
|
75
|
+
|
76
|
+
=== Process type constants
|
77
|
+
==== All platforms
|
78
|
+
Process::P_ALL
|
79
|
+
All non-system process.
|
80
|
+
|
81
|
+
Process::P_PID
|
82
|
+
A standard process id.
|
83
|
+
|
84
|
+
Process::P_PGID
|
85
|
+
Any non-system process group id.
|
86
|
+
|
87
|
+
==== Not supported on all platforms
|
88
|
+
Process::P_CID
|
89
|
+
A scheduler process id.
|
90
|
+
|
91
|
+
Process::P_GID
|
92
|
+
Any non-system effective process group id.
|
93
|
+
|
94
|
+
Process::P_PROJID
|
95
|
+
A project process id. Solaris 8 or later only.
|
96
|
+
|
97
|
+
Process::P_SID
|
98
|
+
A session process id.
|
99
|
+
|
100
|
+
Process::P_TASKID
|
101
|
+
A task process id. Solaris 8 or later only.
|
102
|
+
|
103
|
+
Process::P_UID
|
104
|
+
Any non-system effective process user id.
|
105
|
+
|
106
|
+
=== The following additional constants are defined if the waitid function is
|
107
|
+
supported on your system.
|
108
|
+
|
109
|
+
Process::WCONTINUED
|
110
|
+
Return the status for any child that was stopped and has been continued.
|
111
|
+
|
112
|
+
Process::WEXITED
|
113
|
+
Wait for process(es) to exit.
|
114
|
+
|
115
|
+
Process::WNOWAIT
|
116
|
+
Keep the process in a waitable state.
|
117
|
+
|
118
|
+
Process::WSTOPPED
|
119
|
+
Wait for and return the process status of any child that has stopped upon
|
120
|
+
receipt of a signal.
|
121
|
+
|
122
|
+
Process::WTRAPPED
|
123
|
+
Wait for traced process(es) to become trapped or reach a breakpoint.
|
124
|
+
|
125
|
+
Not supported on all platforms.
|
126
|
+
|
127
|
+
== Notes
|
128
|
+
The wait3 and wait4 methods are similar to the wait2() and waitpid2()
|
129
|
+
methods, except that they return much more information via the rusage
|
130
|
+
struct.
|
131
|
+
|
132
|
+
== Known Bugs
|
133
|
+
None that I'm aware of. Please log any bugs on the SourceForge project
|
134
|
+
page at http://ruby-miscutils.sf.net.
|
135
|
+
|
136
|
+
== License
|
137
|
+
Ruby's
|
138
|
+
|
139
|
+
== Copyright
|
140
|
+
(C) 2003-2006 Daniel J. Berger
|
141
|
+
All Rights Reserved.
|
142
|
+
|
143
|
+
== Warranty
|
144
|
+
This package is provided "as is" and without any express or
|
145
|
+
implied warranties, including, without limitation, the implied
|
146
|
+
warranties of merchantability and fitness for a particular purpose.
|
147
|
+
|
148
|
+
== Author
|
149
|
+
Daniel J. Berger
|
150
|
+
djberg96 at gmail dot com
|
151
|
+
imperator on IRC (irc.freenode.net)
|
152
|
+
|
153
|
+
== See also
|
154
|
+
wait3, wait4, waitid, pause, sigsend
|
data/extconf.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
########################################################
|
2
|
+
# Use the mkmf.rb file that I provide, so I can use the
|
3
|
+
# have_enum_member method
|
4
|
+
########################################################
|
5
|
+
require "mkmf"
|
6
|
+
require "ftools"
|
7
|
+
|
8
|
+
File.copy("lib/proc/wait3.c",".")
|
9
|
+
|
10
|
+
have_header("wait.h")
|
11
|
+
|
12
|
+
# wait3 is mandatory.
|
13
|
+
unless have_func("wait3")
|
14
|
+
STDERR.puts "wait3() function not found"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
# wait4 and waitid are optional (HPUX, et al)
|
19
|
+
have_func("wait4")
|
20
|
+
have_func("waitid")
|
21
|
+
have_func("sigsend")
|
22
|
+
have_func("getrusage")
|
23
|
+
|
24
|
+
have_struct_member("struct siginfo", "si_trapno", "signal.h")
|
25
|
+
have_struct_member("struct siginfo", "si_pc", "signal.h")
|
26
|
+
have_struct_member("struct siginfo", "si_sysarg", "signal.h")
|
27
|
+
have_struct_member("struct siginfo", "si_mstate", "signal.h")
|
28
|
+
have_struct_member("struct siginfo", "si_faddr", "signal.h")
|
29
|
+
have_struct_member("struct siginfo", "si_syscall", "signal.h")
|
30
|
+
have_struct_member("struct siginfo", "si_nsysarg", "signal.h")
|
31
|
+
have_struct_member("struct siginfo", "si_fault", "signal.h")
|
32
|
+
have_struct_member("struct siginfo", "si_tstamp", "signal.h")
|
33
|
+
|
34
|
+
begin
|
35
|
+
have_const("P_CID", "signal.h")
|
36
|
+
have_const("P_GID", "signal.h")
|
37
|
+
have_const("P_MYID", "signal.h")
|
38
|
+
have_const("P_SID", "signal.h")
|
39
|
+
have_const("P_UID", "signal.h")
|
40
|
+
|
41
|
+
# These are only supported by Solaris 8 and later afaik
|
42
|
+
have_const("P_PROJID", "signal.h")
|
43
|
+
have_const("P_TASKID", "signal.h")
|
44
|
+
rescue NoMethodError
|
45
|
+
STDERR.puts
|
46
|
+
STDERR.puts "STOP!"
|
47
|
+
STDERR.puts
|
48
|
+
STDERR.puts "Please run the patch.rb program and try again"
|
49
|
+
STDERR.puts "See the README file for more details"
|
50
|
+
STDERR.puts "Makefile NOT created"
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
create_makefile("proc/wait3")
|
data/lib/proc/wait3.c
ADDED
@@ -0,0 +1,908 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <string.h>
|
3
|
+
#include <unistd.h>
|
4
|
+
|
5
|
+
#ifdef HAVE_WAIT_H
|
6
|
+
#include <wait.h>
|
7
|
+
#else
|
8
|
+
#include <sys/resource.h>
|
9
|
+
#include <sys/wait.h>
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#ifdef HAVE_WAITID
|
13
|
+
#include <signal.h>
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#ifndef SIG2STR_MAX
|
17
|
+
#define SIG2STR_MAX 32
|
18
|
+
#endif
|
19
|
+
|
20
|
+
VALUE v_last_status;
|
21
|
+
VALUE v_procstat_struct, v_siginfo_struct, v_usage_struct;
|
22
|
+
|
23
|
+
static void sigproc(int signum);
|
24
|
+
|
25
|
+
/*
|
26
|
+
* Returns true if this process is stopped. This is only returned
|
27
|
+
* returned if the corresponding wait() call had the WUNTRACED flag
|
28
|
+
* set.
|
29
|
+
*/
|
30
|
+
static VALUE pst_wifstopped(int status)
|
31
|
+
{
|
32
|
+
if(WIFSTOPPED(status))
|
33
|
+
return Qtrue;
|
34
|
+
else
|
35
|
+
return Qfalse;
|
36
|
+
}
|
37
|
+
|
38
|
+
/*
|
39
|
+
* Returns true if _stat_ terminated because of an uncaught signal.
|
40
|
+
*/
|
41
|
+
static VALUE pst_wifsignaled(int status)
|
42
|
+
{
|
43
|
+
if (WIFSIGNALED(status))
|
44
|
+
return Qtrue;
|
45
|
+
else
|
46
|
+
return Qfalse;
|
47
|
+
}
|
48
|
+
|
49
|
+
/*
|
50
|
+
* Returns true if _stat_ exited normally (for example using an exit()
|
51
|
+
* call or finishing the program).
|
52
|
+
*/
|
53
|
+
static VALUE pst_wifexited(int status)
|
54
|
+
{
|
55
|
+
if (WIFEXITED(status))
|
56
|
+
return Qtrue;
|
57
|
+
else
|
58
|
+
return Qfalse;
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
* Returns true if _stat_ is successful, false otherwise.
|
63
|
+
* Returns nil if exited? is not true.
|
64
|
+
*/
|
65
|
+
static VALUE pst_success_p(int status)
|
66
|
+
{
|
67
|
+
if (!WIFEXITED(status))
|
68
|
+
return Qnil;
|
69
|
+
return WEXITSTATUS(status) == EXIT_SUCCESS ? Qtrue : Qfalse;
|
70
|
+
}
|
71
|
+
|
72
|
+
/*
|
73
|
+
* Returns true if _stat_ generated a coredump when it terminated. Not
|
74
|
+
* available on all platforms.
|
75
|
+
*/
|
76
|
+
static VALUE pst_wcoredump(int status)
|
77
|
+
{
|
78
|
+
#ifdef WCOREDUMP
|
79
|
+
if (WCOREDUMP(status))
|
80
|
+
return Qtrue;
|
81
|
+
else
|
82
|
+
return Qfalse;
|
83
|
+
#else
|
84
|
+
return Qfalse;
|
85
|
+
#endif
|
86
|
+
}
|
87
|
+
|
88
|
+
/*
|
89
|
+
* Returns the least significant eight bits of the return code of
|
90
|
+
* _stat_. Only available if exited? is true.
|
91
|
+
*/
|
92
|
+
static VALUE pst_wexitstatus(int status)
|
93
|
+
{
|
94
|
+
if (WIFEXITED(status))
|
95
|
+
return INT2NUM(WEXITSTATUS(status));
|
96
|
+
return Qnil;
|
97
|
+
}
|
98
|
+
|
99
|
+
/*
|
100
|
+
* Returns the number of the signal that caused _stat_ to terminate
|
101
|
+
* (or nil if self was not terminated by an uncaught signal).
|
102
|
+
*/
|
103
|
+
static VALUE pst_wtermsig(int status)
|
104
|
+
{
|
105
|
+
if (WIFSIGNALED(status))
|
106
|
+
return INT2NUM(WTERMSIG(status));
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
/*
|
111
|
+
* Returns the number of the signal that caused _stat_ to stop (or nil
|
112
|
+
* if self is not stopped).
|
113
|
+
*/
|
114
|
+
static VALUE pst_wstopsig(int status)
|
115
|
+
{
|
116
|
+
if(WIFSTOPPED(status))
|
117
|
+
return INT2NUM(WSTOPSIG(status));
|
118
|
+
return Qnil;
|
119
|
+
}
|
120
|
+
|
121
|
+
/*
|
122
|
+
* call-seq:
|
123
|
+
* Proc.wait3(flags=nil)
|
124
|
+
*
|
125
|
+
* Delays its caller until a signal is received or one of its child processes
|
126
|
+
* terminates or stops due to tracing.
|
127
|
+
*
|
128
|
+
* The return value is a ProcStat structure. The special global $? is also
|
129
|
+
* set. Raises a SystemError if there are no child processes.
|
130
|
+
*/
|
131
|
+
static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
132
|
+
int status;
|
133
|
+
int flags = 0;
|
134
|
+
struct rusage r;
|
135
|
+
pid_t pid;
|
136
|
+
VALUE v_flags = Qnil;
|
137
|
+
|
138
|
+
rb_scan_args(argc,argv,"01",&v_flags);
|
139
|
+
|
140
|
+
if(Qnil != v_flags){
|
141
|
+
flags = NUM2INT(v_flags);
|
142
|
+
}
|
143
|
+
|
144
|
+
pid = wait3(&status, flags, &r);
|
145
|
+
|
146
|
+
if(pid < 0){
|
147
|
+
rb_sys_fail("wait3");
|
148
|
+
}
|
149
|
+
else if(pid > 0){
|
150
|
+
v_last_status = rb_struct_new(v_procstat_struct,
|
151
|
+
INT2FIX(pid),
|
152
|
+
INT2FIX(status),
|
153
|
+
INT2FIX(r.ru_utime.tv_sec + (r.ru_utime.tv_usec/1000.0)),
|
154
|
+
INT2FIX(r.ru_stime.tv_sec + (r.ru_stime.tv_usec/1000.0)),
|
155
|
+
INT2FIX(r.ru_maxrss),
|
156
|
+
INT2FIX(r.ru_ixrss),
|
157
|
+
INT2FIX(r.ru_idrss),
|
158
|
+
INT2FIX(r.ru_isrss),
|
159
|
+
INT2FIX(r.ru_minflt),
|
160
|
+
INT2FIX(r.ru_majflt),
|
161
|
+
INT2FIX(r.ru_nswap),
|
162
|
+
INT2FIX(r.ru_inblock),
|
163
|
+
INT2FIX(r.ru_oublock),
|
164
|
+
INT2FIX(r.ru_msgsnd),
|
165
|
+
INT2FIX(r.ru_msgrcv),
|
166
|
+
INT2FIX(r.ru_nsignals),
|
167
|
+
INT2FIX(r.ru_nvcsw),
|
168
|
+
INT2FIX(r.ru_nivcsw),
|
169
|
+
pst_wifstopped(status),
|
170
|
+
pst_wifsignaled(status),
|
171
|
+
pst_wifexited(status),
|
172
|
+
pst_success_p(status),
|
173
|
+
pst_wcoredump(status),
|
174
|
+
pst_wexitstatus(status),
|
175
|
+
pst_wtermsig(status),
|
176
|
+
pst_wstopsig(status)
|
177
|
+
);
|
178
|
+
return v_last_status;
|
179
|
+
}
|
180
|
+
else{
|
181
|
+
return Qnil;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
#ifdef HAVE_WAIT4
|
186
|
+
/*
|
187
|
+
* call-seq:
|
188
|
+
* Proc.wait4(pid, flags=0)
|
189
|
+
*
|
190
|
+
* Waits for the given child process to exit. Returns a ProcStat structure.
|
191
|
+
* Also sets the $? special global variable.
|
192
|
+
*
|
193
|
+
* This method is not supported on all platforms.
|
194
|
+
*
|
195
|
+
* Some +flags+ are not supported on all platforms.
|
196
|
+
*/
|
197
|
+
static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
198
|
+
int status;
|
199
|
+
int flags = 0;
|
200
|
+
struct rusage r;
|
201
|
+
pid_t pid;
|
202
|
+
VALUE v_pid;
|
203
|
+
VALUE v_flags = Qnil;
|
204
|
+
|
205
|
+
rb_scan_args(argc, argv, "11", &v_pid, &v_flags);
|
206
|
+
|
207
|
+
pid = NUM2INT(v_pid);
|
208
|
+
|
209
|
+
if(RTEST(v_flags))
|
210
|
+
flags = NUM2INT(v_flags);
|
211
|
+
|
212
|
+
pid = wait4(pid, &status, flags, &r);
|
213
|
+
|
214
|
+
if(pid < 0){
|
215
|
+
rb_sys_fail("wait4");
|
216
|
+
}
|
217
|
+
else if(pid > 0){
|
218
|
+
v_last_status = rb_struct_new(v_procstat_struct,
|
219
|
+
INT2FIX(pid),
|
220
|
+
INT2FIX(status),
|
221
|
+
INT2FIX(r.ru_utime.tv_sec + (r.ru_utime.tv_usec/1000.0)),
|
222
|
+
INT2FIX(r.ru_stime.tv_sec + (r.ru_stime.tv_usec/1000.0)),
|
223
|
+
INT2FIX(r.ru_maxrss),
|
224
|
+
INT2FIX(r.ru_ixrss),
|
225
|
+
INT2FIX(r.ru_idrss),
|
226
|
+
INT2FIX(r.ru_isrss),
|
227
|
+
INT2FIX(r.ru_minflt),
|
228
|
+
INT2FIX(r.ru_majflt),
|
229
|
+
INT2FIX(r.ru_nswap),
|
230
|
+
INT2FIX(r.ru_inblock),
|
231
|
+
INT2FIX(r.ru_oublock),
|
232
|
+
INT2FIX(r.ru_msgsnd),
|
233
|
+
INT2FIX(r.ru_msgrcv),
|
234
|
+
INT2FIX(r.ru_nsignals),
|
235
|
+
INT2FIX(r.ru_nvcsw),
|
236
|
+
INT2FIX(r.ru_nivcsw),
|
237
|
+
pst_wifstopped(status),
|
238
|
+
pst_wifsignaled(status),
|
239
|
+
pst_wifexited(status),
|
240
|
+
pst_success_p(status),
|
241
|
+
pst_wcoredump(status),
|
242
|
+
pst_wexitstatus(status),
|
243
|
+
pst_wtermsig(status),
|
244
|
+
pst_wstopsig(status)
|
245
|
+
);
|
246
|
+
return v_last_status;
|
247
|
+
}
|
248
|
+
else{
|
249
|
+
return Qnil;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
#endif
|
253
|
+
|
254
|
+
#ifdef HAVE_WAITID
|
255
|
+
/*
|
256
|
+
* call-seq:
|
257
|
+
* Proc.waitid(id_type, id_num=nil, options=nil)
|
258
|
+
*
|
259
|
+
* Suspends the calling process until one of its children changes state,
|
260
|
+
* returning immediately if a child process changed state prior to the call.
|
261
|
+
* The state of a child process will change if it terminates, stops because
|
262
|
+
* of a signal, becomes trapped or reaches a breakpoint.
|
263
|
+
*
|
264
|
+
* The +id_num+ argument corresponds to a pid or pgid, depending on the value
|
265
|
+
* of +id_type+, which may be Process::P_PID, Process::P_GID or Process::P_ALL.
|
266
|
+
* If Process::P_ALL, then +id_num+ is ignored.
|
267
|
+
*
|
268
|
+
* The options argument is used to specify which state changes are to be
|
269
|
+
* waited for. It is constructed from the bitwise-OR of one or more of the
|
270
|
+
* following constants:
|
271
|
+
*
|
272
|
+
* Process::WCONTINUED
|
273
|
+
* Process::WEXITED
|
274
|
+
* Process::WNOHANG
|
275
|
+
* Process::WNOWAIT
|
276
|
+
* Process::WSTOPPED
|
277
|
+
* Process::WTRAPPED
|
278
|
+
*
|
279
|
+
* Not all of these constants are supported on all platforms.
|
280
|
+
*
|
281
|
+
* If Process::WNOHANG is set as an option, this method will return
|
282
|
+
* immediately, whether or not a child has changed state.
|
283
|
+
*
|
284
|
+
* Calling this method with an +id_type+ of Process::P_ALL and the options set
|
285
|
+
* to 'Process::WEXITED | Process::WTRAPPED' is equivalent to calling
|
286
|
+
* Process.wait.
|
287
|
+
*
|
288
|
+
* Returns a Proc::SigInfo struct and sets $?.
|
289
|
+
*
|
290
|
+
* Not supported on all platforms.
|
291
|
+
*/
|
292
|
+
static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
293
|
+
VALUE v_type, v_id, v_options;
|
294
|
+
siginfo_t infop;
|
295
|
+
idtype_t idtype;
|
296
|
+
id_t id = 0;
|
297
|
+
int options = 0;
|
298
|
+
|
299
|
+
rb_scan_args(argc, argv, "12", &v_type, &v_id, &v_options);
|
300
|
+
|
301
|
+
idtype = NUM2INT(v_type);
|
302
|
+
|
303
|
+
if(RTEST(v_id))
|
304
|
+
id = NUM2INT(v_id);
|
305
|
+
|
306
|
+
if(RTEST(v_options))
|
307
|
+
options = NUM2INT(v_options);
|
308
|
+
|
309
|
+
/* The Linux man page for waitid() says to zero out the pid field and check
|
310
|
+
* its value after the call to waitid() to detect if there were children in
|
311
|
+
* a waitable state or not (which we do later, below). Other platforms
|
312
|
+
* simply check the infop.si_signo struct member against SI_NOINFO.
|
313
|
+
*/
|
314
|
+
#ifndef SI_NOINFO
|
315
|
+
infop.si_pid = 0;
|
316
|
+
#endif
|
317
|
+
|
318
|
+
if(waitid(idtype, id, &infop, options) == -1)
|
319
|
+
rb_sys_fail("waitid");
|
320
|
+
|
321
|
+
/* If the si_code struct member returns SI_NOINFO, or the si_pid member
|
322
|
+
* is still set to 0 after the call to waitid(), then only the si_signo
|
323
|
+
* member of the struct is meaningful. In that case, we'll set all other
|
324
|
+
* members to nil. Even if this condition doesn't arise, many of the
|
325
|
+
* SigInfo struct members may still be nil, depending on the value of
|
326
|
+
* si_signo.
|
327
|
+
*
|
328
|
+
* See Rich Teer's "Solaris Systems Programming", p 755 ff.
|
329
|
+
*/
|
330
|
+
|
331
|
+
#ifdef SI_NOINFO
|
332
|
+
if(infop.si_code == SI_NOINFO){
|
333
|
+
#else
|
334
|
+
if(infop.si_pid == 0){
|
335
|
+
#endif
|
336
|
+
v_last_status = rb_struct_new(v_siginfo_struct,
|
337
|
+
INT2FIX(infop.si_signo),
|
338
|
+
INT2FIX(infop.si_errno),
|
339
|
+
Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, /* code, pid, uid, utime, status, stime */
|
340
|
+
#ifdef HAVE_ST_SI_TRAPNO
|
341
|
+
Qnil,
|
342
|
+
#endif
|
343
|
+
#ifdef HAVE_ST_SI_PC
|
344
|
+
Qnil,
|
345
|
+
#endif
|
346
|
+
Qnil, Qnil, /* fd, band */
|
347
|
+
#ifdef HAVE_ST_SI_FADDR
|
348
|
+
Qnil,
|
349
|
+
#endif
|
350
|
+
#ifdef HAVE_ST_SI_TSTAMP
|
351
|
+
Qnil,
|
352
|
+
#endif
|
353
|
+
#ifdef HAVE_ST_SI_SYSCALL
|
354
|
+
Qnil,
|
355
|
+
#endif
|
356
|
+
#ifdef HAVE_ST_SI_NSYSARG
|
357
|
+
Qnil,
|
358
|
+
#endif
|
359
|
+
#ifdef HAVE_ST_SI_FAULT
|
360
|
+
Qnil,
|
361
|
+
#endif
|
362
|
+
#ifdef HAVE_ST_SI_SYSARG
|
363
|
+
Qnil,
|
364
|
+
#endif
|
365
|
+
#ifdef HAVE_ST_SI_MSTATE
|
366
|
+
Qnil,
|
367
|
+
#endif
|
368
|
+
Qnil /* entity */
|
369
|
+
);
|
370
|
+
}
|
371
|
+
else{
|
372
|
+
VALUE rbUtime = Qnil, rbStatus = Qnil, rbStime = Qnil, rbFD = Qnil;
|
373
|
+
#ifdef HAVE_ST_SI_TRAPNO
|
374
|
+
VALUE rbTrapno = Qnil;
|
375
|
+
#endif
|
376
|
+
#ifdef HAVE_ST_SI_PC
|
377
|
+
VALUE rbPC = Qnil;
|
378
|
+
#endif
|
379
|
+
#ifdef HAVE_ST_SI_FADDR
|
380
|
+
VALUE rbFaddr = Qnil;
|
381
|
+
#endif
|
382
|
+
#ifdef HAVE_ST_SI_TSTAMP
|
383
|
+
VALUE rbTime = Qnil;
|
384
|
+
#endif
|
385
|
+
#ifdef HAVE_ST_SI_SYSCALL
|
386
|
+
VALUE rbSyscall = Qnil;
|
387
|
+
#endif
|
388
|
+
#ifdef HAVE_ST_SI_NSYSARG
|
389
|
+
VALUE rbNSysarg = Qnil;
|
390
|
+
#endif
|
391
|
+
#ifdef HAVE_ST_SI_FAULT
|
392
|
+
VALUE rbFault = Qnil;
|
393
|
+
#endif
|
394
|
+
#ifdef HAVE_ST_SI_SYSARG
|
395
|
+
VALUE rbSysarg = Qnil;
|
396
|
+
#endif
|
397
|
+
#ifdef HAVE_ST_SI_MSTATE
|
398
|
+
VALUE rbMState = Qnil;
|
399
|
+
#endif
|
400
|
+
VALUE rbBand = Qnil, rbEntity = Qnil;
|
401
|
+
int sig = infop.si_signo;
|
402
|
+
int code = infop.si_code;
|
403
|
+
|
404
|
+
/* If Process.waitid returns because a child process was found that
|
405
|
+
* satisfies the conditions indicated by +id_type+ and +options+, then
|
406
|
+
* the si_signo struct member will always be SIGCHLD.
|
407
|
+
*/
|
408
|
+
if(sig == SIGCHLD){
|
409
|
+
rbUtime = ULL2NUM(infop.si_utime);
|
410
|
+
rbStatus = ULL2NUM(infop.si_status);
|
411
|
+
rbStime = ULL2NUM(infop.si_stime);
|
412
|
+
}
|
413
|
+
|
414
|
+
if(sig == SIGBUS || sig == SIGFPE || sig == SIGILL || sig == SIGSEGV ||
|
415
|
+
sig == SIGTRAP)
|
416
|
+
{
|
417
|
+
#ifdef HAVE_ST_SI_TRAPNO
|
418
|
+
rbTrapno = INT2FIX(infop.si_trapno);
|
419
|
+
#endif
|
420
|
+
#ifdef HAVE_ST_SI_PC
|
421
|
+
rbPC = INT2FIX(infop.si_pc);
|
422
|
+
#endif
|
423
|
+
}
|
424
|
+
|
425
|
+
if(sig == SIGXFSZ){
|
426
|
+
rbFD = INT2FIX(infop.si_fd);
|
427
|
+
if(code == POLL_IN || code == POLL_OUT || code == POLL_MSG){
|
428
|
+
rbBand = LONG2FIX(infop.si_band);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
|
432
|
+
if(sig == SIGPROF){
|
433
|
+
int i = 0;
|
434
|
+
#ifdef HAVE_ST_SI_SYSARG
|
435
|
+
int ssize = sizeof(infop.si_sysarg) / sizeof(infop.si_sysarg[0]);
|
436
|
+
rbSysarg = rb_ary_new();
|
437
|
+
|
438
|
+
for(i = 0; i < ssize; i++)
|
439
|
+
rb_ary_push(rbSysarg, LONG2FIX(infop.si_sysarg[i]));
|
440
|
+
#endif
|
441
|
+
#ifdef HAVE_ST_SI_MSTATE
|
442
|
+
int msize = sizeof(infop.si_mstate) / sizeof(infop.si_mstate[0]);
|
443
|
+
rbMState = rb_ary_new();
|
444
|
+
|
445
|
+
for(i = 0; i < msize; i++)
|
446
|
+
rb_ary_push(rbMState, INT2FIX(infop.si_mstate[i]));
|
447
|
+
#endif
|
448
|
+
#ifdef HAVE_ST_SI_FADDR
|
449
|
+
rbFaddr = INT2FIX(infop.si_faddr);
|
450
|
+
#endif
|
451
|
+
#ifdef HAVE_ST_SI_SYSCALL
|
452
|
+
rbSyscall = INT2FIX(infop.si_syscall);
|
453
|
+
#endif
|
454
|
+
#ifdef HAVE_ST_SI_NSYSARG
|
455
|
+
rbNSysarg = INT2FIX(infop.si_nsysarg);
|
456
|
+
#endif
|
457
|
+
#ifdef HAVE_ST_SI_FAULT
|
458
|
+
rbFault = INT2FIX(infop.si_fault);
|
459
|
+
#endif
|
460
|
+
#ifdef HAVE_ST_SI_TSTAMP
|
461
|
+
rbTime = rb_time_new(infop.si_tstamp.tv_sec,infop.si_tstamp.tv_nsec);
|
462
|
+
#endif
|
463
|
+
}
|
464
|
+
|
465
|
+
#ifdef SIGXRES
|
466
|
+
if(sig == SIGXRES){
|
467
|
+
rbEntity = INT2FIX(infop.si_entity);
|
468
|
+
}
|
469
|
+
#endif
|
470
|
+
|
471
|
+
v_last_status = rb_struct_new(v_siginfo_struct,
|
472
|
+
INT2FIX(infop.si_signo), /* Probably SIGCHLD */
|
473
|
+
INT2FIX(infop.si_errno), /* 0 means no error */
|
474
|
+
INT2FIX(infop.si_code), /* Should be anything but SI_NOINFO */
|
475
|
+
INT2FIX(infop.si_pid), /* Real PID that sent the signal */
|
476
|
+
INT2FIX(infop.si_uid), /* Real UID of process that sent signal */
|
477
|
+
rbUtime,
|
478
|
+
rbStatus,
|
479
|
+
rbStime,
|
480
|
+
#ifdef HAVE_ST_SI_TRAPNO
|
481
|
+
rbTrapno,
|
482
|
+
#endif
|
483
|
+
#ifdef HAVE_ST_SI_PC
|
484
|
+
rbPC,
|
485
|
+
#endif
|
486
|
+
rbFD,
|
487
|
+
rbBand,
|
488
|
+
#ifdef HAVE_ST_SI_FADDR
|
489
|
+
rbFaddr,
|
490
|
+
#endif
|
491
|
+
#ifdef HAVE_ST_SI_TSTAMP
|
492
|
+
rbTime,
|
493
|
+
#endif
|
494
|
+
#ifdef HAVE_ST_SI_SYSCALL
|
495
|
+
rbSyscall,
|
496
|
+
#endif
|
497
|
+
#ifdef HAVE_ST_SI_NSYSARG
|
498
|
+
rbNSysarg,
|
499
|
+
#endif
|
500
|
+
#ifdef HAVE_ST_SI_FAULT
|
501
|
+
rbFault,
|
502
|
+
#endif
|
503
|
+
#ifdef HAVE_ST_SI_SYSARG
|
504
|
+
rbSysarg,
|
505
|
+
#endif
|
506
|
+
#ifdef HAVE_ST_SI_MSTATE
|
507
|
+
rbMState,
|
508
|
+
#endif
|
509
|
+
rbEntity
|
510
|
+
);
|
511
|
+
}
|
512
|
+
|
513
|
+
return v_last_status;
|
514
|
+
}
|
515
|
+
#endif
|
516
|
+
|
517
|
+
/*
|
518
|
+
* call-seq:
|
519
|
+
* Process.pause(signals=nil)
|
520
|
+
*
|
521
|
+
* Pauses the current process. If the process receives any of the +signals+
|
522
|
+
* you pass as arguments it will return from the pause and continue with
|
523
|
+
* the execution of your code. Otherwise, it will exit.
|
524
|
+
*
|
525
|
+
* Note that you must leave out the 'SIG' prefix for the signal name, e.g.
|
526
|
+
* use 'INT', not 'SIGINT'.
|
527
|
+
*
|
528
|
+
* Returns the result of the pause() function, which should always be -1.
|
529
|
+
*/
|
530
|
+
static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
531
|
+
VALUE v_signals;
|
532
|
+
int i, len;
|
533
|
+
|
534
|
+
rb_scan_args(argc, argv, "0*", &v_signals);
|
535
|
+
|
536
|
+
/* Iterate over each signal, calling sigset for each one */
|
537
|
+
len = RARRAY(v_signals)->len;
|
538
|
+
if(len > 0){
|
539
|
+
VALUE v_val;
|
540
|
+
char signame[SIG2STR_MAX];
|
541
|
+
unsigned int max = SIG2STR_MAX;
|
542
|
+
int signum;
|
543
|
+
|
544
|
+
for(i = 0; i < len; i++){
|
545
|
+
v_val = rb_ary_shift(v_signals);
|
546
|
+
|
547
|
+
if(strlcpy(signame, StringValuePtr(v_val), max) >= max)
|
548
|
+
rb_raise(rb_eArgError, "string too large");
|
549
|
+
|
550
|
+
if(str2sig(signame, &signum) != 0)
|
551
|
+
rb_sys_fail("pause");
|
552
|
+
|
553
|
+
sigset(signum, sigproc);
|
554
|
+
}
|
555
|
+
}
|
556
|
+
|
557
|
+
return INT2FIX(pause()); /* Should always be -1 */
|
558
|
+
}
|
559
|
+
|
560
|
+
/*
|
561
|
+
* This is just a placeholder proc to prevent the "pause" method from exiting
|
562
|
+
* the program if the appropriate signal is intercepted.
|
563
|
+
*/
|
564
|
+
static void sigproc(int signum){ /* Do nothing */ }
|
565
|
+
|
566
|
+
#ifdef HAVE_SIGSEND
|
567
|
+
/*
|
568
|
+
* call-seq:
|
569
|
+
* Process.sigsend(idtype, id, signal=0)
|
570
|
+
*
|
571
|
+
* Sends a signal of type +idtype+ to a process or process group. This is
|
572
|
+
* more versatile method of sending signals to processes than Process.kill.
|
573
|
+
*
|
574
|
+
* The idtype * must be one of the following values:
|
575
|
+
*
|
576
|
+
* * Process::P_ALL
|
577
|
+
* All non-system processes. The +id+ is ignored.
|
578
|
+
*
|
579
|
+
* * Process::P_CID
|
580
|
+
* Any process whose scheduler class ID is equal to +id+.
|
581
|
+
*
|
582
|
+
* * Process::P_GID
|
583
|
+
* Any non-system process whose effective group ID is equal to +id+.
|
584
|
+
*
|
585
|
+
* * Process::P_PGID
|
586
|
+
* Any non-system process whose process group ID is equal to +id+.
|
587
|
+
*
|
588
|
+
* * Process::P_PID
|
589
|
+
* The process ID equal to +id+.
|
590
|
+
*
|
591
|
+
* * Process::P_PROJID
|
592
|
+
* All processes whose project ID id equal to +id+. Solaris 8 or later
|
593
|
+
* only.
|
594
|
+
*
|
595
|
+
* * Process::P_SID
|
596
|
+
* Any non-system process whose session ID is equal to +id+.
|
597
|
+
*
|
598
|
+
* * Process::P_TASKID
|
599
|
+
* All processes whose task ID is equal to +id+. Solaris 8 or later
|
600
|
+
* only.
|
601
|
+
*
|
602
|
+
* * Process::P_UID
|
603
|
+
* Any non-system process whose effective user ID is equal to +id+.
|
604
|
+
*/
|
605
|
+
static VALUE proc_sigsend(int argc, VALUE* argv, VALUE mod){
|
606
|
+
VALUE v_type, v_pid, v_signal;
|
607
|
+
idtype_t idtype;
|
608
|
+
id_t id;
|
609
|
+
int sig = 0; /* 0 is our default signal (i.e. no signal) */
|
610
|
+
|
611
|
+
rb_scan_args(argc, argv, "21", &v_type, &v_pid, &v_signal);
|
612
|
+
|
613
|
+
idtype = NUM2INT(v_type);
|
614
|
+
id = NUM2INT(v_pid);
|
615
|
+
|
616
|
+
if(!NIL_P(v_signal)){
|
617
|
+
if(TYPE(v_signal) == T_FIXNUM){
|
618
|
+
sig = FIX2INT(v_signal);
|
619
|
+
}
|
620
|
+
else{
|
621
|
+
char signame[SIG2STR_MAX];
|
622
|
+
unsigned int max = SIG2STR_MAX;
|
623
|
+
|
624
|
+
if(strlcpy(signame, StringValuePtr(v_signal), max) >= max)
|
625
|
+
rb_raise(rb_eArgError, "string too large");
|
626
|
+
|
627
|
+
if(str2sig(signame,&sig) != 0)
|
628
|
+
rb_sys_fail("str2sig");
|
629
|
+
}
|
630
|
+
}
|
631
|
+
|
632
|
+
if(sigsend(idtype,id,sig) != 0)
|
633
|
+
rb_sys_fail("sigsend");
|
634
|
+
|
635
|
+
return Qnil;
|
636
|
+
}
|
637
|
+
#endif
|
638
|
+
|
639
|
+
#ifdef HAVE_GETRUSAGE
|
640
|
+
/*
|
641
|
+
* call-seq:
|
642
|
+
* Process.getrusage(children=false)
|
643
|
+
*
|
644
|
+
* Returns comprehensive process resource usage information in the form of a
|
645
|
+
* RUsage struct. By default, this will return information for the current
|
646
|
+
* process. If +children+ is set to true, it will return information for
|
647
|
+
* terminated and waited for children of the current process.
|
648
|
+
*
|
649
|
+
* The RUsage struct contains the following members:
|
650
|
+
*
|
651
|
+
* * utime - User time
|
652
|
+
* * stime - System time
|
653
|
+
* * maxrss - Maximum resident set size
|
654
|
+
* * intrss - Integral shared memory size
|
655
|
+
* * idrss - Integral unshared data size
|
656
|
+
* * isrss - Integral unshared statck size
|
657
|
+
* * minflt - Minor page faults
|
658
|
+
* * majflt - Major page faults
|
659
|
+
* * nswap - Number of swaps
|
660
|
+
* * inblock - Block input operations
|
661
|
+
* * oublock - Block output operations
|
662
|
+
* * msgsnd - Messages sent
|
663
|
+
* * msgrcv - Messages received
|
664
|
+
* * nsignals - Number of signals received
|
665
|
+
* * nvcsw - Voluntary context switches
|
666
|
+
* * nivcsw - Involuntary context switches
|
667
|
+
*
|
668
|
+
* Note that not all members contain meaningful values on all platforms.
|
669
|
+
*/
|
670
|
+
static VALUE proc_getrusage(int argc, VALUE* argv, VALUE mod){
|
671
|
+
VALUE v_children = Qfalse;
|
672
|
+
struct rusage r;
|
673
|
+
int who = RUSAGE_SELF;
|
674
|
+
|
675
|
+
rb_scan_args(argc, argv, "01", &v_children);
|
676
|
+
|
677
|
+
if(Qtrue == v_children)
|
678
|
+
who = RUSAGE_CHILDREN;
|
679
|
+
|
680
|
+
if(getrusage(who,&r) == -1)
|
681
|
+
rb_sys_fail("getrusage");
|
682
|
+
|
683
|
+
return rb_struct_new(v_usage_struct,
|
684
|
+
LONG2FIX(r.ru_utime.tv_sec),
|
685
|
+
LONG2FIX(r.ru_stime.tv_sec),
|
686
|
+
LONG2FIX(r.ru_maxrss),
|
687
|
+
LONG2FIX(r.ru_ixrss),
|
688
|
+
LONG2FIX(r.ru_idrss),
|
689
|
+
LONG2FIX(r.ru_isrss),
|
690
|
+
LONG2FIX(r.ru_minflt),
|
691
|
+
LONG2FIX(r.ru_majflt),
|
692
|
+
LONG2FIX(r.ru_nswap),
|
693
|
+
LONG2FIX(r.ru_inblock),
|
694
|
+
LONG2FIX(r.ru_oublock),
|
695
|
+
LONG2FIX(r.ru_msgsnd),
|
696
|
+
LONG2FIX(r.ru_msgrcv),
|
697
|
+
LONG2FIX(r.ru_nsignals),
|
698
|
+
LONG2FIX(r.ru_nvcsw),
|
699
|
+
LONG2FIX(r.ru_nivcsw)
|
700
|
+
);
|
701
|
+
}
|
702
|
+
#endif
|
703
|
+
|
704
|
+
/*
|
705
|
+
* call-seq:
|
706
|
+
* Process.getrlimit(resource)
|
707
|
+
*
|
708
|
+
* Returns a two element array consisting of the hard and soft limit
|
709
|
+
* for the current process for the given +resource+. The array consists of
|
710
|
+
* either numeric values or the word "infinite".
|
711
|
+
*/
|
712
|
+
static VALUE proc_getrlimit(VALUE mod, VALUE rbResource){
|
713
|
+
struct rlimit limits;
|
714
|
+
VALUE v_array = rb_ary_new();
|
715
|
+
|
716
|
+
rb_secure(2);
|
717
|
+
|
718
|
+
if(getrlimit(NUM2INT(rbResource), &limits) < 0)
|
719
|
+
rb_sys_fail("getrlimit");
|
720
|
+
|
721
|
+
if(limits.rlim_cur == RLIM_INFINITY)
|
722
|
+
rb_ary_push(v_array, rb_str_new2("infinity"));
|
723
|
+
else
|
724
|
+
rb_ary_push(v_array, INT2FIX(limits.rlim_cur));
|
725
|
+
|
726
|
+
if(limits.rlim_max == RLIM_INFINITY)
|
727
|
+
rb_ary_push(v_array, rb_str_new2("infinity"));
|
728
|
+
else
|
729
|
+
rb_ary_push(v_array, INT2FIX(limits.rlim_max));
|
730
|
+
|
731
|
+
return v_array;
|
732
|
+
}
|
733
|
+
|
734
|
+
/*
|
735
|
+
* call-seq;
|
736
|
+
* Process.setrlimit(resource, current, max)
|
737
|
+
*
|
738
|
+
* Sets the current (soft) and max (hard) limit for the given +resource+ for
|
739
|
+
* the current process.
|
740
|
+
*/
|
741
|
+
static VALUE proc_setrlimit(VALUE mod, VALUE rbRes, VALUE rbCur, VALUE rbMax){
|
742
|
+
struct rlimit limits;
|
743
|
+
|
744
|
+
rb_secure(2);
|
745
|
+
|
746
|
+
limits.rlim_cur = NUM2INT(rbCur);
|
747
|
+
limits.rlim_max = NUM2INT(rbMax);
|
748
|
+
|
749
|
+
if(setrlimit(NUM2INT(rbRes), &limits) == -1)
|
750
|
+
rb_sys_fail("setrlimit");
|
751
|
+
|
752
|
+
return Qnil;
|
753
|
+
}
|
754
|
+
|
755
|
+
/*
|
756
|
+
* Adds the wait3, wait4, waitid, pause, sigsend, and getrusage methods to the
|
757
|
+
* Process module.
|
758
|
+
*/
|
759
|
+
void Init_wait3()
|
760
|
+
{
|
761
|
+
v_procstat_struct =
|
762
|
+
rb_struct_define("ProcStat","pid","status","utime","stime","maxrss",
|
763
|
+
"ixrss", "idrss", "isrss", "minflt","majflt","nswap","inblock",
|
764
|
+
"oublock","msgsnd", "msgrcv","nsignals","nvcsw","nivcsw","stopped",
|
765
|
+
"signaled","exited","success","coredump","exitstatus","termsig",
|
766
|
+
"stopsig",NULL
|
767
|
+
);
|
768
|
+
|
769
|
+
rb_define_module_function(rb_mProcess, "wait3", proc_wait3, -1);
|
770
|
+
rb_define_module_function(rb_mProcess, "pause", proc_pause, -1);
|
771
|
+
rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
|
772
|
+
rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, 3);
|
773
|
+
|
774
|
+
#ifdef HAVE_SIGSEND
|
775
|
+
rb_define_module_function(rb_mProcess, "sigsend", proc_sigsend, -1);
|
776
|
+
#endif
|
777
|
+
|
778
|
+
#ifdef HAVE_WAIT4
|
779
|
+
rb_define_module_function(rb_mProcess, "wait4", proc_wait4, -1);
|
780
|
+
#endif
|
781
|
+
|
782
|
+
#ifdef HAVE_GETRUSAGE
|
783
|
+
v_usage_struct =
|
784
|
+
rb_struct_define("RUsage","utime","stime","maxrss","ixrss","idrss",
|
785
|
+
"isrss","minflt","majflt","nswap","inblock","oublock","msgsnd",
|
786
|
+
"msgrcv","nsignals","nvcsw","nivcsw",NULL
|
787
|
+
);
|
788
|
+
|
789
|
+
rb_define_module_function(rb_mProcess, "getrusage", proc_getrusage, -1);
|
790
|
+
#endif
|
791
|
+
|
792
|
+
#ifdef HAVE_WAITID
|
793
|
+
v_siginfo_struct =
|
794
|
+
rb_struct_define("SigInfo","signo","errno","code","pid","uid",
|
795
|
+
"utime","status","stime"
|
796
|
+
#ifdef HAVE_ST_SI_TRAPNO
|
797
|
+
,"trapno"
|
798
|
+
#endif
|
799
|
+
#ifdef HAVE_ST_SI_PC
|
800
|
+
,"pc"
|
801
|
+
#endif
|
802
|
+
,"fd","band"
|
803
|
+
#ifdef HAVE_ST_SI_FADDR
|
804
|
+
,"faddr"
|
805
|
+
#endif
|
806
|
+
#ifdef HAVE_ST_SI_TSTAMP
|
807
|
+
,"tstamp"
|
808
|
+
#endif
|
809
|
+
#ifdef HAVE_ST_SI_SYSCALL
|
810
|
+
,"syscall"
|
811
|
+
#endif
|
812
|
+
#ifdef HAVE_ST_SI_NSYSARG
|
813
|
+
,"nsysarg"
|
814
|
+
#endif
|
815
|
+
#ifdef HAVE_ST_SI_FAULT
|
816
|
+
,"fault"
|
817
|
+
#endif
|
818
|
+
#ifdef HAVE_ST_SI_SYSARG
|
819
|
+
,"sysarg"
|
820
|
+
#endif
|
821
|
+
#ifdef HAVE_ST_SI_MSTATE
|
822
|
+
,"mstate"
|
823
|
+
#endif
|
824
|
+
,"entity", NULL
|
825
|
+
);
|
826
|
+
|
827
|
+
rb_define_module_function(rb_mProcess, "waitid", proc_waitid, -1);
|
828
|
+
|
829
|
+
#ifdef WCONTINUED
|
830
|
+
rb_define_const(rb_mProcess, "WCONTINUED", INT2FIX(WCONTINUED));
|
831
|
+
#endif
|
832
|
+
|
833
|
+
#ifdef WEXITED
|
834
|
+
rb_define_const(rb_mProcess, "WEXITED", INT2FIX(WEXITED));
|
835
|
+
#endif
|
836
|
+
|
837
|
+
#ifdef WNOWAIT
|
838
|
+
rb_define_const(rb_mProcess, "WNOWAIT", INT2FIX(WNOWAIT));
|
839
|
+
#endif
|
840
|
+
|
841
|
+
#ifdef WSTOPPED
|
842
|
+
rb_define_const(rb_mProcess, "WSTOPPED", INT2FIX(WSTOPPED));
|
843
|
+
#endif
|
844
|
+
|
845
|
+
#ifdef WTRAPPED
|
846
|
+
rb_define_const(rb_mProcess, "WTRAPPED", INT2FIX(WTRAPPED));
|
847
|
+
#endif
|
848
|
+
#endif
|
849
|
+
|
850
|
+
/* Because core Ruby already defines a Process::GID and Process::UID,
|
851
|
+
* I am forced to keep the leading 'P_' for these constants.
|
852
|
+
*/
|
853
|
+
rb_define_const(rb_mProcess, "P_ALL", INT2FIX(P_ALL));
|
854
|
+
rb_define_const(rb_mProcess, "P_PGID", INT2FIX(P_PGID));
|
855
|
+
rb_define_const(rb_mProcess, "P_PID", INT2FIX(P_PID));
|
856
|
+
|
857
|
+
#ifdef HAVE_CONST_P_CID
|
858
|
+
rb_define_const(rb_mProcess, "P_CID", INT2FIX(P_CID));
|
859
|
+
#endif
|
860
|
+
|
861
|
+
#ifdef HAVE_CONST_P_GID
|
862
|
+
rb_define_const(rb_mProcess, "P_GID", INT2FIX(P_GID));
|
863
|
+
#endif
|
864
|
+
|
865
|
+
#ifdef HAVE_CONST_P_MYID
|
866
|
+
rb_define_const(rb_mProcess, "P_MYID", INT2FIX(P_MYID));
|
867
|
+
#endif
|
868
|
+
|
869
|
+
#ifdef HAVE_CONST_P_SID
|
870
|
+
rb_define_const(rb_mProcess, "P_SID", INT2FIX(P_SID));
|
871
|
+
#endif
|
872
|
+
|
873
|
+
#ifdef HAVE_CONST_P_UID
|
874
|
+
rb_define_const(rb_mProcess, "P_UID", INT2FIX(P_UID));
|
875
|
+
#endif
|
876
|
+
|
877
|
+
#ifdef HAVE_CONST_P_TASKID
|
878
|
+
rb_define_const(rb_mProcess, "P_TASKID", INT2FIX(P_TASKID));
|
879
|
+
#endif
|
880
|
+
|
881
|
+
#ifdef HAVE_CONST_P_PROJID
|
882
|
+
rb_define_const(rb_mProcess, "P_PROJID", INT2FIX(P_PROJID));
|
883
|
+
#endif
|
884
|
+
|
885
|
+
/* Constants for getrlimit, setrlimit. It appears that these are defined
|
886
|
+
* by Ruby as of 1.8.5. Assume that if RLIMIT_AS is defined, all the
|
887
|
+
* standard rlimit constants are defined.
|
888
|
+
*/
|
889
|
+
#ifndef RLIMIT_AS
|
890
|
+
rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
|
891
|
+
rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
|
892
|
+
rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
|
893
|
+
rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
|
894
|
+
rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
|
895
|
+
rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
|
896
|
+
rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
|
897
|
+
rb_define_const(rb_mProcess, "RLIM_INFINITY", UINT2NUM(RLIM_INFINITY));
|
898
|
+
rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", UINT2NUM(RLIM_SAVED_MAX));
|
899
|
+
rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", UINT2NUM(RLIM_SAVED_CUR));
|
900
|
+
#endif
|
901
|
+
|
902
|
+
#ifdef RLIMIT_VMEM
|
903
|
+
rb_define_const(rb_mProcess, "RLIMIT_VMEM", INT2FIX(RLIMIT_VMEM));
|
904
|
+
#endif
|
905
|
+
|
906
|
+
/* Define this last in our Init_wait3 function */
|
907
|
+
rb_define_readonly_variable("$?", &v_last_status);
|
908
|
+
}
|