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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6e56b25dc085ce18c5808a81d259c4e9f54cb75d1ff985985bb5a575d58ed90
4
- data.tar.gz: 65379d28529797369401cc65abb6c234b9cf1995ec7cf92152d03c03c6a89a83
3
+ metadata.gz: bba2d43b0af474f64ee8879055afc649a62afed46269bafc2bea754eb2ab770b
4
+ data.tar.gz: 0b5e3a6ebc48e370c32273db28e107c068a70e08f367031011bb0c1d1c2065a8
5
5
  SHA512:
6
- metadata.gz: 51f2d1148e8fcadb8b9530420ac164e81b4645b04e3f7b8acded43a62acaa3000240f5e5e53b5fda4cc734f0e2f76edbf76d5b325c2cc3fefd450cf0f60ca519
7
- data.tar.gz: ce1e71899e8db9c2c74bb5207d3a715e7cf8b355d0c5b6bc203b51608647d90fe53c0414bce48ee38c1c796987df7f9fa2b4a30c9eeebdd35900e34d288be82a
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', # Gem files
11
- '**/*.rbc', # Rubinius
12
- '**/*.o', # C object file
13
- '**/*.log', # Ruby extension build log
14
- '**/Makefile', # C Makefile
15
- '**/conftest.dSYM', # OS X build directory
16
- "**/*.#{CONFIG['DLEXT']}", # C shared object
17
- '**/*.lock' # Bundler
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
 
@@ -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
- pid = fork { sleep 2 }
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
- Process.waitid(Process::P_PID, pid, Process::WEXITED)
17
- p $CHILD_STATUS
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
- if(WIFSTOPPED(status))
42
- return Qtrue;
43
- else
44
- return Qfalse;
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
- return Qtrue;
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
- int status;
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
- pid = wait3(&status, flags, &r);
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)r.ru_utime.tv_sec+(double)r.ru_utime.tv_usec/1e6),
167
- rb_float_new((double)r.ru_stime.tv_sec+(double)r.ru_stime.tv_usec/1e6),
168
- LONG2NUM(r.ru_maxrss),
169
- LONG2NUM(r.ru_ixrss),
170
- LONG2NUM(r.ru_idrss),
171
- LONG2NUM(r.ru_isrss),
172
- LONG2NUM(r.ru_minflt),
173
- LONG2NUM(r.ru_majflt),
174
- LONG2NUM(r.ru_nswap),
175
- LONG2NUM(r.ru_inblock),
176
- LONG2NUM(r.ru_oublock),
177
- LONG2NUM(r.ru_msgsnd),
178
- LONG2NUM(r.ru_msgrcv),
179
- LONG2NUM(r.ru_nsignals),
180
- LONG2NUM(r.ru_nvcsw),
181
- LONG2NUM(r.ru_nivcsw),
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
- int status;
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 = NUM2INT(v_pid);
354
+ pid = NUM2PIDT(v_pid);
225
355
 
226
356
  if(RTEST(v_flags))
227
357
  flags = NUM2INT(v_flags);
228
358
 
229
- pid = wait4(pid, &status, flags, &r);
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
- if(pid < 0){
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(pid > 0){
391
+ else if(args.result > 0){
235
392
  v_last_status = rb_struct_new(v_procstat_struct,
236
- INT2FIX(pid),
237
- INT2FIX(status),
238
- rb_float_new((double)r.ru_utime.tv_sec+(double)r.ru_utime.tv_usec/1e6),
239
- rb_float_new((double)r.ru_stime.tv_sec+(double)r.ru_stime.tv_usec/1e6),
240
- LONG2NUM(r.ru_maxrss),
241
- LONG2NUM(r.ru_ixrss),
242
- LONG2NUM(r.ru_idrss),
243
- LONG2NUM(r.ru_isrss),
244
- LONG2NUM(r.ru_minflt),
245
- LONG2NUM(r.ru_majflt),
246
- LONG2NUM(r.ru_nswap),
247
- LONG2NUM(r.ru_inblock),
248
- LONG2NUM(r.ru_oublock),
249
- LONG2NUM(r.ru_msgsnd),
250
- LONG2NUM(r.ru_msgrcv),
251
- LONG2NUM(r.ru_nsignals),
252
- LONG2NUM(r.ru_nvcsw),
253
- LONG2NUM(r.ru_nivcsw),
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, pid);
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
- siginfo_t infop;
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
- idtype = NUM2INT(v_type);
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
- if(waitid(idtype, id, &infop, options) == -1)
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) do not support automatically
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(RSTRING(v_val)->len > max)
758
+ if(RSTRING_LEN(v_val) >= max)
599
759
  rb_raise(rb_eArgError, "string too large");
600
- else
601
- strncpy(signame, RSTRING(v_val)->ptr, max);
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
- memset(&act, 0, sizeof(act));
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
- rb_sys_fail("sigaction");
785
+ rb_sys_fail("sigaction");
624
786
  }
625
787
  }
626
788
 
627
- return INT2FIX(pause()); /* Should always be -1 */
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
- /* 1.9.2: The version of the proc-wait3 library */
970
- rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("1.9.2")));
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 = '1.9.2'
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
@@ -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
- # via the 'rake spec' task.
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 'proc/wait3'
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('1.9.2')
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 { described_class.wait3 }.not_to raise_error
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 = described_class.wait3 }.not_to raise_error
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
- described_class.wait3
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
- described_class.wait3
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 = described_class.wait3
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
- skip 'wait4 test skipped on this platform' if hpux
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 = described_class.wait4(@pid) }.not_to raise_error
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
- described_class.wait4(@pid)
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
- described_class.wait4(@pid)
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 = described_class.wait4(@pid)
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 { described_class.waitid(Process::P_PID, @pid, Process::WEXITED) }.not_to raise_error
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 { described_class.waitid('foo', @pid, Process::WEXITED) }.to raise_error(TypeError)
155
- expect { described_class.waitid(Process::P_PID, @pid, 'foo') }.to raise_error(TypeError)
156
- expect { described_class.waitid(Process::P_PID, 'foo', Process::WEXITED) }.to raise_error(TypeError)
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
- skip 'WTRAPPED constant check skipped on this platform' if linux
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
 
@@ -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: 1.9.2
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: 2024-04-21 00:00:00.000000000 Z
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
- post_install_message:
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: 3.3.26
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