Class: Winproc::Process
- Inherits:
-
Object
- Object
- Winproc::Process
- Defined in:
- lib/winproc.rb,
ext/winproc/winproc.c
Overview
---------------------------------------------------------------- Process ---
Instance Method Summary collapse
-
#_kill(*args) ⇒ Object
unreached.
-
#_wait(vms) ⇒ Object
Process#_wait(ms) -> exit code Integer, or nil on timeout (-1 ms = INFINITE).
- #alive? ⇒ Boolean
- #close ⇒ Object
- #closed? ⇒ Boolean
-
#exitstatus ⇒ Object
unreached.
-
#initialize(*args) ⇒ Object
constructor
user-facing Process.new is forbidden; alloc exists only for safe GC.
-
#kill(exit_code = 1) ⇒ Object
Hard kill (TerminateProcess); does NOT touch children (use a Job for trees).
- #pid ⇒ Object
- #stderr ⇒ Object
-
#stdin ⇒ Object
The writable/readable pipe ends, present only for :pipe stdio slots.
- #stdout ⇒ Object
-
#wait(timeout: nil) ⇒ Object
Block until the process exits; returns the exit code (Integer).
Constructor Details
#initialize(*args) ⇒ Object
user-facing Process.new is forbidden; alloc exists only for safe GC.
242 243 244 245 246 247 248 249 |
# File 'ext/winproc/winproc.c', line 242
static VALUE
process_initialize(int argc, VALUE *argv, VALUE self)
{
(void)argc; (void)argv; (void)self;
rb_raise(eError, "winproc: processes are created by Winproc.spawn / "
"Winproc.pty / Winproc.runas");
return self;
}
|
Instance Method Details
#_kill(*args) ⇒ Object
unreached
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'ext/winproc/winproc.c', line 427
static VALUE
process_kill(int argc, VALUE *argv, VALUE self)
{
process_t *pr = process_live(self);
VALUE vcode;
UINT code = 1;
DWORD r;
rb_scan_args(argc, argv, "01", &vcode);
if (!NIL_P(vcode)) code = (UINT)NUM2UINT(vcode);
if (pr->exited) return self; /* no-op if already exited */
r = WaitForSingleObject(pr->h, 0);
if (r == WAIT_OBJECT_0) {
DWORD c = 0;
if (GetExitCodeProcess(pr->h, &c)) { pr->exit_code = c; pr->exited = 1; }
return self; /* already gone */
}
if (!TerminateProcess(pr->h, code)) {
DWORD gle = GetLastError();
/* lost the race with natural exit: treat "already gone" as success */
if (gle == ERROR_ACCESS_DENIED) {
if (WaitForSingleObject(pr->h, 0) == WAIT_OBJECT_0) return self;
}
raise_gle("TerminateProcess", gle);
}
return self;
}
|
#_wait(vms) ⇒ Object
Process#_wait(ms) -> exit code Integer, or nil on timeout (-1 ms = INFINITE). Memoizes the exit code. Raises Closed if #close is in progress.
365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'ext/winproc/winproc.c', line 365
static VALUE
process_do_wait(VALUE self, VALUE vms)
{
process_t *pr = process_get(self);
pwait_args a;
if (pr->exited) return ULONG2NUM(pr->exit_code); /* memoized; works after close */
if (pr->closed) rb_raise(eClosed, "winproc: process is closed");
a.pr = pr;
a.ms_in = NUM2LL(vms); /* 64-bit: ms can exceed LONG_MAX on LLP64 (E-Slice) */
InterlockedIncrement(&pr->waiters); /* under the GVL, before the region */
return rb_ensure(process_wait_body, (VALUE)&a, process_wait_ensure, (VALUE)pr);
}
|
#alive? ⇒ Boolean
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'ext/winproc/winproc.c', line 387
static VALUE
process_alive_p(VALUE self)
{
process_t *pr = process_live(self);
DWORD r;
if (pr->exited) return Qfalse;
r = WaitForSingleObject(pr->h, 0);
if (r == WAIT_OBJECT_0) {
DWORD code = 0;
if (GetExitCodeProcess(pr->h, &code)) { pr->exit_code = code; pr->exited = 1; }
return Qfalse;
}
if (r == WAIT_TIMEOUT) return Qtrue;
raise_gle("WaitForSingleObject", GetLastError());
return Qfalse; /* unreached */
}
|
#close ⇒ Object
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
# File 'ext/winproc/winproc.c', line 482
static VALUE
process_close(VALUE self)
{
process_t *pr = process_get(self);
if (pr->closed) return Qnil;
pr->closing = 1;
if (pr->cancel_event) {
pclose_t c; c.pr = pr;
SetEvent(pr->cancel_event);
rb_thread_call_without_gvl(pclose_spin_fn, &c, NULL, NULL);
}
process_memoize_exit(pr);
if (pr->h != INVALID_HANDLE_VALUE) { CloseHandle(pr->h); pr->h = INVALID_HANDLE_VALUE; }
if (pr->cancel_event) { CloseHandle(pr->cancel_event); pr->cancel_event = NULL; }
pr->closed = 1;
return Qnil;
}
|
#closed? ⇒ Boolean
500 |
# File 'ext/winproc/winproc.c', line 500
static VALUE process_closed_p(VALUE self) { return process_get(self)->closed ? Qtrue : Qfalse; }
|
#exitstatus ⇒ Object
unreached
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'ext/winproc/winproc.c', line 404
static VALUE
process_exitstatus(VALUE self)
{
process_t *pr = process_get(self);
DWORD r;
if (pr->exited) return ULONG2NUM(pr->exit_code);
if (pr->closed) return Qnil; /* memoized value or nil after close */
/* Only read GetExitCodeProcess after WaitForSingleObject reports signaled,
* so 259 STILL_ACTIVE is never exposed as a real status (E-17). */
r = WaitForSingleObject(pr->h, 0);
if (r == WAIT_OBJECT_0) {
DWORD code = 0;
if (GetExitCodeProcess(pr->h, &code)) {
pr->exit_code = code; pr->exited = 1;
return ULONG2NUM(code);
}
raise_gle("GetExitCodeProcess", GetLastError());
}
if (r == WAIT_TIMEOUT) return Qnil; /* still running */
raise_gle("WaitForSingleObject", GetLastError());
return Qnil; /* unreached */
}
|
#kill(exit_code = 1) ⇒ Object
Hard kill (TerminateProcess); does NOT touch children (use a Job for trees).
299 300 301 |
# File 'lib/winproc.rb', line 299 def kill(exit_code = 1) _kill(exit_code) end |
#pid ⇒ Object
380 381 382 383 384 385 |
# File 'ext/winproc/winproc.c', line 380
static VALUE
process_pid(VALUE self)
{
/* never raises; works after close */
return ULONG2NUM(process_get(self)->pid);
}
|
#stderr ⇒ Object
306 |
# File 'lib/winproc.rb', line 306 def stderr = @stderr |
#stdin ⇒ Object
The writable/readable pipe ends, present only for :pipe stdio slots.
304 |
# File 'lib/winproc.rb', line 304 def stdin = @stdin |
#stdout ⇒ Object
305 |
# File 'lib/winproc.rb', line 305 def stdout = @stdout |
#wait(timeout: nil) ⇒ Object
Block until the process exits; returns the exit code (Integer). timeout
in seconds (nil = infinite); returns nil on timeout. Cooperative under a
scheduler. Memoizes the exit code.
294 295 296 |
# File 'lib/winproc.rb', line 294 def wait(timeout: nil) Winproc.run_blocking { _wait(Winproc.ms_for(timeout)) } end |