proc-wait3 1.9.2 → 2.0.0
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +17 -1
- data/Rakefile +15 -10
- data/doc/wait3.md +7 -0
- data/examples/example_waitid.rb +14 -4
- data/ext/proc/wait3.c +298 -120
- data/proc-wait3.gemspec +3 -2
- data/spec/proc_wait3_spec.rb +64 -91
- data/spec/spec_helper.rb +16 -0
- data.tar.gz.sig +0 -0
- metadata +5 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bba2d43b0af474f64ee8879055afc649a62afed46269bafc2bea754eb2ab770b
|
|
4
|
+
data.tar.gz: 0b5e3a6ebc48e370c32273db28e107c068a70e08f367031011bb0c1d1c2065a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e31e23649b03fcff7e274634536c6c5924ff9e0cecb52141c34a694c71a3817a00dded441394b9dbd3f7266818c4ec2ca41a41e7b347b63cdad148ab43a7a28b
|
|
7
|
+
data.tar.gz: 86d669dfe0d6e0dcbe3b136c4b857a52039c53f61de0b0a3cbed9f36bc274ce9c6487136c3e52f112e2f8cd2c2414acae64f239426a69e84a3d976047021e1d2
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 2.0.0 - 10-Jan-2026
|
|
2
|
+
* Added fiber scheduler support for wait3 and wait4 methods, allowing them
|
|
3
|
+
to cooperate with Ruby's fiber scheduler for non-blocking async operations.
|
|
4
|
+
Note that rusage fields will be zero when using the fiber scheduler path.
|
|
5
|
+
* Added `rb_thread_call_without_gvl` for blocking calls so that other Ruby
|
|
6
|
+
threads can run while waiting.
|
|
7
|
+
* Added `RB_GC_GUARD` to protect Ruby objects during blocking operations.
|
|
8
|
+
* Replaced deprecated `RSTRING()->len` and `RSTRING()->ptr` with `RSTRING_LEN()`
|
|
9
|
+
and `RSTRING_PTR()` macros.
|
|
10
|
+
* Added missing `HAVE_STRLCPY` guard in sigsend with strncpy fallback.
|
|
11
|
+
* Fixed some minor whitespace inconsistencies.
|
|
12
|
+
* Now requires Ruby 3.1 or later.
|
|
13
|
+
|
|
14
|
+
## 1.9.3 - 4-May-2024
|
|
15
|
+
* Some internal refactoring where I bzero C structs before using them.
|
|
16
|
+
|
|
1
17
|
## 1.9.2 - 21-Apr-2024
|
|
2
18
|
* Added the P_JAILID constant for BSD platforms.
|
|
3
19
|
* Added some notes to the README for coping with EINTR.
|
|
@@ -154,7 +170,7 @@
|
|
|
154
170
|
* Updated tests and documentation.
|
|
155
171
|
|
|
156
172
|
## 1.2.0 - 7-Feb-2005
|
|
157
|
-
* Added the Proc.waitid method (for those platforms that support it).
|
|
173
|
+
* Added the Proc.waitid method (for those platforms that support it).
|
|
158
174
|
* Made the wait3.c file more rdoc friendly.
|
|
159
175
|
* Added a test_waitid.rb file in the examples directory.
|
|
160
176
|
|
data/Rakefile
CHANGED
|
@@ -7,17 +7,17 @@ require 'rbconfig'
|
|
|
7
7
|
include RbConfig
|
|
8
8
|
|
|
9
9
|
CLEAN.include(
|
|
10
|
-
'**/*.gem',
|
|
11
|
-
'**/*.rbc',
|
|
12
|
-
'**/*.o',
|
|
13
|
-
'**/*.log',
|
|
14
|
-
'
|
|
15
|
-
'**/
|
|
16
|
-
|
|
17
|
-
'
|
|
10
|
+
'**/*.gem', # Gem files
|
|
11
|
+
'**/*.rbc', # Rubinius
|
|
12
|
+
'**/*.o', # C object file
|
|
13
|
+
'**/*.log', # Ruby extension build log
|
|
14
|
+
'**/*.lock', # Gemfile.lock
|
|
15
|
+
'**/Makefile', # C Makefile
|
|
16
|
+
'**/*.dSYM', # OS X build directory
|
|
17
|
+
"**/*.#{CONFIG['DLEXT']}", # C shared object
|
|
18
|
+
'**/*.lock' # Bundler
|
|
18
19
|
)
|
|
19
20
|
|
|
20
|
-
|
|
21
21
|
desc "Build the source (but don't install it)"
|
|
22
22
|
task :build => [:clean] do |t|
|
|
23
23
|
Dir.chdir('ext') do
|
|
@@ -72,7 +72,12 @@ end
|
|
|
72
72
|
|
|
73
73
|
desc 'Run the test suite'
|
|
74
74
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
75
|
-
t.rspec_opts = '-Iext'
|
|
75
|
+
t.rspec_opts = '-Iext -f documentation -w'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Clean up afterwards
|
|
79
|
+
Rake::Task[:spec].enhance do
|
|
80
|
+
Rake::Task[:clean].invoke
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
task :default => [:build, :spec]
|
data/doc/wait3.md
CHANGED
|
@@ -80,6 +80,13 @@ Returns a `Proc::SigInfo` struct and sets `$?`.
|
|
|
80
80
|
|
|
81
81
|
Not supported on all platforms.
|
|
82
82
|
|
|
83
|
+
### `Proc.getdtablesize`
|
|
84
|
+
|
|
85
|
+
Returns the current soft limit of the maximum file descriptor number.
|
|
86
|
+
|
|
87
|
+
This is effectively the same as calling Process.getrlimit with RLIMIT_NOFILE
|
|
88
|
+
as the resource identifier.
|
|
89
|
+
|
|
83
90
|
## Standard Constants
|
|
84
91
|
`Process::WAIT3_VERSION`
|
|
85
92
|
|
data/examples/example_waitid.rb
CHANGED
|
@@ -8,10 +8,20 @@
|
|
|
8
8
|
#
|
|
9
9
|
# Modify as you see fit.
|
|
10
10
|
#######################################################################
|
|
11
|
-
require 'English'
|
|
12
11
|
require 'proc/wait3'
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
pid1 = fork { puts "PID1 GRP: #{Process.getpgrp}"; sleep 2 }
|
|
14
|
+
pid2 = fork { puts "PID2 GRP: #{Process.getpgrp}"; sleep 3 }
|
|
15
|
+
pid3 = fork { puts "PID2 GRP: #{Process.getpgrp}"; sleep 4 }
|
|
16
|
+
|
|
17
|
+
puts "PID1: #{pid1}"
|
|
18
|
+
puts "PID2: #{pid2}"
|
|
19
|
+
puts "PID3: #{pid3}"
|
|
20
|
+
|
|
21
|
+
puts "MAIN GRP: #{Process.getpgrp}"
|
|
15
22
|
p Time.now
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
|
|
24
|
+
status = Process.waitid(Process::P_PGID, Process.getpgrp, Process::WEXITED)
|
|
25
|
+
|
|
26
|
+
# status.pid should equal pid1 since it exits first
|
|
27
|
+
p status
|
data/ext/proc/wait3.c
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
|
+
#include <ruby/thread.h>
|
|
3
|
+
#include <ruby/fiber/scheduler.h>
|
|
2
4
|
#include <string.h>
|
|
3
5
|
#include <unistd.h>
|
|
4
6
|
|
|
@@ -31,6 +33,67 @@ VALUE v_procstat_struct, v_siginfo_struct, v_usage_struct;
|
|
|
31
33
|
|
|
32
34
|
static void sigproc(int signum, siginfo_t* info, void* ucontext);
|
|
33
35
|
|
|
36
|
+
/* Structs for rb_thread_call_without_gvl wrappers */
|
|
37
|
+
struct wait3_args {
|
|
38
|
+
int status;
|
|
39
|
+
int flags;
|
|
40
|
+
struct rusage rusage;
|
|
41
|
+
pid_t pid;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
#ifdef HAVE_WAIT4
|
|
45
|
+
struct wait4_args {
|
|
46
|
+
pid_t pid;
|
|
47
|
+
int status;
|
|
48
|
+
int flags;
|
|
49
|
+
struct rusage rusage;
|
|
50
|
+
pid_t result;
|
|
51
|
+
};
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#ifdef HAVE_WAITID
|
|
55
|
+
struct waitid_args {
|
|
56
|
+
idtype_t idtype;
|
|
57
|
+
id_t id;
|
|
58
|
+
siginfo_t infop;
|
|
59
|
+
int options;
|
|
60
|
+
int result;
|
|
61
|
+
};
|
|
62
|
+
#endif
|
|
63
|
+
|
|
64
|
+
struct pause_args {
|
|
65
|
+
int result;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/* GVL-free wrapper functions */
|
|
69
|
+
static void* wait3_without_gvl(void* data) {
|
|
70
|
+
struct wait3_args* args = (struct wait3_args*)data;
|
|
71
|
+
args->pid = wait3(&args->status, args->flags, &args->rusage);
|
|
72
|
+
return NULL;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#ifdef HAVE_WAIT4
|
|
76
|
+
static void* wait4_without_gvl(void* data) {
|
|
77
|
+
struct wait4_args* args = (struct wait4_args*)data;
|
|
78
|
+
args->result = wait4(args->pid, &args->status, args->flags, &args->rusage);
|
|
79
|
+
return NULL;
|
|
80
|
+
}
|
|
81
|
+
#endif
|
|
82
|
+
|
|
83
|
+
#ifdef HAVE_WAITID
|
|
84
|
+
static void* waitid_without_gvl(void* data) {
|
|
85
|
+
struct waitid_args* args = (struct waitid_args*)data;
|
|
86
|
+
args->result = waitid(args->idtype, args->id, &args->infop, args->options);
|
|
87
|
+
return NULL;
|
|
88
|
+
}
|
|
89
|
+
#endif
|
|
90
|
+
|
|
91
|
+
static void* pause_without_gvl(void* data) {
|
|
92
|
+
struct pause_args* args = (struct pause_args*)data;
|
|
93
|
+
args->result = pause();
|
|
94
|
+
return NULL;
|
|
95
|
+
}
|
|
96
|
+
|
|
34
97
|
/*
|
|
35
98
|
* Returns true if this process is stopped. This is only returned
|
|
36
99
|
* returned if the corresponding wait() call had the WUNTRACED flag
|
|
@@ -38,10 +101,10 @@ static void sigproc(int signum, siginfo_t* info, void* ucontext);
|
|
|
38
101
|
*/
|
|
39
102
|
static VALUE pst_wifstopped(int status)
|
|
40
103
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
104
|
+
if(WIFSTOPPED(status))
|
|
105
|
+
return Qtrue;
|
|
106
|
+
else
|
|
107
|
+
return Qfalse;
|
|
45
108
|
}
|
|
46
109
|
|
|
47
110
|
/*
|
|
@@ -50,7 +113,7 @@ static VALUE pst_wifstopped(int status)
|
|
|
50
113
|
static VALUE pst_wifsignaled(int status)
|
|
51
114
|
{
|
|
52
115
|
if (WIFSIGNALED(status))
|
|
53
|
-
|
|
116
|
+
return Qtrue;
|
|
54
117
|
else
|
|
55
118
|
return Qfalse;
|
|
56
119
|
}
|
|
@@ -131,6 +194,42 @@ static VALUE pst_wstopsig(int status)
|
|
|
131
194
|
return Qnil;
|
|
132
195
|
}
|
|
133
196
|
|
|
197
|
+
/*
|
|
198
|
+
* Helper to build ProcStat struct from pid and status.
|
|
199
|
+
* Used by fiber scheduler path where rusage is not available.
|
|
200
|
+
* All rusage fields are set to 0.
|
|
201
|
+
*/
|
|
202
|
+
static VALUE build_procstat_without_rusage(pid_t pid, int status) {
|
|
203
|
+
return rb_struct_new(v_procstat_struct,
|
|
204
|
+
INT2FIX(pid),
|
|
205
|
+
INT2FIX(status),
|
|
206
|
+
rb_float_new(0.0), /* utime - not available via fiber scheduler */
|
|
207
|
+
rb_float_new(0.0), /* stime - not available via fiber scheduler */
|
|
208
|
+
LONG2NUM(0), /* maxrss */
|
|
209
|
+
LONG2NUM(0), /* ixrss */
|
|
210
|
+
LONG2NUM(0), /* idrss */
|
|
211
|
+
LONG2NUM(0), /* isrss */
|
|
212
|
+
LONG2NUM(0), /* minflt */
|
|
213
|
+
LONG2NUM(0), /* majflt */
|
|
214
|
+
LONG2NUM(0), /* nswap */
|
|
215
|
+
LONG2NUM(0), /* inblock */
|
|
216
|
+
LONG2NUM(0), /* oublock */
|
|
217
|
+
LONG2NUM(0), /* msgsnd */
|
|
218
|
+
LONG2NUM(0), /* msgrcv */
|
|
219
|
+
LONG2NUM(0), /* nsignals */
|
|
220
|
+
LONG2NUM(0), /* nvcsw */
|
|
221
|
+
LONG2NUM(0), /* nivcsw */
|
|
222
|
+
pst_wifstopped(status),
|
|
223
|
+
pst_wifsignaled(status),
|
|
224
|
+
pst_wifexited(status),
|
|
225
|
+
pst_success_p(status),
|
|
226
|
+
pst_wcoredump(status),
|
|
227
|
+
pst_wexitstatus(status),
|
|
228
|
+
pst_wtermsig(status),
|
|
229
|
+
pst_wstopsig(status)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
134
233
|
/*
|
|
135
234
|
* call-seq:
|
|
136
235
|
* Process.wait3(flags=nil)
|
|
@@ -140,13 +239,15 @@ static VALUE pst_wstopsig(int status)
|
|
|
140
239
|
*
|
|
141
240
|
* The return value is a ProcStat structure. The special global $? is also
|
|
142
241
|
* set. Raises a SystemError if there are no child processes.
|
|
242
|
+
*
|
|
243
|
+
* Note: When a fiber scheduler is active (Ruby 3.0+), this method will
|
|
244
|
+
* cooperate with the scheduler. However, rusage information will not be
|
|
245
|
+
* available and those fields will be set to 0 in the returned struct.
|
|
143
246
|
*/
|
|
144
247
|
static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
145
|
-
|
|
146
|
-
int flags = 0;
|
|
147
|
-
struct rusage r;
|
|
148
|
-
pid_t pid;
|
|
248
|
+
struct wait3_args args;
|
|
149
249
|
VALUE v_flags = Qnil;
|
|
250
|
+
int flags = 0;
|
|
150
251
|
|
|
151
252
|
rb_scan_args(argc,argv,"01",&v_flags);
|
|
152
253
|
|
|
@@ -154,42 +255,68 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
154
255
|
flags = NUM2INT(v_flags);
|
|
155
256
|
}
|
|
156
257
|
|
|
157
|
-
|
|
258
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
259
|
+
if (!NIL_P(scheduler)) {
|
|
260
|
+
/* Use fiber scheduler - wait for any child (pid = -1) */
|
|
261
|
+
VALUE result = rb_fiber_scheduler_process_wait(scheduler, (rb_pid_t)-1, flags);
|
|
262
|
+
|
|
263
|
+
if (NIL_P(result)) {
|
|
264
|
+
return Qnil;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* Extract pid and status from Process::Status object */
|
|
268
|
+
pid_t pid = NUM2PIDT(rb_funcall(result, rb_intern("pid"), 0));
|
|
269
|
+
int status = NUM2INT(rb_funcall(result, rb_intern("to_i"), 0));
|
|
270
|
+
|
|
271
|
+
RB_GC_GUARD(result);
|
|
272
|
+
|
|
273
|
+
v_last_status = build_procstat_without_rusage(pid, status);
|
|
274
|
+
rb_last_status_set(status, pid);
|
|
275
|
+
OBJ_FREEZE(v_last_status);
|
|
276
|
+
|
|
277
|
+
return v_last_status;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* No fiber scheduler - use thread-based blocking */
|
|
281
|
+
bzero(&args, sizeof(args));
|
|
282
|
+
args.flags = flags;
|
|
283
|
+
|
|
284
|
+
rb_thread_call_without_gvl(wait3_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
158
285
|
|
|
159
|
-
if(pid < 0){
|
|
286
|
+
if(args.pid < 0){
|
|
160
287
|
rb_sys_fail("wait3");
|
|
161
288
|
}
|
|
162
|
-
else if(pid > 0){
|
|
289
|
+
else if(args.pid > 0){
|
|
163
290
|
v_last_status = rb_struct_new(v_procstat_struct,
|
|
164
|
-
INT2FIX(pid),
|
|
165
|
-
INT2FIX(status),
|
|
166
|
-
rb_float_new((double)
|
|
167
|
-
rb_float_new((double)
|
|
168
|
-
LONG2NUM(
|
|
169
|
-
LONG2NUM(
|
|
170
|
-
LONG2NUM(
|
|
171
|
-
LONG2NUM(
|
|
172
|
-
LONG2NUM(
|
|
173
|
-
LONG2NUM(
|
|
174
|
-
LONG2NUM(
|
|
175
|
-
LONG2NUM(
|
|
176
|
-
LONG2NUM(
|
|
177
|
-
LONG2NUM(
|
|
178
|
-
LONG2NUM(
|
|
179
|
-
LONG2NUM(
|
|
180
|
-
LONG2NUM(
|
|
181
|
-
LONG2NUM(
|
|
182
|
-
pst_wifstopped(status),
|
|
183
|
-
pst_wifsignaled(status),
|
|
184
|
-
pst_wifexited(status),
|
|
185
|
-
pst_success_p(status),
|
|
186
|
-
pst_wcoredump(status),
|
|
187
|
-
pst_wexitstatus(status),
|
|
188
|
-
pst_wtermsig(status),
|
|
189
|
-
pst_wstopsig(status)
|
|
291
|
+
INT2FIX(args.pid),
|
|
292
|
+
INT2FIX(args.status),
|
|
293
|
+
rb_float_new((double)args.rusage.ru_utime.tv_sec+(double)args.rusage.ru_utime.tv_usec/1e6),
|
|
294
|
+
rb_float_new((double)args.rusage.ru_stime.tv_sec+(double)args.rusage.ru_stime.tv_usec/1e6),
|
|
295
|
+
LONG2NUM(args.rusage.ru_maxrss),
|
|
296
|
+
LONG2NUM(args.rusage.ru_ixrss),
|
|
297
|
+
LONG2NUM(args.rusage.ru_idrss),
|
|
298
|
+
LONG2NUM(args.rusage.ru_isrss),
|
|
299
|
+
LONG2NUM(args.rusage.ru_minflt),
|
|
300
|
+
LONG2NUM(args.rusage.ru_majflt),
|
|
301
|
+
LONG2NUM(args.rusage.ru_nswap),
|
|
302
|
+
LONG2NUM(args.rusage.ru_inblock),
|
|
303
|
+
LONG2NUM(args.rusage.ru_oublock),
|
|
304
|
+
LONG2NUM(args.rusage.ru_msgsnd),
|
|
305
|
+
LONG2NUM(args.rusage.ru_msgrcv),
|
|
306
|
+
LONG2NUM(args.rusage.ru_nsignals),
|
|
307
|
+
LONG2NUM(args.rusage.ru_nvcsw),
|
|
308
|
+
LONG2NUM(args.rusage.ru_nivcsw),
|
|
309
|
+
pst_wifstopped(args.status),
|
|
310
|
+
pst_wifsignaled(args.status),
|
|
311
|
+
pst_wifexited(args.status),
|
|
312
|
+
pst_success_p(args.status),
|
|
313
|
+
pst_wcoredump(args.status),
|
|
314
|
+
pst_wexitstatus(args.status),
|
|
315
|
+
pst_wtermsig(args.status),
|
|
316
|
+
pst_wstopsig(args.status)
|
|
190
317
|
);
|
|
191
318
|
|
|
192
|
-
rb_last_status_set(status, pid);
|
|
319
|
+
rb_last_status_set(args.status, args.pid);
|
|
193
320
|
OBJ_FREEZE(v_last_status);
|
|
194
321
|
|
|
195
322
|
return v_last_status;
|
|
@@ -210,58 +337,88 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
210
337
|
* This method is not supported on all platforms.
|
|
211
338
|
*
|
|
212
339
|
* Some +flags+ are not supported on all platforms.
|
|
340
|
+
*
|
|
341
|
+
* Note: When a fiber scheduler is active (Ruby 3.0+), this method will
|
|
342
|
+
* cooperate with the scheduler. However, rusage information will not be
|
|
343
|
+
* available and those fields will be set to 0 in the returned struct.
|
|
213
344
|
*/
|
|
214
345
|
static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
215
|
-
|
|
216
|
-
int flags = 0;
|
|
217
|
-
struct rusage r;
|
|
218
|
-
pid_t pid;
|
|
346
|
+
struct wait4_args args;
|
|
219
347
|
VALUE v_pid;
|
|
220
348
|
VALUE v_flags = Qnil;
|
|
349
|
+
pid_t pid;
|
|
350
|
+
int flags = 0;
|
|
221
351
|
|
|
222
352
|
rb_scan_args(argc, argv, "11", &v_pid, &v_flags);
|
|
223
353
|
|
|
224
|
-
pid =
|
|
354
|
+
pid = NUM2PIDT(v_pid);
|
|
225
355
|
|
|
226
356
|
if(RTEST(v_flags))
|
|
227
357
|
flags = NUM2INT(v_flags);
|
|
228
358
|
|
|
229
|
-
|
|
359
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
360
|
+
if (!NIL_P(scheduler)) {
|
|
361
|
+
/* Use fiber scheduler */
|
|
362
|
+
VALUE result = rb_fiber_scheduler_process_wait(scheduler, pid, flags);
|
|
363
|
+
|
|
364
|
+
if (NIL_P(result)) {
|
|
365
|
+
return Qnil;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Extract pid and status from Process::Status object */
|
|
369
|
+
pid_t rpid = NUM2PIDT(rb_funcall(result, rb_intern("pid"), 0));
|
|
370
|
+
int status = NUM2INT(rb_funcall(result, rb_intern("to_i"), 0));
|
|
230
371
|
|
|
231
|
-
|
|
372
|
+
RB_GC_GUARD(result);
|
|
373
|
+
|
|
374
|
+
v_last_status = build_procstat_without_rusage(rpid, status);
|
|
375
|
+
rb_last_status_set(status, rpid);
|
|
376
|
+
OBJ_FREEZE(v_last_status);
|
|
377
|
+
|
|
378
|
+
return v_last_status;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* No fiber scheduler - use thread-based blocking */
|
|
382
|
+
bzero(&args, sizeof(args));
|
|
383
|
+
args.pid = pid;
|
|
384
|
+
args.flags = flags;
|
|
385
|
+
|
|
386
|
+
rb_thread_call_without_gvl(wait4_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
387
|
+
|
|
388
|
+
if(args.result < 0){
|
|
232
389
|
rb_sys_fail("wait4");
|
|
233
390
|
}
|
|
234
|
-
else if(
|
|
391
|
+
else if(args.result > 0){
|
|
235
392
|
v_last_status = rb_struct_new(v_procstat_struct,
|
|
236
|
-
INT2FIX(
|
|
237
|
-
INT2FIX(status),
|
|
238
|
-
rb_float_new((double)
|
|
239
|
-
rb_float_new((double)
|
|
240
|
-
LONG2NUM(
|
|
241
|
-
LONG2NUM(
|
|
242
|
-
LONG2NUM(
|
|
243
|
-
LONG2NUM(
|
|
244
|
-
LONG2NUM(
|
|
245
|
-
LONG2NUM(
|
|
246
|
-
LONG2NUM(
|
|
247
|
-
LONG2NUM(
|
|
248
|
-
LONG2NUM(
|
|
249
|
-
LONG2NUM(
|
|
250
|
-
LONG2NUM(
|
|
251
|
-
LONG2NUM(
|
|
252
|
-
LONG2NUM(
|
|
253
|
-
LONG2NUM(
|
|
254
|
-
pst_wifstopped(status),
|
|
255
|
-
pst_wifsignaled(status),
|
|
256
|
-
pst_wifexited(status),
|
|
257
|
-
pst_success_p(status),
|
|
258
|
-
pst_wcoredump(status),
|
|
259
|
-
pst_wexitstatus(status),
|
|
260
|
-
pst_wtermsig(status),
|
|
261
|
-
pst_wstopsig(status)
|
|
393
|
+
INT2FIX(args.result),
|
|
394
|
+
INT2FIX(args.status),
|
|
395
|
+
rb_float_new((double)args.rusage.ru_utime.tv_sec+(double)args.rusage.ru_utime.tv_usec/1e6),
|
|
396
|
+
rb_float_new((double)args.rusage.ru_stime.tv_sec+(double)args.rusage.ru_stime.tv_usec/1e6),
|
|
397
|
+
LONG2NUM(args.rusage.ru_maxrss),
|
|
398
|
+
LONG2NUM(args.rusage.ru_ixrss),
|
|
399
|
+
LONG2NUM(args.rusage.ru_idrss),
|
|
400
|
+
LONG2NUM(args.rusage.ru_isrss),
|
|
401
|
+
LONG2NUM(args.rusage.ru_minflt),
|
|
402
|
+
LONG2NUM(args.rusage.ru_majflt),
|
|
403
|
+
LONG2NUM(args.rusage.ru_nswap),
|
|
404
|
+
LONG2NUM(args.rusage.ru_inblock),
|
|
405
|
+
LONG2NUM(args.rusage.ru_oublock),
|
|
406
|
+
LONG2NUM(args.rusage.ru_msgsnd),
|
|
407
|
+
LONG2NUM(args.rusage.ru_msgrcv),
|
|
408
|
+
LONG2NUM(args.rusage.ru_nsignals),
|
|
409
|
+
LONG2NUM(args.rusage.ru_nvcsw),
|
|
410
|
+
LONG2NUM(args.rusage.ru_nivcsw),
|
|
411
|
+
pst_wifstopped(args.status),
|
|
412
|
+
pst_wifsignaled(args.status),
|
|
413
|
+
pst_wifexited(args.status),
|
|
414
|
+
pst_success_p(args.status),
|
|
415
|
+
pst_wcoredump(args.status),
|
|
416
|
+
pst_wexitstatus(args.status),
|
|
417
|
+
pst_wtermsig(args.status),
|
|
418
|
+
pst_wstopsig(args.status)
|
|
262
419
|
);
|
|
263
420
|
|
|
264
|
-
rb_last_status_set(status,
|
|
421
|
+
rb_last_status_set(args.status, args.result);
|
|
265
422
|
OBJ_FREEZE(v_last_status);
|
|
266
423
|
|
|
267
424
|
return v_last_status;
|
|
@@ -312,20 +469,18 @@ static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
|
312
469
|
*/
|
|
313
470
|
static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
314
471
|
VALUE v_type, v_id, v_options;
|
|
315
|
-
|
|
316
|
-
idtype_t idtype;
|
|
317
|
-
id_t id = 0;
|
|
318
|
-
int options = 0;
|
|
472
|
+
struct waitid_args args;
|
|
319
473
|
|
|
320
474
|
rb_scan_args(argc, argv, "12", &v_type, &v_id, &v_options);
|
|
321
475
|
|
|
322
|
-
|
|
476
|
+
bzero(&args, sizeof(args));
|
|
477
|
+
args.idtype = NUM2INT(v_type);
|
|
323
478
|
|
|
324
479
|
if(RTEST(v_id))
|
|
325
|
-
id = NUM2INT(v_id);
|
|
480
|
+
args.id = NUM2INT(v_id);
|
|
326
481
|
|
|
327
482
|
if(RTEST(v_options))
|
|
328
|
-
options = NUM2INT(v_options);
|
|
483
|
+
args.options = NUM2INT(v_options);
|
|
329
484
|
|
|
330
485
|
/* The Linux man page for waitid() says to zero out the pid field and check
|
|
331
486
|
* its value after the call to waitid() to detect if there were children in
|
|
@@ -333,10 +488,12 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
333
488
|
* simply check the infop.si_signo struct member against SI_NOINFO.
|
|
334
489
|
*/
|
|
335
490
|
#ifndef SI_NOINFO
|
|
336
|
-
infop.si_pid = 0;
|
|
491
|
+
args.infop.si_pid = 0;
|
|
337
492
|
#endif
|
|
338
493
|
|
|
339
|
-
|
|
494
|
+
rb_thread_call_without_gvl(waitid_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
495
|
+
|
|
496
|
+
if(args.result == -1)
|
|
340
497
|
rb_sys_fail("waitid");
|
|
341
498
|
|
|
342
499
|
/* If the si_code struct member returns SI_NOINFO, or the si_pid member
|
|
@@ -350,13 +507,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
350
507
|
*/
|
|
351
508
|
|
|
352
509
|
#ifdef SI_NOINFO
|
|
353
|
-
if(infop.si_code == SI_NOINFO){
|
|
510
|
+
if(args.infop.si_code == SI_NOINFO){
|
|
354
511
|
#else
|
|
355
|
-
if(infop.si_pid == 0){
|
|
512
|
+
if(args.infop.si_pid == 0){
|
|
356
513
|
#endif
|
|
357
514
|
v_last_status = rb_struct_new(v_siginfo_struct,
|
|
358
|
-
INT2FIX(infop.si_signo),
|
|
359
|
-
INT2FIX(infop.si_errno),
|
|
515
|
+
INT2FIX(args.infop.si_signo),
|
|
516
|
+
INT2FIX(args.infop.si_errno),
|
|
360
517
|
Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, /* code, pid, uid, utime, status, stime */
|
|
361
518
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
362
519
|
Qnil,
|
|
@@ -422,8 +579,8 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
422
579
|
VALUE v_state = Qnil;
|
|
423
580
|
#endif
|
|
424
581
|
VALUE v_band = Qnil, v_entity = Qnil;
|
|
425
|
-
int sig = infop.si_signo;
|
|
426
|
-
int code = infop.si_code;
|
|
582
|
+
int sig = args.infop.si_signo;
|
|
583
|
+
int code = args.infop.si_code;
|
|
427
584
|
|
|
428
585
|
#if defined(HAVE_ST_SI_SYSARG) || defined(HAVE_ST_SI_MSTATE)
|
|
429
586
|
int i = 0;
|
|
@@ -435,13 +592,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
435
592
|
*/
|
|
436
593
|
if(sig == SIGCHLD){
|
|
437
594
|
#ifdef HAVE_ST_SI_UTIME
|
|
438
|
-
v_utime = ULL2NUM(infop.si_utime);
|
|
595
|
+
v_utime = ULL2NUM(args.infop.si_utime);
|
|
439
596
|
#endif
|
|
440
597
|
#ifdef HAVE_ST_SI_STATUS
|
|
441
|
-
v_status = ULL2NUM(infop.si_status);
|
|
598
|
+
v_status = ULL2NUM(args.infop.si_status);
|
|
442
599
|
#endif
|
|
443
600
|
#ifdef HAVE_ST_SI_STIME
|
|
444
|
-
v_stime = ULL2NUM(infop.si_stime);
|
|
601
|
+
v_stime = ULL2NUM(args.infop.si_stime);
|
|
445
602
|
#endif
|
|
446
603
|
}
|
|
447
604
|
|
|
@@ -449,66 +606,66 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
449
606
|
sig == SIGTRAP)
|
|
450
607
|
{
|
|
451
608
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
452
|
-
v_trapno = INT2FIX(infop.si_trapno);
|
|
609
|
+
v_trapno = INT2FIX(args.infop.si_trapno);
|
|
453
610
|
#endif
|
|
454
611
|
#ifdef HAVE_ST_SI_PC
|
|
455
|
-
v_pc = INT2FIX(infop.si_pc);
|
|
612
|
+
v_pc = INT2FIX(args.infop.si_pc);
|
|
456
613
|
#endif
|
|
457
614
|
}
|
|
458
615
|
|
|
459
616
|
if(sig == SIGXFSZ){
|
|
460
617
|
#ifdef HAVE_ST_SI_FD
|
|
461
|
-
v_fd = INT2FIX(infop.si_fd);
|
|
618
|
+
v_fd = INT2FIX(args.infop.si_fd);
|
|
462
619
|
#endif
|
|
463
620
|
if(code == POLL_IN || code == POLL_OUT || code == POLL_MSG){
|
|
464
|
-
v_band = LONG2FIX(infop.si_band);
|
|
621
|
+
v_band = LONG2FIX(args.infop.si_band);
|
|
465
622
|
}
|
|
466
623
|
}
|
|
467
624
|
|
|
468
625
|
if(sig == SIGPROF){
|
|
469
626
|
#ifdef HAVE_ST_SI_SYSARG
|
|
470
|
-
int ssize = sizeof(infop.si_sysarg) / sizeof(infop.si_sysarg[0]);
|
|
627
|
+
int ssize = sizeof(args.infop.si_sysarg) / sizeof(args.infop.si_sysarg[0]);
|
|
471
628
|
v_sysarg = rb_ary_new();
|
|
472
629
|
|
|
473
630
|
for(i = 0; i < ssize; i++)
|
|
474
|
-
rb_ary_push(v_sysarg, LONG2FIX(infop.si_sysarg[i]));
|
|
631
|
+
rb_ary_push(v_sysarg, LONG2FIX(args.infop.si_sysarg[i]));
|
|
475
632
|
#endif
|
|
476
633
|
#ifdef HAVE_ST_SI_MSTATE
|
|
477
|
-
int msize = sizeof(infop.si_mstate) / sizeof(infop.si_mstate[0]);
|
|
634
|
+
int msize = sizeof(args.infop.si_mstate) / sizeof(args.infop.si_mstate[0]);
|
|
478
635
|
v_state = rb_ary_new();
|
|
479
636
|
|
|
480
637
|
for(i = 0; i < msize; i++)
|
|
481
|
-
rb_ary_push(v_state, INT2FIX(infop.si_mstate[i]));
|
|
638
|
+
rb_ary_push(v_state, INT2FIX(args.infop.si_mstate[i]));
|
|
482
639
|
#endif
|
|
483
640
|
#ifdef HAVE_ST_SI_FADDR
|
|
484
|
-
v_addr = INT2FIX(infop.si_faddr);
|
|
641
|
+
v_addr = INT2FIX(args.infop.si_faddr);
|
|
485
642
|
#endif
|
|
486
643
|
#ifdef HAVE_ST_SI_SYSCALL
|
|
487
|
-
v_syscall = INT2FIX(infop.si_syscall);
|
|
644
|
+
v_syscall = INT2FIX(args.infop.si_syscall);
|
|
488
645
|
#endif
|
|
489
646
|
#ifdef HAVE_ST_SI_NSYSARG
|
|
490
|
-
v_nsysarg = INT2FIX(infop.si_nsysarg);
|
|
647
|
+
v_nsysarg = INT2FIX(args.infop.si_nsysarg);
|
|
491
648
|
#endif
|
|
492
649
|
#ifdef HAVE_ST_SI_FAULT
|
|
493
|
-
v_fault = INT2FIX(infop.si_fault);
|
|
650
|
+
v_fault = INT2FIX(args.infop.si_fault);
|
|
494
651
|
#endif
|
|
495
652
|
#ifdef HAVE_ST_SI_TSTAMP
|
|
496
|
-
v_time = rb_time_new(infop.si_tstamp.tv_sec,infop.si_tstamp.tv_nsec);
|
|
653
|
+
v_time = rb_time_new(args.infop.si_tstamp.tv_sec,args.infop.si_tstamp.tv_nsec);
|
|
497
654
|
#endif
|
|
498
655
|
}
|
|
499
656
|
|
|
500
657
|
#ifdef SIGXRES
|
|
501
658
|
if(sig == SIGXRES){
|
|
502
|
-
v_entity = INT2FIX(infop.si_entity);
|
|
659
|
+
v_entity = INT2FIX(args.infop.si_entity);
|
|
503
660
|
}
|
|
504
661
|
#endif
|
|
505
662
|
|
|
506
663
|
v_last_status = rb_struct_new(v_siginfo_struct,
|
|
507
|
-
INT2FIX(infop.si_signo), // Probably SIGCHLD
|
|
508
|
-
INT2FIX(infop.si_errno), // 0 means no error
|
|
509
|
-
INT2FIX(infop.si_code), // Should be anything but SI_NOINFO
|
|
510
|
-
INT2FIX(infop.si_pid), // Real PID that sent the signal
|
|
511
|
-
INT2FIX(infop.si_uid), // Real UID of process that sent signal
|
|
664
|
+
INT2FIX(args.infop.si_signo), // Probably SIGCHLD
|
|
665
|
+
INT2FIX(args.infop.si_errno), // 0 means no error
|
|
666
|
+
INT2FIX(args.infop.si_code), // Should be anything but SI_NOINFO
|
|
667
|
+
INT2FIX(args.infop.si_pid), // Real PID that sent the signal
|
|
668
|
+
INT2FIX(args.infop.si_uid), // Real UID of process that sent signal
|
|
512
669
|
v_utime,
|
|
513
670
|
v_status,
|
|
514
671
|
v_stime,
|
|
@@ -564,7 +721,7 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
564
721
|
* be sure to leave off the leading 'SIG' substring, e.g. use 'INT' instead
|
|
565
722
|
* of 'SIGINT'.
|
|
566
723
|
*
|
|
567
|
-
* Note that not all platforms (notably Linux)
|
|
724
|
+
* Note that not all platforms (notably Linux) support automatically
|
|
568
725
|
* converting strings to their corresponding signal values, so it is
|
|
569
726
|
* recommended that you always use an array of numeric values.
|
|
570
727
|
*
|
|
@@ -587,6 +744,9 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
587
744
|
int signum;
|
|
588
745
|
struct sigaction act, sa;
|
|
589
746
|
|
|
747
|
+
bzero(&act, sizeof(act));
|
|
748
|
+
bzero(&sa, sizeof(sa));
|
|
749
|
+
|
|
590
750
|
for(i = 0; i < len; i++){
|
|
591
751
|
v_val = rb_ary_shift(v_signals);
|
|
592
752
|
|
|
@@ -595,10 +755,12 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
595
755
|
if(strlcpy(signame, StringValuePtr(v_val), max) >= max)
|
|
596
756
|
rb_raise(rb_eArgError, "string too large");
|
|
597
757
|
#else
|
|
598
|
-
if(
|
|
758
|
+
if(RSTRING_LEN(v_val) >= max)
|
|
599
759
|
rb_raise(rb_eArgError, "string too large");
|
|
600
|
-
else
|
|
601
|
-
strncpy(signame,
|
|
760
|
+
else{
|
|
761
|
+
strncpy(signame, RSTRING_PTR(v_val), max);
|
|
762
|
+
signame[max-1] = '\0';
|
|
763
|
+
}
|
|
602
764
|
#endif
|
|
603
765
|
|
|
604
766
|
#ifdef HAVE_STR2SIG
|
|
@@ -614,17 +776,22 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
614
776
|
signum = NUM2INT(v_val);
|
|
615
777
|
}
|
|
616
778
|
|
|
617
|
-
|
|
779
|
+
bzero(&act, sizeof(act));
|
|
618
780
|
act.sa_flags = SA_SIGINFO;
|
|
619
781
|
act.sa_sigaction = sigproc;
|
|
620
782
|
res = sigaction(signum, &act, &sa);
|
|
621
783
|
|
|
622
784
|
if(res)
|
|
623
|
-
|
|
785
|
+
rb_sys_fail("sigaction");
|
|
624
786
|
}
|
|
625
787
|
}
|
|
626
788
|
|
|
627
|
-
|
|
789
|
+
{
|
|
790
|
+
struct pause_args pargs;
|
|
791
|
+
rb_thread_call_without_gvl(pause_without_gvl, &pargs, RUBY_UBF_PROCESS, NULL);
|
|
792
|
+
RB_GC_GUARD(v_signals);
|
|
793
|
+
return INT2FIX(pargs.result); /* Should always be -1 */
|
|
794
|
+
}
|
|
628
795
|
}
|
|
629
796
|
|
|
630
797
|
/*
|
|
@@ -691,8 +858,17 @@ static VALUE proc_sigsend(int argc, VALUE* argv, VALUE mod){
|
|
|
691
858
|
char signame[SIG2STR_MAX];
|
|
692
859
|
unsigned int max = SIG2STR_MAX;
|
|
693
860
|
|
|
861
|
+
#ifdef HAVE_STRLCPY
|
|
694
862
|
if(strlcpy(signame, StringValuePtr(v_signal), max) >= max)
|
|
695
863
|
rb_raise(rb_eArgError, "string too large");
|
|
864
|
+
#else
|
|
865
|
+
if(RSTRING_LEN(v_signal) >= max)
|
|
866
|
+
rb_raise(rb_eArgError, "string too large");
|
|
867
|
+
else{
|
|
868
|
+
strncpy(signame, RSTRING_PTR(v_signal), max);
|
|
869
|
+
signame[max-1] = '\0';
|
|
870
|
+
}
|
|
871
|
+
#endif
|
|
696
872
|
|
|
697
873
|
if(str2sig(signame,&sig) != 0)
|
|
698
874
|
rb_sys_fail("str2sig");
|
|
@@ -752,6 +928,8 @@ static VALUE proc_getrusage(int argc, VALUE* argv, VALUE mod){
|
|
|
752
928
|
else if(RTEST(v_children))
|
|
753
929
|
who = RUSAGE_CHILDREN;
|
|
754
930
|
|
|
931
|
+
bzero(&r, sizeof(r));
|
|
932
|
+
|
|
755
933
|
if(getrusage(who,&r) == -1)
|
|
756
934
|
rb_sys_fail("getrusage");
|
|
757
935
|
|
|
@@ -966,8 +1144,8 @@ void Init_wait3(void)
|
|
|
966
1144
|
rb_define_const(rb_mProcess, "RUSAGE_THREAD", INT2FIX(RUSAGE_THREAD));
|
|
967
1145
|
#endif
|
|
968
1146
|
|
|
969
|
-
/*
|
|
970
|
-
rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("
|
|
1147
|
+
/* 2.0.0: The version of the proc-wait3 library */
|
|
1148
|
+
rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("2.0.0")));
|
|
971
1149
|
|
|
972
1150
|
/* Define this last in our Init_wait3 function */
|
|
973
1151
|
rb_define_readonly_variable("$last_status", &v_last_status);
|
data/proc-wait3.gemspec
CHANGED
|
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = 'proc-wait3'
|
|
5
|
-
spec.version = '
|
|
5
|
+
spec.version = '2.0.0'
|
|
6
6
|
spec.author = 'Daniel J. Berger'
|
|
7
7
|
spec.license = 'Apache-2.0'
|
|
8
8
|
spec.email = 'djberg96@gmail.com'
|
|
@@ -26,7 +26,8 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
'source_code_uri' => 'https://github.com/djberg96/proc-wait3',
|
|
27
27
|
'wiki_uri' => 'https://github.com/djberg96/proc-wait3/wiki',
|
|
28
28
|
'rubygems_mfa_required' => 'true',
|
|
29
|
-
'github_repo' => 'https://github.com/djberg96/proc-wait3'
|
|
29
|
+
'github_repo' => 'https://github.com/djberg96/proc-wait3',
|
|
30
|
+
'funding_uri' => 'https://github.com/sponsors/djberg96'
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
spec.description = <<-EOF
|
data/spec/proc_wait3_spec.rb
CHANGED
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
##############################################################################
|
|
4
4
|
# proc_wait3_spec.rb
|
|
5
5
|
#
|
|
6
|
-
# Test suite for the Ruby proc-wait3 library. You should run these
|
|
7
|
-
#
|
|
8
|
-
|
|
6
|
+
# Test suite for the Ruby proc-wait3 library. You should run these via the
|
|
7
|
+
# 'rake spec' task.
|
|
8
|
+
#
|
|
9
|
+
# Note that several specs are deliberately wrapped in EINTR rescue handlers
|
|
10
|
+
# because I think the Ruby interpreter is sending a signal to the process
|
|
11
|
+
# from somewhere in the guts of its core code. Originally I thought this was
|
|
12
|
+
# a SIGCHLD but it doesn't always appear to be.
|
|
13
|
+
##############################################################################
|
|
9
14
|
require 'English'
|
|
10
|
-
require '
|
|
11
|
-
require 'rspec'
|
|
15
|
+
require 'spec_helper'
|
|
12
16
|
require 'rbconfig'
|
|
13
17
|
|
|
14
18
|
RSpec.describe Process do
|
|
15
|
-
# Something in the guts of Ruby was being a pain.
|
|
16
|
-
Signal.trap('CHLD', 'IGNORE') if RUBY_VERSION.to_f < 3
|
|
17
|
-
|
|
18
|
-
let(:solaris) { RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i }
|
|
19
|
-
let(:darwin) { RbConfig::CONFIG['host_os'] =~ /darwin|osx/i }
|
|
20
|
-
let(:hpux) { RbConfig::CONFIG['host_os'] =~ /hpux/i }
|
|
21
|
-
let(:linux) { RbConfig::CONFIG['host_os'] =~ /linux/i }
|
|
22
|
-
let(:bsd) { RbConfig::CONFIG['host_os'] =~ /bsd|dragonfly/i }
|
|
23
|
-
|
|
24
19
|
let(:proc_stat_members) {
|
|
25
20
|
%i[
|
|
26
21
|
pid status utime stime maxrss ixrss idrss isrss minflt majflt nswap
|
|
@@ -34,8 +29,26 @@ RSpec.describe Process do
|
|
|
34
29
|
@pid = nil
|
|
35
30
|
end
|
|
36
31
|
|
|
32
|
+
def call_wait3
|
|
33
|
+
described_class.wait3
|
|
34
|
+
rescue Errno::EINTR
|
|
35
|
+
retry
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def call_wait4(*args)
|
|
39
|
+
described_class.wait4(*args)
|
|
40
|
+
rescue Errno::EINTR
|
|
41
|
+
retry
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def call_waitid(*args)
|
|
45
|
+
described_class.waitid(*args)
|
|
46
|
+
rescue Errno::EINTR
|
|
47
|
+
retry
|
|
48
|
+
end
|
|
49
|
+
|
|
37
50
|
example 'version constant is set to expected value' do
|
|
38
|
-
expect(Process::WAIT3_VERSION).to eq('
|
|
51
|
+
expect(Process::WAIT3_VERSION).to eq('2.0.0')
|
|
39
52
|
expect(Process::WAIT3_VERSION).to be_frozen
|
|
40
53
|
end
|
|
41
54
|
|
|
@@ -44,15 +57,13 @@ RSpec.describe Process do
|
|
|
44
57
|
end
|
|
45
58
|
|
|
46
59
|
example 'wait3 works as expected' do
|
|
47
|
-
skip 'wait3 test skipped on this platform' if darwin
|
|
48
60
|
@pid = fork { sleep 0.5 }
|
|
49
|
-
expect {
|
|
61
|
+
expect { call_wait3 }.not_to raise_error
|
|
50
62
|
end
|
|
51
63
|
|
|
52
64
|
example 'wait3 returns the expected proc status members' do
|
|
53
|
-
skip 'wait3 test skipped on this platform' if darwin
|
|
54
65
|
@pid = fork { sleep 0.5 }
|
|
55
|
-
expect { @proc_stat =
|
|
66
|
+
expect { @proc_stat = call_wait3 }.not_to raise_error
|
|
56
67
|
expect(@proc_stat.members).to eq(proc_stat_members)
|
|
57
68
|
end
|
|
58
69
|
|
|
@@ -62,116 +73,89 @@ RSpec.describe Process do
|
|
|
62
73
|
end
|
|
63
74
|
|
|
64
75
|
example 'wait3 sets and returns $last_status to expected values' do
|
|
65
|
-
skip 'wait3 test skipped on this platform' if darwin
|
|
66
76
|
@pid = fork { sleep 0.5 }
|
|
67
|
-
|
|
77
|
+
call_wait3
|
|
68
78
|
expect($last_status).to be_a(Struct::ProcStat)
|
|
69
79
|
expect($last_status).not_to be_nil
|
|
70
80
|
end
|
|
71
81
|
|
|
72
82
|
example 'wait3 sets pid and status members of $?' do
|
|
73
|
-
skip 'wait3 test skipped on this platform' if darwin
|
|
74
83
|
@pid = fork { sleep 0.5 }
|
|
75
|
-
|
|
84
|
+
call_wait3
|
|
76
85
|
expect($CHILD_STATUS).not_to be_nil
|
|
77
86
|
end
|
|
78
87
|
|
|
79
88
|
example 'wait3 returns frozen struct' do
|
|
80
|
-
skip 'wait3 test skipped on this platform' if darwin
|
|
81
89
|
@pid = fork { sleep 0.5 }
|
|
82
|
-
struct =
|
|
90
|
+
struct = call_wait3
|
|
83
91
|
expect(struct).to be_frozen
|
|
84
92
|
end
|
|
85
93
|
|
|
86
|
-
example 'getdtablesize works as expected' do
|
|
87
|
-
skip 'getdtablesize skipped on this platform' unless solaris
|
|
88
|
-
|
|
94
|
+
example 'getdtablesize works as expected', :solaris do
|
|
89
95
|
expect(described_class).to respond_to(:getdtablesize)
|
|
90
96
|
expect(described_class.getdtablesize).to be_a(Integer)
|
|
91
97
|
assert(described_class.getdtablesize > 0)
|
|
92
98
|
end
|
|
93
99
|
|
|
94
|
-
example 'wait4 method is defined' do
|
|
95
|
-
skip 'wait4 test skipped on this platform' if hpux
|
|
100
|
+
example 'wait4 method is defined', :skip_hpux do
|
|
96
101
|
expect(described_class).to respond_to(:wait4)
|
|
97
102
|
end
|
|
98
103
|
|
|
99
|
-
example 'wait4 requires at least one argument' do
|
|
100
|
-
|
|
101
|
-
expect { described_class.wait4 }.to raise_error(ArgumentError)
|
|
104
|
+
example 'wait4 requires at least one argument', :skip_hpux do
|
|
105
|
+
expect { call_wait4 }.to raise_error(ArgumentError)
|
|
102
106
|
end
|
|
103
107
|
|
|
104
|
-
example 'wait4 works as expected' do
|
|
105
|
-
skip 'wait4 test skipped on this platform' if hpux || darwin
|
|
106
|
-
|
|
108
|
+
example 'wait4 works as expected', :skip_hpux do
|
|
107
109
|
@pid = fork { sleep 0.5 }
|
|
108
|
-
expect { @proc_stat =
|
|
110
|
+
expect { @proc_stat = call_wait4(@pid) }.not_to raise_error
|
|
109
111
|
expect(@proc_stat).to be_a(Struct::ProcStat)
|
|
110
112
|
end
|
|
111
113
|
|
|
112
|
-
example 'wait4 sets and returns $last_status to expected values' do
|
|
113
|
-
skip 'wait4 test skipped on this platform' if hpux || darwin
|
|
114
|
-
|
|
114
|
+
example 'wait4 sets and returns $last_status to expected values', :skip_hpux do
|
|
115
115
|
@pid = fork { sleep 0.5 }
|
|
116
|
-
|
|
116
|
+
call_wait4(@pid)
|
|
117
117
|
expect($last_status).to be_a(Struct::ProcStat)
|
|
118
118
|
expect($last_status).not_to be_nil
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
example 'wait4 sets pid and status members of $?' do
|
|
122
|
-
skip 'wait4 test skipped on this platform' if hpux || darwin
|
|
123
|
-
|
|
121
|
+
example 'wait4 sets pid and status members of $?', :skip_hpux do
|
|
124
122
|
@pid = fork { sleep 0.5 }
|
|
125
|
-
|
|
123
|
+
call_wait4(@pid)
|
|
126
124
|
expect($CHILD_STATUS).not_to be_nil
|
|
127
125
|
end
|
|
128
126
|
|
|
129
|
-
example 'wait4 returns frozen struct' do
|
|
130
|
-
skip 'wait4 test skipped on this platform' if hpux || darwin
|
|
131
|
-
|
|
127
|
+
example 'wait4 returns frozen struct', :skip_hpux do
|
|
132
128
|
@pid = fork { sleep 0.5 }
|
|
133
|
-
struct =
|
|
129
|
+
struct = call_wait4(@pid)
|
|
134
130
|
expect(struct).to be_frozen
|
|
135
131
|
end
|
|
136
132
|
|
|
137
|
-
example 'waitid method is defined' do
|
|
138
|
-
skip 'waitid test skipped on this platform' if hpux || darwin || bsd
|
|
139
|
-
|
|
133
|
+
example 'waitid method is defined', :skip_hpux do
|
|
140
134
|
expect(described_class).to respond_to(:waitid)
|
|
141
135
|
end
|
|
142
136
|
|
|
143
|
-
example 'waitid method works as expected' do
|
|
144
|
-
skip 'waitid test skipped on this platform' if hpux || darwin || bsd
|
|
145
|
-
|
|
137
|
+
example 'waitid method works as expected', :skip_hpux do
|
|
146
138
|
@pid = fork { sleep 0.5 }
|
|
147
|
-
expect {
|
|
139
|
+
expect { call_waitid(Process::P_PID, @pid, Process::WEXITED) }.not_to raise_error
|
|
148
140
|
end
|
|
149
141
|
|
|
150
|
-
example 'waitid method raises expected errors if wrong argument type is passed' do
|
|
151
|
-
skip 'waitid test skipped on this platform' if hpux || darwin || bsd
|
|
152
|
-
|
|
142
|
+
example 'waitid method raises expected errors if wrong argument type is passed', :skip_hpux do
|
|
153
143
|
@pid = fork { sleep 0.5 }
|
|
154
|
-
expect {
|
|
155
|
-
expect {
|
|
156
|
-
expect {
|
|
144
|
+
expect { call_waitid('foo', @pid, Process::WEXITED) }.to raise_error(TypeError)
|
|
145
|
+
expect { call_waitid(Process::P_PID, @pid, 'foo') }.to raise_error(TypeError)
|
|
146
|
+
expect { call_waitid(Process::P_PID, 'foo', Process::WEXITED) }.to raise_error(TypeError)
|
|
157
147
|
end
|
|
158
148
|
|
|
159
|
-
example 'waitid method raises expected error if invalid argument is passed' do
|
|
160
|
-
skip 'waitid test skipped on this platform' if hpux || darwin || bsd
|
|
161
|
-
|
|
149
|
+
example 'waitid method raises expected error if invalid argument is passed', :skip_hpux do
|
|
162
150
|
@pid = fork { sleep 0.5 }
|
|
163
151
|
expect { described_class.waitid(Process::P_PID, 99999999, Process::WEXITED) }.to raise_error(Errno::ECHILD)
|
|
164
152
|
end
|
|
165
153
|
|
|
166
|
-
example 'sigsend method is defined' do
|
|
167
|
-
skip 'sigsend test skipped on this platform' unless solaris
|
|
168
|
-
|
|
154
|
+
example 'sigsend method is defined', :solaris do
|
|
169
155
|
expect(described_class).to respond_to(:sigsend)
|
|
170
156
|
end
|
|
171
157
|
|
|
172
|
-
example 'sigsend works as expected' do
|
|
173
|
-
skip 'sigsend test skipped on this platform' unless solaris
|
|
174
|
-
|
|
158
|
+
example 'sigsend works as expected', :solaris do
|
|
175
159
|
@pid = fork { sleep 0.5 }
|
|
176
160
|
expect { described_class.sigsend(Process::P_PID, @pid, 0) }.not_to raise_error
|
|
177
161
|
end
|
|
@@ -187,14 +171,11 @@ RSpec.describe Process do
|
|
|
187
171
|
expect { described_class.getrusage(true) }.not_to raise_error
|
|
188
172
|
end
|
|
189
173
|
|
|
190
|
-
example 'getrusage can get thread info on Linux' do
|
|
191
|
-
skip 'getrusage only tested on Linux' unless linux
|
|
174
|
+
example 'getrusage can get thread info on Linux', :linux do
|
|
192
175
|
expect { described_class.getrusage(Process::RUSAGE_THREAD) }.not_to raise_error
|
|
193
176
|
end
|
|
194
177
|
|
|
195
|
-
example 'getrusage returns the expected struct' do
|
|
196
|
-
skip 'getrusage only tested on Linux' unless linux
|
|
197
|
-
|
|
178
|
+
example 'getrusage returns the expected struct', :linux do
|
|
198
179
|
@pid = fork { sleep 0.5 }
|
|
199
180
|
expect(described_class.getrusage).to be_a(Struct::RUsage)
|
|
200
181
|
expect(described_class.getrusage.stime).to be_a(Float)
|
|
@@ -205,21 +186,18 @@ RSpec.describe Process do
|
|
|
205
186
|
expect(described_class).to respond_to(:pause)
|
|
206
187
|
end
|
|
207
188
|
|
|
208
|
-
example 'expected constants are defined' do
|
|
209
|
-
skip 'wait constant check skipped on this platform' if darwin || bsd
|
|
210
|
-
|
|
189
|
+
example 'expected constants are defined', :skip_darwin, :skip_bsd do
|
|
211
190
|
expect(Process::WCONTINUED).not_to be_nil
|
|
212
191
|
expect(Process::WEXITED).not_to be_nil
|
|
213
192
|
expect(Process::WNOWAIT).not_to be_nil
|
|
214
193
|
expect(Process::WSTOPPED).not_to be_nil
|
|
194
|
+
end
|
|
215
195
|
|
|
216
|
-
|
|
196
|
+
example 'expected constant WTRAPPED is defined', :bsd do
|
|
217
197
|
expect(Process::WTRAPPED).not_to be_nil
|
|
218
198
|
end
|
|
219
199
|
|
|
220
|
-
example 'expected process type flag constants are defined' do
|
|
221
|
-
skip 'process type flag check skipped on this platform' if linux || darwin || bsd
|
|
222
|
-
|
|
200
|
+
example 'expected process type flag constants are defined', :solaris do
|
|
223
201
|
expect(Process::P_ALL).not_to be_nil
|
|
224
202
|
expect(Process::P_CID).not_to be_nil
|
|
225
203
|
expect(Process::P_GID).not_to be_nil
|
|
@@ -227,20 +205,15 @@ RSpec.describe Process do
|
|
|
227
205
|
expect(Process::P_PID).not_to be_nil
|
|
228
206
|
expect(Process::P_SID).not_to be_nil
|
|
229
207
|
expect(Process::P_UID).not_to be_nil
|
|
230
|
-
|
|
231
|
-
skip 'P_MYID constant check skipped on this platform' unless solaris
|
|
232
208
|
expect(Process::P_MYID).not_to be_nil
|
|
233
209
|
end
|
|
234
210
|
|
|
235
|
-
example 'solaris-specific process type flags are defined on solaris' do
|
|
236
|
-
skip 'P_TASKID and P_PROJID constant check skipped on this platform' unless solaris
|
|
237
|
-
|
|
211
|
+
example 'solaris-specific process type flags are defined on solaris', :solaris do
|
|
238
212
|
expect(Process::P_TASKID).not_to be_nil
|
|
239
213
|
expect(Process::P_PROJID).not_to be_nil
|
|
240
214
|
end
|
|
241
215
|
|
|
242
|
-
example 'bsd-specific process type flags are defined on BSD platforms' do
|
|
243
|
-
skip 'P_JAILID constant check skipped on this platform' unless bsd
|
|
216
|
+
example 'bsd-specific process type flags are defined on BSD platforms', :bsd do
|
|
244
217
|
expect(Process::P_JAILID).not_to be_nil
|
|
245
218
|
end
|
|
246
219
|
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rspec'
|
|
4
|
+
require 'proc-wait3'
|
|
5
|
+
|
|
6
|
+
RSpec.configure do |config|
|
|
7
|
+
config.filter_run_excluding(:darwin) if Gem::Platform.local.os !~ /darwin|macos/i
|
|
8
|
+
config.filter_run_excluding(:solaris) if Gem::Platform.local.os !~ /sunos|solaris/i
|
|
9
|
+
config.filter_run_excluding(:bsd) if Gem::Platform.local.os !~ /bsd|dragonfly/i
|
|
10
|
+
config.filter_run_excluding(:linux) if Gem::Platform.local.os !~ /linux/i
|
|
11
|
+
|
|
12
|
+
config.filter_run_excluding(:skip_hpux) if Gem::Platform.local.os =~ /hpux/i
|
|
13
|
+
config.filter_run_excluding(:skip_darwin) if Gem::Platform.local.os =~ /darwin|macos/i
|
|
14
|
+
config.filter_run_excluding(:skip_bsd) if Gem::Platform.local.os =~ /bsd|dragonfly/i
|
|
15
|
+
config.filter_run_excluding(:skip_linux) if Gem::Platform.local.os =~ /linux/i
|
|
16
|
+
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: proc-wait3
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel J. Berger
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain:
|
|
11
10
|
- |
|
|
@@ -35,7 +34,7 @@ cert_chain:
|
|
|
35
34
|
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
|
36
35
|
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
|
37
36
|
-----END CERTIFICATE-----
|
|
38
|
-
date:
|
|
37
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
39
38
|
dependencies:
|
|
40
39
|
- !ruby/object:Gem::Dependency
|
|
41
40
|
name: rake
|
|
@@ -120,6 +119,7 @@ files:
|
|
|
120
119
|
- lib/proc-wait3.rb
|
|
121
120
|
- proc-wait3.gemspec
|
|
122
121
|
- spec/proc_wait3_spec.rb
|
|
122
|
+
- spec/spec_helper.rb
|
|
123
123
|
homepage: https://github.com/djberg96/proc-wait3
|
|
124
124
|
licenses:
|
|
125
125
|
- Apache-2.0
|
|
@@ -132,7 +132,7 @@ metadata:
|
|
|
132
132
|
wiki_uri: https://github.com/djberg96/proc-wait3/wiki
|
|
133
133
|
rubygems_mfa_required: 'true'
|
|
134
134
|
github_repo: https://github.com/djberg96/proc-wait3
|
|
135
|
-
|
|
135
|
+
funding_uri: https://github.com/sponsors/djberg96
|
|
136
136
|
rdoc_options: []
|
|
137
137
|
require_paths:
|
|
138
138
|
- lib
|
|
@@ -147,8 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
147
147
|
- !ruby/object:Gem::Version
|
|
148
148
|
version: '0'
|
|
149
149
|
requirements: []
|
|
150
|
-
rubygems_version:
|
|
151
|
-
signing_key:
|
|
150
|
+
rubygems_version: 4.0.3
|
|
152
151
|
specification_version: 4
|
|
153
152
|
summary: Adds wait3, wait4 and other methods to the Process module
|
|
154
153
|
test_files:
|
metadata.gz.sig
CHANGED
|
Binary file
|