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.
Files changed (7) hide show
  1. data/CHANGES +61 -0
  2. data/README +53 -0
  3. data/doc/wait3.txt +154 -0
  4. data/extconf.rb +54 -0
  5. data/lib/proc/wait3.c +908 -0
  6. data/test/tc_wait3.rb +199 -0
  7. 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.
@@ -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
@@ -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")
@@ -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
+ }