proc-wait3 1.9.3 → 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 +14 -1
- data/Rakefile +15 -10
- data/doc/wait3.md +7 -0
- data/examples/example_waitid.rb +14 -4
- data/ext/proc/wait3.c +293 -122
- data/proc-wait3.gemspec +3 -2
- data/spec/proc_wait3_spec.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -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,16 @@
|
|
|
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
|
+
|
|
1
14
|
## 1.9.3 - 4-May-2024
|
|
2
15
|
* Some internal refactoring where I bzero C structs before using them.
|
|
3
16
|
|
|
@@ -157,7 +170,7 @@
|
|
|
157
170
|
* Updated tests and documentation.
|
|
158
171
|
|
|
159
172
|
## 1.2.0 - 7-Feb-2005
|
|
160
|
-
* Added the Proc.waitid method (for those platforms that support it).
|
|
173
|
+
* Added the Proc.waitid method (for those platforms that support it).
|
|
161
174
|
* Made the wait3.c file more rdoc friendly.
|
|
162
175
|
* Added a test_waitid.rb file in the examples directory.
|
|
163
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,43 +255,68 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
154
255
|
flags = NUM2INT(v_flags);
|
|
155
256
|
}
|
|
156
257
|
|
|
157
|
-
|
|
158
|
-
|
|
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);
|
|
159
262
|
|
|
160
|
-
|
|
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);
|
|
285
|
+
|
|
286
|
+
if(args.pid < 0){
|
|
161
287
|
rb_sys_fail("wait3");
|
|
162
288
|
}
|
|
163
|
-
else if(pid > 0){
|
|
289
|
+
else if(args.pid > 0){
|
|
164
290
|
v_last_status = rb_struct_new(v_procstat_struct,
|
|
165
|
-
INT2FIX(pid),
|
|
166
|
-
INT2FIX(status),
|
|
167
|
-
rb_float_new((double)
|
|
168
|
-
rb_float_new((double)
|
|
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
|
-
LONG2NUM(
|
|
183
|
-
pst_wifstopped(status),
|
|
184
|
-
pst_wifsignaled(status),
|
|
185
|
-
pst_wifexited(status),
|
|
186
|
-
pst_success_p(status),
|
|
187
|
-
pst_wcoredump(status),
|
|
188
|
-
pst_wexitstatus(status),
|
|
189
|
-
pst_wtermsig(status),
|
|
190
|
-
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)
|
|
191
317
|
);
|
|
192
318
|
|
|
193
|
-
rb_last_status_set(status, pid);
|
|
319
|
+
rb_last_status_set(args.status, args.pid);
|
|
194
320
|
OBJ_FREEZE(v_last_status);
|
|
195
321
|
|
|
196
322
|
return v_last_status;
|
|
@@ -211,59 +337,88 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
211
337
|
* This method is not supported on all platforms.
|
|
212
338
|
*
|
|
213
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.
|
|
214
344
|
*/
|
|
215
345
|
static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
216
|
-
|
|
217
|
-
int flags = 0;
|
|
218
|
-
struct rusage r;
|
|
219
|
-
pid_t pid;
|
|
346
|
+
struct wait4_args args;
|
|
220
347
|
VALUE v_pid;
|
|
221
348
|
VALUE v_flags = Qnil;
|
|
349
|
+
pid_t pid;
|
|
350
|
+
int flags = 0;
|
|
222
351
|
|
|
223
352
|
rb_scan_args(argc, argv, "11", &v_pid, &v_flags);
|
|
224
353
|
|
|
225
|
-
pid =
|
|
354
|
+
pid = NUM2PIDT(v_pid);
|
|
226
355
|
|
|
227
356
|
if(RTEST(v_flags))
|
|
228
357
|
flags = NUM2INT(v_flags);
|
|
229
358
|
|
|
230
|
-
|
|
231
|
-
|
|
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));
|
|
371
|
+
|
|
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);
|
|
232
387
|
|
|
233
|
-
if(
|
|
388
|
+
if(args.result < 0){
|
|
234
389
|
rb_sys_fail("wait4");
|
|
235
390
|
}
|
|
236
|
-
else if(
|
|
391
|
+
else if(args.result > 0){
|
|
237
392
|
v_last_status = rb_struct_new(v_procstat_struct,
|
|
238
|
-
INT2FIX(
|
|
239
|
-
INT2FIX(status),
|
|
240
|
-
rb_float_new((double)
|
|
241
|
-
rb_float_new((double)
|
|
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
|
-
LONG2NUM(
|
|
255
|
-
LONG2NUM(
|
|
256
|
-
pst_wifstopped(status),
|
|
257
|
-
pst_wifsignaled(status),
|
|
258
|
-
pst_wifexited(status),
|
|
259
|
-
pst_success_p(status),
|
|
260
|
-
pst_wcoredump(status),
|
|
261
|
-
pst_wexitstatus(status),
|
|
262
|
-
pst_wtermsig(status),
|
|
263
|
-
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)
|
|
264
419
|
);
|
|
265
420
|
|
|
266
|
-
rb_last_status_set(status,
|
|
421
|
+
rb_last_status_set(args.status, args.result);
|
|
267
422
|
OBJ_FREEZE(v_last_status);
|
|
268
423
|
|
|
269
424
|
return v_last_status;
|
|
@@ -314,20 +469,18 @@ static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
|
314
469
|
*/
|
|
315
470
|
static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
316
471
|
VALUE v_type, v_id, v_options;
|
|
317
|
-
|
|
318
|
-
idtype_t idtype;
|
|
319
|
-
id_t id = 0;
|
|
320
|
-
int options = 0;
|
|
472
|
+
struct waitid_args args;
|
|
321
473
|
|
|
322
474
|
rb_scan_args(argc, argv, "12", &v_type, &v_id, &v_options);
|
|
323
475
|
|
|
324
|
-
|
|
476
|
+
bzero(&args, sizeof(args));
|
|
477
|
+
args.idtype = NUM2INT(v_type);
|
|
325
478
|
|
|
326
479
|
if(RTEST(v_id))
|
|
327
|
-
id = NUM2INT(v_id);
|
|
480
|
+
args.id = NUM2INT(v_id);
|
|
328
481
|
|
|
329
482
|
if(RTEST(v_options))
|
|
330
|
-
options = NUM2INT(v_options);
|
|
483
|
+
args.options = NUM2INT(v_options);
|
|
331
484
|
|
|
332
485
|
/* The Linux man page for waitid() says to zero out the pid field and check
|
|
333
486
|
* its value after the call to waitid() to detect if there were children in
|
|
@@ -335,10 +488,12 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
335
488
|
* simply check the infop.si_signo struct member against SI_NOINFO.
|
|
336
489
|
*/
|
|
337
490
|
#ifndef SI_NOINFO
|
|
338
|
-
infop.si_pid = 0;
|
|
491
|
+
args.infop.si_pid = 0;
|
|
339
492
|
#endif
|
|
340
493
|
|
|
341
|
-
|
|
494
|
+
rb_thread_call_without_gvl(waitid_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
495
|
+
|
|
496
|
+
if(args.result == -1)
|
|
342
497
|
rb_sys_fail("waitid");
|
|
343
498
|
|
|
344
499
|
/* If the si_code struct member returns SI_NOINFO, or the si_pid member
|
|
@@ -352,13 +507,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
352
507
|
*/
|
|
353
508
|
|
|
354
509
|
#ifdef SI_NOINFO
|
|
355
|
-
if(infop.si_code == SI_NOINFO){
|
|
510
|
+
if(args.infop.si_code == SI_NOINFO){
|
|
356
511
|
#else
|
|
357
|
-
if(infop.si_pid == 0){
|
|
512
|
+
if(args.infop.si_pid == 0){
|
|
358
513
|
#endif
|
|
359
514
|
v_last_status = rb_struct_new(v_siginfo_struct,
|
|
360
|
-
INT2FIX(infop.si_signo),
|
|
361
|
-
INT2FIX(infop.si_errno),
|
|
515
|
+
INT2FIX(args.infop.si_signo),
|
|
516
|
+
INT2FIX(args.infop.si_errno),
|
|
362
517
|
Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, /* code, pid, uid, utime, status, stime */
|
|
363
518
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
364
519
|
Qnil,
|
|
@@ -424,8 +579,8 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
424
579
|
VALUE v_state = Qnil;
|
|
425
580
|
#endif
|
|
426
581
|
VALUE v_band = Qnil, v_entity = Qnil;
|
|
427
|
-
int sig = infop.si_signo;
|
|
428
|
-
int code = infop.si_code;
|
|
582
|
+
int sig = args.infop.si_signo;
|
|
583
|
+
int code = args.infop.si_code;
|
|
429
584
|
|
|
430
585
|
#if defined(HAVE_ST_SI_SYSARG) || defined(HAVE_ST_SI_MSTATE)
|
|
431
586
|
int i = 0;
|
|
@@ -437,13 +592,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
437
592
|
*/
|
|
438
593
|
if(sig == SIGCHLD){
|
|
439
594
|
#ifdef HAVE_ST_SI_UTIME
|
|
440
|
-
v_utime = ULL2NUM(infop.si_utime);
|
|
595
|
+
v_utime = ULL2NUM(args.infop.si_utime);
|
|
441
596
|
#endif
|
|
442
597
|
#ifdef HAVE_ST_SI_STATUS
|
|
443
|
-
v_status = ULL2NUM(infop.si_status);
|
|
598
|
+
v_status = ULL2NUM(args.infop.si_status);
|
|
444
599
|
#endif
|
|
445
600
|
#ifdef HAVE_ST_SI_STIME
|
|
446
|
-
v_stime = ULL2NUM(infop.si_stime);
|
|
601
|
+
v_stime = ULL2NUM(args.infop.si_stime);
|
|
447
602
|
#endif
|
|
448
603
|
}
|
|
449
604
|
|
|
@@ -451,66 +606,66 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
451
606
|
sig == SIGTRAP)
|
|
452
607
|
{
|
|
453
608
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
454
|
-
v_trapno = INT2FIX(infop.si_trapno);
|
|
609
|
+
v_trapno = INT2FIX(args.infop.si_trapno);
|
|
455
610
|
#endif
|
|
456
611
|
#ifdef HAVE_ST_SI_PC
|
|
457
|
-
v_pc = INT2FIX(infop.si_pc);
|
|
612
|
+
v_pc = INT2FIX(args.infop.si_pc);
|
|
458
613
|
#endif
|
|
459
614
|
}
|
|
460
615
|
|
|
461
616
|
if(sig == SIGXFSZ){
|
|
462
617
|
#ifdef HAVE_ST_SI_FD
|
|
463
|
-
v_fd = INT2FIX(infop.si_fd);
|
|
618
|
+
v_fd = INT2FIX(args.infop.si_fd);
|
|
464
619
|
#endif
|
|
465
620
|
if(code == POLL_IN || code == POLL_OUT || code == POLL_MSG){
|
|
466
|
-
v_band = LONG2FIX(infop.si_band);
|
|
621
|
+
v_band = LONG2FIX(args.infop.si_band);
|
|
467
622
|
}
|
|
468
623
|
}
|
|
469
624
|
|
|
470
625
|
if(sig == SIGPROF){
|
|
471
626
|
#ifdef HAVE_ST_SI_SYSARG
|
|
472
|
-
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]);
|
|
473
628
|
v_sysarg = rb_ary_new();
|
|
474
629
|
|
|
475
630
|
for(i = 0; i < ssize; i++)
|
|
476
|
-
rb_ary_push(v_sysarg, LONG2FIX(infop.si_sysarg[i]));
|
|
631
|
+
rb_ary_push(v_sysarg, LONG2FIX(args.infop.si_sysarg[i]));
|
|
477
632
|
#endif
|
|
478
633
|
#ifdef HAVE_ST_SI_MSTATE
|
|
479
|
-
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]);
|
|
480
635
|
v_state = rb_ary_new();
|
|
481
636
|
|
|
482
637
|
for(i = 0; i < msize; i++)
|
|
483
|
-
rb_ary_push(v_state, INT2FIX(infop.si_mstate[i]));
|
|
638
|
+
rb_ary_push(v_state, INT2FIX(args.infop.si_mstate[i]));
|
|
484
639
|
#endif
|
|
485
640
|
#ifdef HAVE_ST_SI_FADDR
|
|
486
|
-
v_addr = INT2FIX(infop.si_faddr);
|
|
641
|
+
v_addr = INT2FIX(args.infop.si_faddr);
|
|
487
642
|
#endif
|
|
488
643
|
#ifdef HAVE_ST_SI_SYSCALL
|
|
489
|
-
v_syscall = INT2FIX(infop.si_syscall);
|
|
644
|
+
v_syscall = INT2FIX(args.infop.si_syscall);
|
|
490
645
|
#endif
|
|
491
646
|
#ifdef HAVE_ST_SI_NSYSARG
|
|
492
|
-
v_nsysarg = INT2FIX(infop.si_nsysarg);
|
|
647
|
+
v_nsysarg = INT2FIX(args.infop.si_nsysarg);
|
|
493
648
|
#endif
|
|
494
649
|
#ifdef HAVE_ST_SI_FAULT
|
|
495
|
-
v_fault = INT2FIX(infop.si_fault);
|
|
650
|
+
v_fault = INT2FIX(args.infop.si_fault);
|
|
496
651
|
#endif
|
|
497
652
|
#ifdef HAVE_ST_SI_TSTAMP
|
|
498
|
-
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);
|
|
499
654
|
#endif
|
|
500
655
|
}
|
|
501
656
|
|
|
502
657
|
#ifdef SIGXRES
|
|
503
658
|
if(sig == SIGXRES){
|
|
504
|
-
v_entity = INT2FIX(infop.si_entity);
|
|
659
|
+
v_entity = INT2FIX(args.infop.si_entity);
|
|
505
660
|
}
|
|
506
661
|
#endif
|
|
507
662
|
|
|
508
663
|
v_last_status = rb_struct_new(v_siginfo_struct,
|
|
509
|
-
INT2FIX(infop.si_signo), // Probably SIGCHLD
|
|
510
|
-
INT2FIX(infop.si_errno), // 0 means no error
|
|
511
|
-
INT2FIX(infop.si_code), // Should be anything but SI_NOINFO
|
|
512
|
-
INT2FIX(infop.si_pid), // Real PID that sent the signal
|
|
513
|
-
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
|
|
514
669
|
v_utime,
|
|
515
670
|
v_status,
|
|
516
671
|
v_stime,
|
|
@@ -566,7 +721,7 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
566
721
|
* be sure to leave off the leading 'SIG' substring, e.g. use 'INT' instead
|
|
567
722
|
* of 'SIGINT'.
|
|
568
723
|
*
|
|
569
|
-
* Note that not all platforms (notably Linux)
|
|
724
|
+
* Note that not all platforms (notably Linux) support automatically
|
|
570
725
|
* converting strings to their corresponding signal values, so it is
|
|
571
726
|
* recommended that you always use an array of numeric values.
|
|
572
727
|
*
|
|
@@ -600,10 +755,12 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
600
755
|
if(strlcpy(signame, StringValuePtr(v_val), max) >= max)
|
|
601
756
|
rb_raise(rb_eArgError, "string too large");
|
|
602
757
|
#else
|
|
603
|
-
if(
|
|
758
|
+
if(RSTRING_LEN(v_val) >= max)
|
|
604
759
|
rb_raise(rb_eArgError, "string too large");
|
|
605
|
-
else
|
|
606
|
-
strncpy(signame,
|
|
760
|
+
else{
|
|
761
|
+
strncpy(signame, RSTRING_PTR(v_val), max);
|
|
762
|
+
signame[max-1] = '\0';
|
|
763
|
+
}
|
|
607
764
|
#endif
|
|
608
765
|
|
|
609
766
|
#ifdef HAVE_STR2SIG
|
|
@@ -619,17 +776,22 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
619
776
|
signum = NUM2INT(v_val);
|
|
620
777
|
}
|
|
621
778
|
|
|
622
|
-
|
|
779
|
+
bzero(&act, sizeof(act));
|
|
623
780
|
act.sa_flags = SA_SIGINFO;
|
|
624
781
|
act.sa_sigaction = sigproc;
|
|
625
782
|
res = sigaction(signum, &act, &sa);
|
|
626
783
|
|
|
627
784
|
if(res)
|
|
628
|
-
|
|
785
|
+
rb_sys_fail("sigaction");
|
|
629
786
|
}
|
|
630
787
|
}
|
|
631
788
|
|
|
632
|
-
|
|
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
|
+
}
|
|
633
795
|
}
|
|
634
796
|
|
|
635
797
|
/*
|
|
@@ -696,8 +858,17 @@ static VALUE proc_sigsend(int argc, VALUE* argv, VALUE mod){
|
|
|
696
858
|
char signame[SIG2STR_MAX];
|
|
697
859
|
unsigned int max = SIG2STR_MAX;
|
|
698
860
|
|
|
861
|
+
#ifdef HAVE_STRLCPY
|
|
699
862
|
if(strlcpy(signame, StringValuePtr(v_signal), max) >= max)
|
|
700
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
|
|
701
872
|
|
|
702
873
|
if(str2sig(signame,&sig) != 0)
|
|
703
874
|
rb_sys_fail("str2sig");
|
|
@@ -973,8 +1144,8 @@ void Init_wait3(void)
|
|
|
973
1144
|
rb_define_const(rb_mProcess, "RUSAGE_THREAD", INT2FIX(RUSAGE_THREAD));
|
|
974
1145
|
#endif
|
|
975
1146
|
|
|
976
|
-
/*
|
|
977
|
-
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")));
|
|
978
1149
|
|
|
979
1150
|
/* Define this last in our Init_wait3 function */
|
|
980
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
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
|
|
@@ -133,7 +132,7 @@ metadata:
|
|
|
133
132
|
wiki_uri: https://github.com/djberg96/proc-wait3/wiki
|
|
134
133
|
rubygems_mfa_required: 'true'
|
|
135
134
|
github_repo: https://github.com/djberg96/proc-wait3
|
|
136
|
-
|
|
135
|
+
funding_uri: https://github.com/sponsors/djberg96
|
|
137
136
|
rdoc_options: []
|
|
138
137
|
require_paths:
|
|
139
138
|
- lib
|
|
@@ -148,8 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
148
147
|
- !ruby/object:Gem::Version
|
|
149
148
|
version: '0'
|
|
150
149
|
requirements: []
|
|
151
|
-
rubygems_version:
|
|
152
|
-
signing_key:
|
|
150
|
+
rubygems_version: 4.0.3
|
|
153
151
|
specification_version: 4
|
|
154
152
|
summary: Adds wait3, wait4 and other methods to the Process module
|
|
155
153
|
test_files:
|
metadata.gz.sig
CHANGED
|
Binary file
|