proc-wait3 1.9.3 → 2.1.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 +5 -5
- data/CHANGES.md +19 -1
- data/README.md +3 -0
- data/Rakefile +15 -10
- data/doc/wait3.md +8 -1
- data/examples/example_waitid.rb +14 -4
- data/ext/proc/wait3.c +315 -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 +1 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d9ed8e7bd3a3b5631bbb5e2a4d658c60d1876e8880ebc95eab77f920d81b26be
|
|
4
|
+
data.tar.gz: fa72e2f110aa9a1c4858d7c7a51cc072f115d7de0e63c7f7f0fca0210d26315e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 027c982ad10f5e7a66bdac1e8406df6f99f4372dd739da56b4a5c05bf9115e58bda7e6fbd5b72a3b6e3734ad652928bb3dbc4750a86a70252abc7541b0792613
|
|
7
|
+
data.tar.gz: 0b8289e6c28ce586d9a8f932e31b4e7dd39edfc223061a07d85ff8f8a28daf50329df4933079fcf347c592aaf9d9538ee9de78e448022222294b2a2c2ba5b91e
|
checksums.yaml.gz.sig
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
�
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
J�����M�%���� Z"s��n�IY;;B�0��c?B�=Oq��N��t��XH���C�x��=_�� ���<O�P�PC]]c1�u���mM����&d��敔�mo�
|
|
2
|
+
�V:m`h\ �'���Qb|�b��{�B�7vuE�>dC�{Sa�B��G�p
|
|
3
|
+
E���y+�t#=��D�\�ūgDh�K{�Tq��� �+�x��B>w��>��g�g�^��k���W�x�H��O%�1n`���}
|
|
4
|
+
��#�/?��
|
|
5
|
+
ڪ)�/>mH��.҅U�u�������`ޖ��x����Wnv���1|�/�4�L�� ��GC�W."���2�m_ڳ�BOLY�7gf�� �)m��FQC�ړY8���D���S��|�K�
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 2.1.0 - 18-Jan-2026
|
|
2
|
+
* Modified the wait methods to automatically loop on EINTR for consistent
|
|
3
|
+
cross-platform behavior. Previously you had to do this manually on some
|
|
4
|
+
platforms, e.g. OSX.
|
|
5
|
+
|
|
6
|
+
## 2.0.0 - 10-Jan-2026
|
|
7
|
+
* Added fiber scheduler support for wait3 and wait4 methods, allowing them
|
|
8
|
+
to cooperate with Ruby's fiber scheduler for non-blocking async operations.
|
|
9
|
+
Note that rusage fields will be zero when using the fiber scheduler path.
|
|
10
|
+
* Added `rb_thread_call_without_gvl` for blocking calls so that other Ruby
|
|
11
|
+
threads can run while waiting.
|
|
12
|
+
* Added `RB_GC_GUARD` to protect Ruby objects during blocking operations.
|
|
13
|
+
* Replaced deprecated `RSTRING()->len` and `RSTRING()->ptr` with `RSTRING_LEN()`
|
|
14
|
+
and `RSTRING_PTR()` macros.
|
|
15
|
+
* Added missing `HAVE_STRLCPY` guard in sigsend with strncpy fallback.
|
|
16
|
+
* Fixed some minor whitespace inconsistencies.
|
|
17
|
+
* Now requires Ruby 3.1 or later.
|
|
18
|
+
|
|
1
19
|
## 1.9.3 - 4-May-2024
|
|
2
20
|
* Some internal refactoring where I bzero C structs before using them.
|
|
3
21
|
|
|
@@ -157,7 +175,7 @@
|
|
|
157
175
|
* Updated tests and documentation.
|
|
158
176
|
|
|
159
177
|
## 1.2.0 - 7-Feb-2005
|
|
160
|
-
* Added the Proc.waitid method (for those platforms that support it).
|
|
178
|
+
* Added the Proc.waitid method (for those platforms that support it).
|
|
161
179
|
* Made the wait3.c file more rdoc friendly.
|
|
162
180
|
* Added a test_waitid.rb file in the examples directory.
|
|
163
181
|
|
data/README.md
CHANGED
|
@@ -70,6 +70,9 @@ BSD provides another approach using sigaction handlers + `SA_RESTART`, but it re
|
|
|
70
70
|
the signal type in advance. So, unless you want to apply the same handler to *every* type of
|
|
71
71
|
signal, I don't find it especially useful.
|
|
72
72
|
|
|
73
|
+
Update: As of version 2.1.0 you should no longer have to manually rescue EINTR since it's now
|
|
74
|
+
being handled internally.
|
|
75
|
+
|
|
73
76
|
## Integration with Ruby's process.c
|
|
74
77
|
I considered simply providing a patch to the core process.c file, but I
|
|
75
78
|
decided against it for two reasons. First, I wanted to get something
|
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
|
|
|
@@ -209,7 +216,7 @@ page at https://github.com/djberg96/proc-wait3.
|
|
|
209
216
|
Apache-2.0
|
|
210
217
|
|
|
211
218
|
## Copyright
|
|
212
|
-
(C) 2003-
|
|
219
|
+
(C) 2003-2026 Daniel J. Berger
|
|
213
220
|
|
|
214
221
|
All Rights Reserved.
|
|
215
222
|
|
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,6 +1,9 @@
|
|
|
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>
|
|
6
|
+
#include <errno.h>
|
|
4
7
|
|
|
5
8
|
/* Debian */
|
|
6
9
|
#ifdef HAVE_SYS_RESOURCE_H
|
|
@@ -31,6 +34,67 @@ VALUE v_procstat_struct, v_siginfo_struct, v_usage_struct;
|
|
|
31
34
|
|
|
32
35
|
static void sigproc(int signum, siginfo_t* info, void* ucontext);
|
|
33
36
|
|
|
37
|
+
/* Structs for rb_thread_call_without_gvl wrappers */
|
|
38
|
+
struct wait3_args {
|
|
39
|
+
int status;
|
|
40
|
+
int flags;
|
|
41
|
+
struct rusage rusage;
|
|
42
|
+
pid_t pid;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
#ifdef HAVE_WAIT4
|
|
46
|
+
struct wait4_args {
|
|
47
|
+
pid_t pid;
|
|
48
|
+
int status;
|
|
49
|
+
int flags;
|
|
50
|
+
struct rusage rusage;
|
|
51
|
+
pid_t result;
|
|
52
|
+
};
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
#ifdef HAVE_WAITID
|
|
56
|
+
struct waitid_args {
|
|
57
|
+
idtype_t idtype;
|
|
58
|
+
id_t id;
|
|
59
|
+
siginfo_t infop;
|
|
60
|
+
int options;
|
|
61
|
+
int result;
|
|
62
|
+
};
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
struct pause_args {
|
|
66
|
+
int result;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/* GVL-free wrapper functions */
|
|
70
|
+
static void* wait3_without_gvl(void* data) {
|
|
71
|
+
struct wait3_args* args = (struct wait3_args*)data;
|
|
72
|
+
args->pid = wait3(&args->status, args->flags, &args->rusage);
|
|
73
|
+
return NULL;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#ifdef HAVE_WAIT4
|
|
77
|
+
static void* wait4_without_gvl(void* data) {
|
|
78
|
+
struct wait4_args* args = (struct wait4_args*)data;
|
|
79
|
+
args->result = wait4(args->pid, &args->status, args->flags, &args->rusage);
|
|
80
|
+
return NULL;
|
|
81
|
+
}
|
|
82
|
+
#endif
|
|
83
|
+
|
|
84
|
+
#ifdef HAVE_WAITID
|
|
85
|
+
static void* waitid_without_gvl(void* data) {
|
|
86
|
+
struct waitid_args* args = (struct waitid_args*)data;
|
|
87
|
+
args->result = waitid(args->idtype, args->id, &args->infop, args->options);
|
|
88
|
+
return NULL;
|
|
89
|
+
}
|
|
90
|
+
#endif
|
|
91
|
+
|
|
92
|
+
static void* pause_without_gvl(void* data) {
|
|
93
|
+
struct pause_args* args = (struct pause_args*)data;
|
|
94
|
+
args->result = pause();
|
|
95
|
+
return NULL;
|
|
96
|
+
}
|
|
97
|
+
|
|
34
98
|
/*
|
|
35
99
|
* Returns true if this process is stopped. This is only returned
|
|
36
100
|
* returned if the corresponding wait() call had the WUNTRACED flag
|
|
@@ -38,10 +102,10 @@ static void sigproc(int signum, siginfo_t* info, void* ucontext);
|
|
|
38
102
|
*/
|
|
39
103
|
static VALUE pst_wifstopped(int status)
|
|
40
104
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
105
|
+
if(WIFSTOPPED(status))
|
|
106
|
+
return Qtrue;
|
|
107
|
+
else
|
|
108
|
+
return Qfalse;
|
|
45
109
|
}
|
|
46
110
|
|
|
47
111
|
/*
|
|
@@ -50,7 +114,7 @@ static VALUE pst_wifstopped(int status)
|
|
|
50
114
|
static VALUE pst_wifsignaled(int status)
|
|
51
115
|
{
|
|
52
116
|
if (WIFSIGNALED(status))
|
|
53
|
-
|
|
117
|
+
return Qtrue;
|
|
54
118
|
else
|
|
55
119
|
return Qfalse;
|
|
56
120
|
}
|
|
@@ -131,6 +195,42 @@ static VALUE pst_wstopsig(int status)
|
|
|
131
195
|
return Qnil;
|
|
132
196
|
}
|
|
133
197
|
|
|
198
|
+
/*
|
|
199
|
+
* Helper to build ProcStat struct from pid and status.
|
|
200
|
+
* Used by fiber scheduler path where rusage is not available.
|
|
201
|
+
* All rusage fields are set to 0.
|
|
202
|
+
*/
|
|
203
|
+
static VALUE build_procstat_without_rusage(pid_t pid, int status) {
|
|
204
|
+
return rb_struct_new(v_procstat_struct,
|
|
205
|
+
INT2FIX(pid),
|
|
206
|
+
INT2FIX(status),
|
|
207
|
+
rb_float_new(0.0), /* utime - not available via fiber scheduler */
|
|
208
|
+
rb_float_new(0.0), /* stime - not available via fiber scheduler */
|
|
209
|
+
LONG2NUM(0), /* maxrss */
|
|
210
|
+
LONG2NUM(0), /* ixrss */
|
|
211
|
+
LONG2NUM(0), /* idrss */
|
|
212
|
+
LONG2NUM(0), /* isrss */
|
|
213
|
+
LONG2NUM(0), /* minflt */
|
|
214
|
+
LONG2NUM(0), /* majflt */
|
|
215
|
+
LONG2NUM(0), /* nswap */
|
|
216
|
+
LONG2NUM(0), /* inblock */
|
|
217
|
+
LONG2NUM(0), /* oublock */
|
|
218
|
+
LONG2NUM(0), /* msgsnd */
|
|
219
|
+
LONG2NUM(0), /* msgrcv */
|
|
220
|
+
LONG2NUM(0), /* nsignals */
|
|
221
|
+
LONG2NUM(0), /* nvcsw */
|
|
222
|
+
LONG2NUM(0), /* nivcsw */
|
|
223
|
+
pst_wifstopped(status),
|
|
224
|
+
pst_wifsignaled(status),
|
|
225
|
+
pst_wifexited(status),
|
|
226
|
+
pst_success_p(status),
|
|
227
|
+
pst_wcoredump(status),
|
|
228
|
+
pst_wexitstatus(status),
|
|
229
|
+
pst_wtermsig(status),
|
|
230
|
+
pst_wstopsig(status)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
134
234
|
/*
|
|
135
235
|
* call-seq:
|
|
136
236
|
* Process.wait3(flags=nil)
|
|
@@ -140,13 +240,15 @@ static VALUE pst_wstopsig(int status)
|
|
|
140
240
|
*
|
|
141
241
|
* The return value is a ProcStat structure. The special global $? is also
|
|
142
242
|
* set. Raises a SystemError if there are no child processes.
|
|
243
|
+
*
|
|
244
|
+
* Note: When a fiber scheduler is active (Ruby 3.0+), this method will
|
|
245
|
+
* cooperate with the scheduler. However, rusage information will not be
|
|
246
|
+
* available and those fields will be set to 0 in the returned struct.
|
|
143
247
|
*/
|
|
144
248
|
static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
145
|
-
|
|
146
|
-
int flags = 0;
|
|
147
|
-
struct rusage r;
|
|
148
|
-
pid_t pid;
|
|
249
|
+
struct wait3_args args;
|
|
149
250
|
VALUE v_flags = Qnil;
|
|
251
|
+
int flags = 0;
|
|
150
252
|
|
|
151
253
|
rb_scan_args(argc,argv,"01",&v_flags);
|
|
152
254
|
|
|
@@ -154,43 +256,75 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
154
256
|
flags = NUM2INT(v_flags);
|
|
155
257
|
}
|
|
156
258
|
|
|
157
|
-
|
|
158
|
-
|
|
259
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
260
|
+
if (!NIL_P(scheduler)) {
|
|
261
|
+
/* Use fiber scheduler - wait for any child (pid = -1) */
|
|
262
|
+
VALUE result = rb_fiber_scheduler_process_wait(scheduler, (rb_pid_t)-1, flags);
|
|
263
|
+
|
|
264
|
+
if (NIL_P(result)) {
|
|
265
|
+
return Qnil;
|
|
266
|
+
}
|
|
159
267
|
|
|
160
|
-
|
|
268
|
+
/* Extract pid and status from Process::Status object */
|
|
269
|
+
pid_t pid = NUM2PIDT(rb_funcall(result, rb_intern("pid"), 0));
|
|
270
|
+
int status = NUM2INT(rb_funcall(result, rb_intern("to_i"), 0));
|
|
271
|
+
|
|
272
|
+
RB_GC_GUARD(result);
|
|
273
|
+
|
|
274
|
+
v_last_status = build_procstat_without_rusage(pid, status);
|
|
275
|
+
rb_last_status_set(status, pid);
|
|
276
|
+
OBJ_FREEZE(v_last_status);
|
|
277
|
+
|
|
278
|
+
return v_last_status;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* No fiber scheduler - use thread-based blocking */
|
|
282
|
+
bzero(&args, sizeof(args));
|
|
283
|
+
args.flags = flags;
|
|
284
|
+
|
|
285
|
+
/* Retry on EINTR. The RUBY_UBF_PROCESS unblocking function sends a signal
|
|
286
|
+
* to interrupt the blocking call. On macOS (and some other platforms),
|
|
287
|
+
* wait3() is not automatically restarted after being interrupted, so we
|
|
288
|
+
* must retry manually.
|
|
289
|
+
*/
|
|
290
|
+
do {
|
|
291
|
+
rb_thread_call_without_gvl(wait3_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
292
|
+
} while(args.pid < 0 && errno == EINTR);
|
|
293
|
+
|
|
294
|
+
if(args.pid < 0){
|
|
161
295
|
rb_sys_fail("wait3");
|
|
162
296
|
}
|
|
163
|
-
else if(pid > 0){
|
|
297
|
+
else if(args.pid > 0){
|
|
164
298
|
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)
|
|
299
|
+
INT2FIX(args.pid),
|
|
300
|
+
INT2FIX(args.status),
|
|
301
|
+
rb_float_new((double)args.rusage.ru_utime.tv_sec+(double)args.rusage.ru_utime.tv_usec/1e6),
|
|
302
|
+
rb_float_new((double)args.rusage.ru_stime.tv_sec+(double)args.rusage.ru_stime.tv_usec/1e6),
|
|
303
|
+
LONG2NUM(args.rusage.ru_maxrss),
|
|
304
|
+
LONG2NUM(args.rusage.ru_ixrss),
|
|
305
|
+
LONG2NUM(args.rusage.ru_idrss),
|
|
306
|
+
LONG2NUM(args.rusage.ru_isrss),
|
|
307
|
+
LONG2NUM(args.rusage.ru_minflt),
|
|
308
|
+
LONG2NUM(args.rusage.ru_majflt),
|
|
309
|
+
LONG2NUM(args.rusage.ru_nswap),
|
|
310
|
+
LONG2NUM(args.rusage.ru_inblock),
|
|
311
|
+
LONG2NUM(args.rusage.ru_oublock),
|
|
312
|
+
LONG2NUM(args.rusage.ru_msgsnd),
|
|
313
|
+
LONG2NUM(args.rusage.ru_msgrcv),
|
|
314
|
+
LONG2NUM(args.rusage.ru_nsignals),
|
|
315
|
+
LONG2NUM(args.rusage.ru_nvcsw),
|
|
316
|
+
LONG2NUM(args.rusage.ru_nivcsw),
|
|
317
|
+
pst_wifstopped(args.status),
|
|
318
|
+
pst_wifsignaled(args.status),
|
|
319
|
+
pst_wifexited(args.status),
|
|
320
|
+
pst_success_p(args.status),
|
|
321
|
+
pst_wcoredump(args.status),
|
|
322
|
+
pst_wexitstatus(args.status),
|
|
323
|
+
pst_wtermsig(args.status),
|
|
324
|
+
pst_wstopsig(args.status)
|
|
191
325
|
);
|
|
192
326
|
|
|
193
|
-
rb_last_status_set(status, pid);
|
|
327
|
+
rb_last_status_set(args.status, args.pid);
|
|
194
328
|
OBJ_FREEZE(v_last_status);
|
|
195
329
|
|
|
196
330
|
return v_last_status;
|
|
@@ -211,59 +345,95 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
|
|
|
211
345
|
* This method is not supported on all platforms.
|
|
212
346
|
*
|
|
213
347
|
* Some +flags+ are not supported on all platforms.
|
|
348
|
+
*
|
|
349
|
+
* Note: When a fiber scheduler is active (Ruby 3.0+), this method will
|
|
350
|
+
* cooperate with the scheduler. However, rusage information will not be
|
|
351
|
+
* available and those fields will be set to 0 in the returned struct.
|
|
214
352
|
*/
|
|
215
353
|
static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
216
|
-
|
|
217
|
-
int flags = 0;
|
|
218
|
-
struct rusage r;
|
|
219
|
-
pid_t pid;
|
|
354
|
+
struct wait4_args args;
|
|
220
355
|
VALUE v_pid;
|
|
221
356
|
VALUE v_flags = Qnil;
|
|
357
|
+
pid_t pid;
|
|
358
|
+
int flags = 0;
|
|
222
359
|
|
|
223
360
|
rb_scan_args(argc, argv, "11", &v_pid, &v_flags);
|
|
224
361
|
|
|
225
|
-
pid =
|
|
362
|
+
pid = NUM2PIDT(v_pid);
|
|
226
363
|
|
|
227
364
|
if(RTEST(v_flags))
|
|
228
365
|
flags = NUM2INT(v_flags);
|
|
229
366
|
|
|
230
|
-
|
|
231
|
-
|
|
367
|
+
VALUE scheduler = rb_fiber_scheduler_current();
|
|
368
|
+
if (!NIL_P(scheduler)) {
|
|
369
|
+
/* Use fiber scheduler */
|
|
370
|
+
VALUE result = rb_fiber_scheduler_process_wait(scheduler, pid, flags);
|
|
371
|
+
|
|
372
|
+
if (NIL_P(result)) {
|
|
373
|
+
return Qnil;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* Extract pid and status from Process::Status object */
|
|
377
|
+
pid_t rpid = NUM2PIDT(rb_funcall(result, rb_intern("pid"), 0));
|
|
378
|
+
int status = NUM2INT(rb_funcall(result, rb_intern("to_i"), 0));
|
|
232
379
|
|
|
233
|
-
|
|
380
|
+
RB_GC_GUARD(result);
|
|
381
|
+
|
|
382
|
+
v_last_status = build_procstat_without_rusage(rpid, status);
|
|
383
|
+
rb_last_status_set(status, rpid);
|
|
384
|
+
OBJ_FREEZE(v_last_status);
|
|
385
|
+
|
|
386
|
+
return v_last_status;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* No fiber scheduler - use thread-based blocking */
|
|
390
|
+
bzero(&args, sizeof(args));
|
|
391
|
+
args.pid = pid;
|
|
392
|
+
args.flags = flags;
|
|
393
|
+
|
|
394
|
+
/* Retry on EINTR. The RUBY_UBF_PROCESS unblocking function sends a signal
|
|
395
|
+
* to interrupt the blocking call. On macOS (and some other platforms),
|
|
396
|
+
* wait4() is not automatically restarted after being interrupted, so we
|
|
397
|
+
* must retry manually.
|
|
398
|
+
*/
|
|
399
|
+
do {
|
|
400
|
+
rb_thread_call_without_gvl(wait4_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
401
|
+
} while(args.result < 0 && errno == EINTR);
|
|
402
|
+
|
|
403
|
+
if(args.result < 0){
|
|
234
404
|
rb_sys_fail("wait4");
|
|
235
405
|
}
|
|
236
|
-
else if(
|
|
406
|
+
else if(args.result > 0){
|
|
237
407
|
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)
|
|
408
|
+
INT2FIX(args.result),
|
|
409
|
+
INT2FIX(args.status),
|
|
410
|
+
rb_float_new((double)args.rusage.ru_utime.tv_sec+(double)args.rusage.ru_utime.tv_usec/1e6),
|
|
411
|
+
rb_float_new((double)args.rusage.ru_stime.tv_sec+(double)args.rusage.ru_stime.tv_usec/1e6),
|
|
412
|
+
LONG2NUM(args.rusage.ru_maxrss),
|
|
413
|
+
LONG2NUM(args.rusage.ru_ixrss),
|
|
414
|
+
LONG2NUM(args.rusage.ru_idrss),
|
|
415
|
+
LONG2NUM(args.rusage.ru_isrss),
|
|
416
|
+
LONG2NUM(args.rusage.ru_minflt),
|
|
417
|
+
LONG2NUM(args.rusage.ru_majflt),
|
|
418
|
+
LONG2NUM(args.rusage.ru_nswap),
|
|
419
|
+
LONG2NUM(args.rusage.ru_inblock),
|
|
420
|
+
LONG2NUM(args.rusage.ru_oublock),
|
|
421
|
+
LONG2NUM(args.rusage.ru_msgsnd),
|
|
422
|
+
LONG2NUM(args.rusage.ru_msgrcv),
|
|
423
|
+
LONG2NUM(args.rusage.ru_nsignals),
|
|
424
|
+
LONG2NUM(args.rusage.ru_nvcsw),
|
|
425
|
+
LONG2NUM(args.rusage.ru_nivcsw),
|
|
426
|
+
pst_wifstopped(args.status),
|
|
427
|
+
pst_wifsignaled(args.status),
|
|
428
|
+
pst_wifexited(args.status),
|
|
429
|
+
pst_success_p(args.status),
|
|
430
|
+
pst_wcoredump(args.status),
|
|
431
|
+
pst_wexitstatus(args.status),
|
|
432
|
+
pst_wtermsig(args.status),
|
|
433
|
+
pst_wstopsig(args.status)
|
|
264
434
|
);
|
|
265
435
|
|
|
266
|
-
rb_last_status_set(status,
|
|
436
|
+
rb_last_status_set(args.status, args.result);
|
|
267
437
|
OBJ_FREEZE(v_last_status);
|
|
268
438
|
|
|
269
439
|
return v_last_status;
|
|
@@ -314,20 +484,18 @@ static VALUE proc_wait4(int argc, VALUE *argv, VALUE mod){
|
|
|
314
484
|
*/
|
|
315
485
|
static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
316
486
|
VALUE v_type, v_id, v_options;
|
|
317
|
-
|
|
318
|
-
idtype_t idtype;
|
|
319
|
-
id_t id = 0;
|
|
320
|
-
int options = 0;
|
|
487
|
+
struct waitid_args args;
|
|
321
488
|
|
|
322
489
|
rb_scan_args(argc, argv, "12", &v_type, &v_id, &v_options);
|
|
323
490
|
|
|
324
|
-
|
|
491
|
+
bzero(&args, sizeof(args));
|
|
492
|
+
args.idtype = NUM2INT(v_type);
|
|
325
493
|
|
|
326
494
|
if(RTEST(v_id))
|
|
327
|
-
id = NUM2INT(v_id);
|
|
495
|
+
args.id = NUM2INT(v_id);
|
|
328
496
|
|
|
329
497
|
if(RTEST(v_options))
|
|
330
|
-
options = NUM2INT(v_options);
|
|
498
|
+
args.options = NUM2INT(v_options);
|
|
331
499
|
|
|
332
500
|
/* The Linux man page for waitid() says to zero out the pid field and check
|
|
333
501
|
* its value after the call to waitid() to detect if there were children in
|
|
@@ -335,10 +503,19 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
335
503
|
* simply check the infop.si_signo struct member against SI_NOINFO.
|
|
336
504
|
*/
|
|
337
505
|
#ifndef SI_NOINFO
|
|
338
|
-
infop.si_pid = 0;
|
|
506
|
+
args.infop.si_pid = 0;
|
|
339
507
|
#endif
|
|
340
508
|
|
|
341
|
-
|
|
509
|
+
/* Retry on EINTR. The RUBY_UBF_PROCESS unblocking function sends a signal
|
|
510
|
+
* to interrupt the blocking call. On macOS (and some other platforms),
|
|
511
|
+
* waitid() is not automatically restarted after being interrupted, so we
|
|
512
|
+
* must retry manually.
|
|
513
|
+
*/
|
|
514
|
+
do {
|
|
515
|
+
rb_thread_call_without_gvl(waitid_without_gvl, &args, RUBY_UBF_PROCESS, NULL);
|
|
516
|
+
} while(args.result == -1 && errno == EINTR);
|
|
517
|
+
|
|
518
|
+
if(args.result == -1)
|
|
342
519
|
rb_sys_fail("waitid");
|
|
343
520
|
|
|
344
521
|
/* If the si_code struct member returns SI_NOINFO, or the si_pid member
|
|
@@ -352,13 +529,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
352
529
|
*/
|
|
353
530
|
|
|
354
531
|
#ifdef SI_NOINFO
|
|
355
|
-
if(infop.si_code == SI_NOINFO){
|
|
532
|
+
if(args.infop.si_code == SI_NOINFO){
|
|
356
533
|
#else
|
|
357
|
-
if(infop.si_pid == 0){
|
|
534
|
+
if(args.infop.si_pid == 0){
|
|
358
535
|
#endif
|
|
359
536
|
v_last_status = rb_struct_new(v_siginfo_struct,
|
|
360
|
-
INT2FIX(infop.si_signo),
|
|
361
|
-
INT2FIX(infop.si_errno),
|
|
537
|
+
INT2FIX(args.infop.si_signo),
|
|
538
|
+
INT2FIX(args.infop.si_errno),
|
|
362
539
|
Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, /* code, pid, uid, utime, status, stime */
|
|
363
540
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
364
541
|
Qnil,
|
|
@@ -424,8 +601,8 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
424
601
|
VALUE v_state = Qnil;
|
|
425
602
|
#endif
|
|
426
603
|
VALUE v_band = Qnil, v_entity = Qnil;
|
|
427
|
-
int sig = infop.si_signo;
|
|
428
|
-
int code = infop.si_code;
|
|
604
|
+
int sig = args.infop.si_signo;
|
|
605
|
+
int code = args.infop.si_code;
|
|
429
606
|
|
|
430
607
|
#if defined(HAVE_ST_SI_SYSARG) || defined(HAVE_ST_SI_MSTATE)
|
|
431
608
|
int i = 0;
|
|
@@ -437,13 +614,13 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
437
614
|
*/
|
|
438
615
|
if(sig == SIGCHLD){
|
|
439
616
|
#ifdef HAVE_ST_SI_UTIME
|
|
440
|
-
v_utime = ULL2NUM(infop.si_utime);
|
|
617
|
+
v_utime = ULL2NUM(args.infop.si_utime);
|
|
441
618
|
#endif
|
|
442
619
|
#ifdef HAVE_ST_SI_STATUS
|
|
443
|
-
v_status = ULL2NUM(infop.si_status);
|
|
620
|
+
v_status = ULL2NUM(args.infop.si_status);
|
|
444
621
|
#endif
|
|
445
622
|
#ifdef HAVE_ST_SI_STIME
|
|
446
|
-
v_stime = ULL2NUM(infop.si_stime);
|
|
623
|
+
v_stime = ULL2NUM(args.infop.si_stime);
|
|
447
624
|
#endif
|
|
448
625
|
}
|
|
449
626
|
|
|
@@ -451,66 +628,66 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
451
628
|
sig == SIGTRAP)
|
|
452
629
|
{
|
|
453
630
|
#ifdef HAVE_ST_SI_TRAPNO
|
|
454
|
-
v_trapno = INT2FIX(infop.si_trapno);
|
|
631
|
+
v_trapno = INT2FIX(args.infop.si_trapno);
|
|
455
632
|
#endif
|
|
456
633
|
#ifdef HAVE_ST_SI_PC
|
|
457
|
-
v_pc = INT2FIX(infop.si_pc);
|
|
634
|
+
v_pc = INT2FIX(args.infop.si_pc);
|
|
458
635
|
#endif
|
|
459
636
|
}
|
|
460
637
|
|
|
461
638
|
if(sig == SIGXFSZ){
|
|
462
639
|
#ifdef HAVE_ST_SI_FD
|
|
463
|
-
v_fd = INT2FIX(infop.si_fd);
|
|
640
|
+
v_fd = INT2FIX(args.infop.si_fd);
|
|
464
641
|
#endif
|
|
465
642
|
if(code == POLL_IN || code == POLL_OUT || code == POLL_MSG){
|
|
466
|
-
v_band = LONG2FIX(infop.si_band);
|
|
643
|
+
v_band = LONG2FIX(args.infop.si_band);
|
|
467
644
|
}
|
|
468
645
|
}
|
|
469
646
|
|
|
470
647
|
if(sig == SIGPROF){
|
|
471
648
|
#ifdef HAVE_ST_SI_SYSARG
|
|
472
|
-
int ssize = sizeof(infop.si_sysarg) / sizeof(infop.si_sysarg[0]);
|
|
649
|
+
int ssize = sizeof(args.infop.si_sysarg) / sizeof(args.infop.si_sysarg[0]);
|
|
473
650
|
v_sysarg = rb_ary_new();
|
|
474
651
|
|
|
475
652
|
for(i = 0; i < ssize; i++)
|
|
476
|
-
rb_ary_push(v_sysarg, LONG2FIX(infop.si_sysarg[i]));
|
|
653
|
+
rb_ary_push(v_sysarg, LONG2FIX(args.infop.si_sysarg[i]));
|
|
477
654
|
#endif
|
|
478
655
|
#ifdef HAVE_ST_SI_MSTATE
|
|
479
|
-
int msize = sizeof(infop.si_mstate) / sizeof(infop.si_mstate[0]);
|
|
656
|
+
int msize = sizeof(args.infop.si_mstate) / sizeof(args.infop.si_mstate[0]);
|
|
480
657
|
v_state = rb_ary_new();
|
|
481
658
|
|
|
482
659
|
for(i = 0; i < msize; i++)
|
|
483
|
-
rb_ary_push(v_state, INT2FIX(infop.si_mstate[i]));
|
|
660
|
+
rb_ary_push(v_state, INT2FIX(args.infop.si_mstate[i]));
|
|
484
661
|
#endif
|
|
485
662
|
#ifdef HAVE_ST_SI_FADDR
|
|
486
|
-
v_addr = INT2FIX(infop.si_faddr);
|
|
663
|
+
v_addr = INT2FIX(args.infop.si_faddr);
|
|
487
664
|
#endif
|
|
488
665
|
#ifdef HAVE_ST_SI_SYSCALL
|
|
489
|
-
v_syscall = INT2FIX(infop.si_syscall);
|
|
666
|
+
v_syscall = INT2FIX(args.infop.si_syscall);
|
|
490
667
|
#endif
|
|
491
668
|
#ifdef HAVE_ST_SI_NSYSARG
|
|
492
|
-
v_nsysarg = INT2FIX(infop.si_nsysarg);
|
|
669
|
+
v_nsysarg = INT2FIX(args.infop.si_nsysarg);
|
|
493
670
|
#endif
|
|
494
671
|
#ifdef HAVE_ST_SI_FAULT
|
|
495
|
-
v_fault = INT2FIX(infop.si_fault);
|
|
672
|
+
v_fault = INT2FIX(args.infop.si_fault);
|
|
496
673
|
#endif
|
|
497
674
|
#ifdef HAVE_ST_SI_TSTAMP
|
|
498
|
-
v_time = rb_time_new(infop.si_tstamp.tv_sec,infop.si_tstamp.tv_nsec);
|
|
675
|
+
v_time = rb_time_new(args.infop.si_tstamp.tv_sec,args.infop.si_tstamp.tv_nsec);
|
|
499
676
|
#endif
|
|
500
677
|
}
|
|
501
678
|
|
|
502
679
|
#ifdef SIGXRES
|
|
503
680
|
if(sig == SIGXRES){
|
|
504
|
-
v_entity = INT2FIX(infop.si_entity);
|
|
681
|
+
v_entity = INT2FIX(args.infop.si_entity);
|
|
505
682
|
}
|
|
506
683
|
#endif
|
|
507
684
|
|
|
508
685
|
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
|
|
686
|
+
INT2FIX(args.infop.si_signo), // Probably SIGCHLD
|
|
687
|
+
INT2FIX(args.infop.si_errno), // 0 means no error
|
|
688
|
+
INT2FIX(args.infop.si_code), // Should be anything but SI_NOINFO
|
|
689
|
+
INT2FIX(args.infop.si_pid), // Real PID that sent the signal
|
|
690
|
+
INT2FIX(args.infop.si_uid), // Real UID of process that sent signal
|
|
514
691
|
v_utime,
|
|
515
692
|
v_status,
|
|
516
693
|
v_stime,
|
|
@@ -566,7 +743,7 @@ static VALUE proc_waitid(int argc, VALUE* argv, VALUE mod){
|
|
|
566
743
|
* be sure to leave off the leading 'SIG' substring, e.g. use 'INT' instead
|
|
567
744
|
* of 'SIGINT'.
|
|
568
745
|
*
|
|
569
|
-
* Note that not all platforms (notably Linux)
|
|
746
|
+
* Note that not all platforms (notably Linux) support automatically
|
|
570
747
|
* converting strings to their corresponding signal values, so it is
|
|
571
748
|
* recommended that you always use an array of numeric values.
|
|
572
749
|
*
|
|
@@ -600,10 +777,12 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
600
777
|
if(strlcpy(signame, StringValuePtr(v_val), max) >= max)
|
|
601
778
|
rb_raise(rb_eArgError, "string too large");
|
|
602
779
|
#else
|
|
603
|
-
if(
|
|
780
|
+
if(RSTRING_LEN(v_val) >= max)
|
|
604
781
|
rb_raise(rb_eArgError, "string too large");
|
|
605
|
-
else
|
|
606
|
-
strncpy(signame,
|
|
782
|
+
else{
|
|
783
|
+
strncpy(signame, RSTRING_PTR(v_val), max);
|
|
784
|
+
signame[max-1] = '\0';
|
|
785
|
+
}
|
|
607
786
|
#endif
|
|
608
787
|
|
|
609
788
|
#ifdef HAVE_STR2SIG
|
|
@@ -619,17 +798,22 @@ static VALUE proc_pause(int argc, VALUE* argv, VALUE mod){
|
|
|
619
798
|
signum = NUM2INT(v_val);
|
|
620
799
|
}
|
|
621
800
|
|
|
622
|
-
|
|
801
|
+
bzero(&act, sizeof(act));
|
|
623
802
|
act.sa_flags = SA_SIGINFO;
|
|
624
803
|
act.sa_sigaction = sigproc;
|
|
625
804
|
res = sigaction(signum, &act, &sa);
|
|
626
805
|
|
|
627
806
|
if(res)
|
|
628
|
-
|
|
807
|
+
rb_sys_fail("sigaction");
|
|
629
808
|
}
|
|
630
809
|
}
|
|
631
810
|
|
|
632
|
-
|
|
811
|
+
{
|
|
812
|
+
struct pause_args pargs;
|
|
813
|
+
rb_thread_call_without_gvl(pause_without_gvl, &pargs, RUBY_UBF_PROCESS, NULL);
|
|
814
|
+
RB_GC_GUARD(v_signals);
|
|
815
|
+
return INT2FIX(pargs.result); /* Should always be -1 */
|
|
816
|
+
}
|
|
633
817
|
}
|
|
634
818
|
|
|
635
819
|
/*
|
|
@@ -696,8 +880,17 @@ static VALUE proc_sigsend(int argc, VALUE* argv, VALUE mod){
|
|
|
696
880
|
char signame[SIG2STR_MAX];
|
|
697
881
|
unsigned int max = SIG2STR_MAX;
|
|
698
882
|
|
|
883
|
+
#ifdef HAVE_STRLCPY
|
|
699
884
|
if(strlcpy(signame, StringValuePtr(v_signal), max) >= max)
|
|
700
885
|
rb_raise(rb_eArgError, "string too large");
|
|
886
|
+
#else
|
|
887
|
+
if(RSTRING_LEN(v_signal) >= max)
|
|
888
|
+
rb_raise(rb_eArgError, "string too large");
|
|
889
|
+
else{
|
|
890
|
+
strncpy(signame, RSTRING_PTR(v_signal), max);
|
|
891
|
+
signame[max-1] = '\0';
|
|
892
|
+
}
|
|
893
|
+
#endif
|
|
701
894
|
|
|
702
895
|
if(str2sig(signame,&sig) != 0)
|
|
703
896
|
rb_sys_fail("str2sig");
|
|
@@ -973,8 +1166,8 @@ void Init_wait3(void)
|
|
|
973
1166
|
rb_define_const(rb_mProcess, "RUSAGE_THREAD", INT2FIX(RUSAGE_THREAD));
|
|
974
1167
|
#endif
|
|
975
1168
|
|
|
976
|
-
/* 1.
|
|
977
|
-
rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("1.
|
|
1169
|
+
/* 2.1.0: The version of the proc-wait3 library */
|
|
1170
|
+
rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("2.1.0")));
|
|
978
1171
|
|
|
979
1172
|
/* Define this last in our Init_wait3 function */
|
|
980
1173
|
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 = '1.
|
|
5
|
+
spec.version = '2.1.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: 1.
|
|
4
|
+
version: 2.1.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: 3.
|
|
152
|
-
signing_key:
|
|
150
|
+
rubygems_version: 3.6.9
|
|
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
|
@@ -1,3 +1 @@
|
|
|
1
|
-
�
|
|
2
|
-
�溨}gdԥwf*����J�˚䋓t��!FI��`<�ѝ��Gd9ʦ��<� ���`��,{R�����y�R��#9w̻�2zk� T�'@��h�װh��S� �q��_�����v� jљ�J��Y�g2��~C(�>ҵpMNn�f��I��T��dE�פ�SCPn�2h��(�X$��|Rb�n6�9��O��Oȉ^�'
|
|
3
|
-
p���pN���"��n-�M~е:Jc��U��lQ�c���D�z�˾����p�� "$Gu'��w'�[47����q�E�c/�JCh������$��~/��E"[7����R��β�3������Iˍ���9�s�vG��.��8�ZX�ô�B�
|
|
1
|
+
`G��8��x߲���ȱ��r��/��]�@ڱl�'�-N����DFJF�<`��{!(�P�\���l�8;�Z#��z�x�S��L��D<��s��9�gF��I~->��qø-H�{=Q�g
|