Class: Winreg::Watch
- Inherits:
-
Object
- Object
- Winreg::Watch
- Defined in:
- lib/winreg.rb,
ext/winreg/winreg.c
Overview
A change-notification registration (constructed only via Key#watch). Armed at construction and re-armed before every delivery, so no final state is ever missed; deliveries coalesce (:changed means ">= 1 matching change since the previous delivery") and carry no payload.
Class Method Summary collapse
-
._new(vroot, vsub, vview, vsubtree, vfilter) ⇒ Object
Watch._new(root, subpath_or_nil, view_sam, subtree, filter) — private singleton.
Instance Method Summary collapse
-
#close ⇒ Object
Watch#close — step 5.
- #closed? ⇒ Boolean
-
#wait(timeout: nil) ⇒ Object
-> :changed (rearmed; ready to wait again) :deleted (watched key was deleted; the watch auto-closes) nil (timeout elapsed; registration still armed) timeout in seconds (nil = infinite).
Class Method Details
._new(vroot, vsub, vview, vsubtree, vfilter) ⇒ Object
Watch._new(root, subpath_or_nil, view_sam, subtree, filter) — private singleton. Opens its OWN handle (KEY_NOTIFY | view) by path, creates the two private events, and arms the first registration so changes between construction and the first #wait are caught. Any failure: capture code, close what was opened, raise.
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 |
# File 'ext/winreg/winreg.c', line 620
static VALUE
watch_s_new(VALUE klass, VALUE vroot, VALUE vsub, VALUE vview, VALUE vsubtree, VALUE vfilter)
{
VALUE obj = watch_alloc(cWatch);
watch_t *w = watch_get(obj);
HKEY root = root_hkey(vroot);
DWORD view = (DWORD)NUM2ULONG(vview);
DWORD filter = (DWORD)NUM2ULONG(vfilter) | REG_NOTIFY_THREAD_AGNOSTIC;
BOOL subtree = RTEST(vsubtree) ? TRUE : FALSE;
HKEY h = NULL;
LONG rc;
DWORD gle;
if (NIL_P(vsub)) {
/* bare root: the predefined pseudo-handle itself carries KEY_NOTIFY */
h = root;
w->predefined = 1;
} else {
WCHAR *ws = to_wide(vsub);
rc = RegOpenKeyExW(root, ws, 0, KEY_NOTIFY | view, &h);
xfree(ws);
if (rc != ERROR_SUCCESS) raise_lstatus("RegOpenKeyExW", rc);
}
w->hkey = h; /* owned from here: free hook / teardown closes it */
w->notify_event = CreateEventW(NULL, FALSE, FALSE, NULL); /* auto-reset */
if (!w->notify_event) {
gle = GetLastError();
watch_teardown(w);
raise_gle("CreateEvent", gle);
}
w->stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); /* manual-reset */
if (!w->stop_event) {
gle = GetLastError();
watch_teardown(w);
raise_gle("CreateEvent", gle);
}
rc = RegNotifyChangeKeyValue(w->hkey, subtree, filter, w->notify_event, TRUE);
if (rc != ERROR_SUCCESS) {
watch_teardown(w);
raise_lstatus("RegNotifyChangeKeyValue", rc);
}
w->filter = filter;
w->subtree = subtree;
w->closed = 0;
return obj;
}
|
Instance Method Details
#close ⇒ Object
Watch#close — step 5. Idempotent; unblocks a concurrent #wait (which then
raises Closed in the waiting thread). Handles MUST NOT be closed while
another thread waits on them: if waiting, the teardown is deferred to the
waiter's next wake (step 4a, which every wake path executes). waiting is
only ever cleared with the GVL held, so waiting == 0 guarantees no thread
is blocked on the handles.
805 806 807 808 809 810 811 812 813 814 815 816 817 |
# File 'ext/winreg/winreg.c', line 805
static VALUE
watch_close(VALUE self)
{
watch_t *w = watch_get(self);
if (w->closed) return Qnil;
w->closed = 1;
if (w->waiting) {
SetEvent(w->stop_event);
return Qnil;
}
watch_teardown(w);
return Qnil;
}
|
#closed? ⇒ Boolean
819 |
# File 'ext/winreg/winreg.c', line 819
static VALUE watch_closed_p(VALUE self) { return watch_get(self)->closed ? Qtrue : Qfalse; }
|
#wait(timeout: nil) ⇒ Object
-> :changed (rearmed; ready to wait again) :deleted (watched key was deleted; the watch auto-closes) nil (timeout elapsed; registration still armed) timeout in seconds (nil = infinite). Cooperates with a fiber scheduler via Winreg.run_blocking; standalone it releases the GVL and is interruptible. Raises Closed if closed (incl. closed by another thread mid-wait); Winreg::Error if another wait is already in flight (single-waiter); OSError on a rearm failure other than ERROR_KEY_DELETED.
651 652 653 654 |
# File 'lib/winreg.rb', line 651 def wait(timeout: nil) ms = Winreg.ms_for(timeout) Winreg.run_blocking { _wait(ms) } end |