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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f18822c2208220d663b7ddf89cd3ef3763185621f23ed81bf6dced9beb8b76
4
- data.tar.gz: 6a82d5550af63215cf4e62b3e390865f5f08e3b3ec30be50128791bf8b9a45a1
3
+ metadata.gz: bba2d43b0af474f64ee8879055afc649a62afed46269bafc2bea754eb2ab770b
4
+ data.tar.gz: 0b5e3a6ebc48e370c32273db28e107c068a70e08f367031011bb0c1d1c2065a8
5
5
  SHA512:
6
- metadata.gz: b015e49e3c835d2855552e3d54f2fdf047d11889f5db55ac2db246d277c9fe3ad1135e73e6cb01a0caa5d88bd93c3de361670d74dc78b3a5139c10ea86db46c7
7
- data.tar.gz: f0134f481fa6f8d3cdbdcef1e6f380727afb894e1ed754bd77b568f3a0d43118a3c71aa93f68ea7d96b15768f569fa63199782f91c5c2d729c9efc47cdb0d0ab
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', # 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,43 +255,68 @@ static VALUE proc_wait3(int argc, VALUE *argv, VALUE mod){
154
255
  flags = NUM2INT(v_flags);
155
256
  }
156
257
 
157
- bzero(&r, sizeof(r));
158
- 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);
159
262
 
160
- if(pid < 0){
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)r.ru_utime.tv_sec+(double)r.ru_utime.tv_usec/1e6),
168
- rb_float_new((double)r.ru_stime.tv_sec+(double)r.ru_stime.tv_usec/1e6),
169
- LONG2NUM(r.ru_maxrss),
170
- LONG2NUM(r.ru_ixrss),
171
- LONG2NUM(r.ru_idrss),
172
- LONG2NUM(r.ru_isrss),
173
- LONG2NUM(r.ru_minflt),
174
- LONG2NUM(r.ru_majflt),
175
- LONG2NUM(r.ru_nswap),
176
- LONG2NUM(r.ru_inblock),
177
- LONG2NUM(r.ru_oublock),
178
- LONG2NUM(r.ru_msgsnd),
179
- LONG2NUM(r.ru_msgrcv),
180
- LONG2NUM(r.ru_nsignals),
181
- LONG2NUM(r.ru_nvcsw),
182
- LONG2NUM(r.ru_nivcsw),
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
- int status;
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 = NUM2INT(v_pid);
354
+ pid = NUM2PIDT(v_pid);
226
355
 
227
356
  if(RTEST(v_flags))
228
357
  flags = NUM2INT(v_flags);
229
358
 
230
- bzero(&r, sizeof(r));
231
- 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));
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(pid < 0){
388
+ if(args.result < 0){
234
389
  rb_sys_fail("wait4");
235
390
  }
236
- else if(pid > 0){
391
+ else if(args.result > 0){
237
392
  v_last_status = rb_struct_new(v_procstat_struct,
238
- INT2FIX(pid),
239
- INT2FIX(status),
240
- rb_float_new((double)r.ru_utime.tv_sec+(double)r.ru_utime.tv_usec/1e6),
241
- rb_float_new((double)r.ru_stime.tv_sec+(double)r.ru_stime.tv_usec/1e6),
242
- LONG2NUM(r.ru_maxrss),
243
- LONG2NUM(r.ru_ixrss),
244
- LONG2NUM(r.ru_idrss),
245
- LONG2NUM(r.ru_isrss),
246
- LONG2NUM(r.ru_minflt),
247
- LONG2NUM(r.ru_majflt),
248
- LONG2NUM(r.ru_nswap),
249
- LONG2NUM(r.ru_inblock),
250
- LONG2NUM(r.ru_oublock),
251
- LONG2NUM(r.ru_msgsnd),
252
- LONG2NUM(r.ru_msgrcv),
253
- LONG2NUM(r.ru_nsignals),
254
- LONG2NUM(r.ru_nvcsw),
255
- LONG2NUM(r.ru_nivcsw),
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, pid);
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
- siginfo_t infop;
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
- idtype = NUM2INT(v_type);
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
- 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)
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) do not support automatically
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(RSTRING(v_val)->len > max)
758
+ if(RSTRING_LEN(v_val) >= max)
604
759
  rb_raise(rb_eArgError, "string too large");
605
- else
606
- strncpy(signame, RSTRING(v_val)->ptr, max);
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
- memset(&act, 0, sizeof(act));
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
- rb_sys_fail("sigaction");
785
+ rb_sys_fail("sigaction");
629
786
  }
630
787
  }
631
788
 
632
- 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
+ }
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
- /* 1.9.3: The version of the proc-wait3 library */
977
- rb_define_const(rb_mProcess, "WAIT3_VERSION", rb_str_freeze(rb_str_new2("1.9.3")));
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 = '1.9.3'
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
@@ -48,7 +48,7 @@ RSpec.describe Process do
48
48
  end
49
49
 
50
50
  example 'version constant is set to expected value' do
51
- expect(Process::WAIT3_VERSION).to eq('1.9.3')
51
+ expect(Process::WAIT3_VERSION).to eq('2.0.0')
52
52
  expect(Process::WAIT3_VERSION).to be_frozen
53
53
  end
54
54
 
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.3
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-05-04 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
@@ -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
- post_install_message:
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.4.19
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