Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid orphaning chained and "other-queue" callbacks #46

Merged
merged 3 commits into from
Nov 10, 2022

Conversation

rwe
Copy link
Contributor

@rwe rwe commented Nov 4, 2022

Previously, if a callback might have called getProcessList/getProcessTree again (which does not necessarily mean a recursion problem), that callback would be added to the queue, but not processed, and no native.getProcessList would be invoked. The callback would remain orphaned until another invocation caused that queue to be flushed again.

To avoid this, we repeat the draining until the queue is empty. We use "queue.splice(0)" to atomically clear the queue, returning a batch of callbacks to process. If any of those also made requests, we repeat until the callback chain completes.

An alternative would be to splice the queue once and immediately reset requestInProgress before invoking callbacks: CreateToolhelp32Snapshot has safely completed at this point. However, that would circumvent the "too many requests" rate-limiting (?) concern mentioned in one of the comments.

rwe added 2 commits November 9, 2022 13:36
This fixes one of two causes of orphaned callbacks.

(The other cause is that only one of the two queues gets flushed after
each invocation).

Previously, if a callback might have called `getProcessList` or
`getProcessTree` again (which does *not* necessarily mean a recursion
problem), that callback would be added to the queue, but not processed,
and no `native.getProcessList` would be invoked. The callback would
remain orphaned until another invocation caused that queue to be flushed
again.

To avoid this, we repeat the draining until the queue is empty. We use
"queue.splice(0)" to atomically clear the queue, returning a batch of
callbacks to process. If any of those also made requests, we repeat
until the callback chain completes.

An alternative would be to splice the queue once and immediately reset
`requestInProgress` before invoking callbacks:
`CreateToolhelp32Snapshot` has safely completed at this point. However,
that would circumvent the "too many requests" rate-limiting (?) concern
mentioned in one of the comments.
This removes the dependency on the per-transform/-callback result types
(e.g. `IProcessTreeNode`) and "extra" arguments (e.g. `rootPid`).

`getRawProcessList` just handles "max-one" gating of those requests and
invocation of the callbacks with that (raw) result.
Tyriar
Tyriar previously approved these changes Nov 9, 2022
Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Tyriar Tyriar self-assigned this Nov 9, 2022
@Tyriar Tyriar requested a review from rzhao271 November 9, 2022 22:05
Since the transformations/filters are tracked per callback, there's no
need anymore to have multiple request queues.

In fact, the implementation of multiple queues would orphan callbacks in
one queue if a request was active on another one, since only one set of
queue's callbacks would be invoked. That no longer can happen.
@rwe rwe force-pushed the fix-orphan-callbacks branch from 1168930 to bca6934 Compare November 9, 2022 22:06
@rwe rwe changed the title fix: avoid orphaning chained callbacks fix: avoid orphaning chained and cross-queue callbacks Nov 9, 2022
@rwe rwe changed the title fix: avoid orphaning chained and cross-queue callbacks fix: avoid orphaning chained and "other-queue" callbacks Nov 9, 2022
@rwe
Copy link
Contributor Author

rwe commented Nov 9, 2022

Sorry @Tyriar I didn't see that you'd reviewed this already!

My rebase included two new commits which together fix an additional source of stale callbacks: if getProcessList() was invoked, and then getProcessTree() while that was still active, only the first queue's callbacks would invoked on that (single) completion.

The requirement to have two queues was only due to keeping that transform/filter function separate from the callback, but that was unnecessary. By binding those higher, it's possible to use a single queue and also be rid of all the extra generic-type noise.

@rwe
Copy link
Contributor Author

rwe commented Nov 9, 2022

@Tyriar
Copy link
Member

Tyriar commented Nov 9, 2022

Surprisingly we both were looking at this at the same time 5 days after the initial PR 😆

I requeued CI to see if it was just a flake.

@Tyriar Tyriar merged commit d0245cd into microsoft:main Nov 10, 2022
@rwe rwe deleted the fix-orphan-callbacks branch November 11, 2022 06:12
@Tyriar Tyriar added this to the 0.4.0 milestone Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants