Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Support cancellation of timer operations #110
Support cancellation of timer operations #110
Changes from all commits
3eb8270
bc85772
6facb6a
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument
wheel
is unusedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a problem. Previously, operation objects are reusable, and nothing suggested you need to re-create the operation object (convenient for loops!). Now they aren't, and worse it's undocumented.
If state is needed, it needs to be moved into arguments of one of the 'lambdas' below (is API change, but you could define separate 'make-base-operation' and 'make-base-operation/stateful'). Another option is to rename 'flag' to state', make it a pair of (atomic box with flag . wheel-entry) and allow overriding the default construction of the state (
(fibers operations)
initialises to an atomic box, but it doesn't actually use its contents -- doing something with it is left entirely to the individual implementations).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that passing state around would be more elegant. In practice though, the current approach is okay IMO because the variable is closed over by the closures of the operation.
In this case, I fixed the problem you mentioned (being able to reuse a timer operation after it's been "canceled") simply by resetting the
timer-wheel
variable upon cancellation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT, there is still a problem if a single timer operation value is used concurrently from multiple fibers. (Having
guard-operation
would make this pattern work.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies @LiberalArtist, I missed this comment of yours.
Would using an atomic box (as I suggested in the first message) solve the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose it might be possible to adjust the timer wheel implementation to use atomic boxes everywhere + compare and swap, but that seems inefficient, and because two pointers need to be replaced, difficult to do correctly and verify for correctness. It seems simpler & less error-prone to me to simply add a state argument.
In case of 'replace #f' by 'atomic box containing #f', no. We need to assign things to the right thread (in particular, the right scheduler, because of work stealing(?)) and atomic boxes don't do such things, they impose ordering constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note: IIUC, if/when
guard
is created, an explicit 'state' argument could be eliminated, although a 'state' operation-construction API could still be provided for convenience.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, re atomicity, I was thinking about the
(set! timer-wheel ...)
bit, but you're saying the timer wheel implementation itself should be made atomic?I must say I'm unclear on that, though my understanding is that there's one timer wheel per scheduler and one scheduler per thread, no?
@wingo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not saying that it should be made atomic. The state version is also an option.
And that's why, if you don't go for the state version, it needs to be atomic -- you are saving a timer wheel entry of the current scheduler in the closure, and due to work stealing the fiber might migrate to another scheduler (IIUC), so the cancellation can be run from another scheduler, and fiddling with another threads data structures leads to trouble unless designed for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're checking heap sizes, best do a gc beforehand, otherwise some heavy activity could lead to false negatives (as in 'no bug detected even though it exists').
Would it be possible (and sufficiently informative & meaningful) to instead check the length of the timer wheel? Seems less finicky to me (e.g. what if in the future tests are run in parallel in a single process).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, if something finicky like heap sizes is avoided, I imagine the number of iterations could be reduced a lot (good for test performance).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that when #109 is present, the heap would grow way beyond the 2x limit that's tested here; it would not go unnoticed. (Maybe we could make the test faster but it was already reasonably fast in my experience.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How fast is 'reasonably fast'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's going to lead to false positives (*) in case of concurrent tests, or a hypothetical future 'Guile OS' where all Guile is run in a single process (with appropriate isolation, but also with a shared heap and GC).
(*) where positive = "there is a bug"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't answered yet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I missed this comment as well. Again, I really don't think there's going to be false positives here; please judge for yourself by commenting out the "cancel" function of timers to see where it goes.
That said we can always add a comment in the test to clarify that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refuse to [rewrite the foundations of operating systems, Guile processes or Fiber's test suite just to test this elementary logical conclusion]. (brackets added for clarity]. And why clarify things when you can just fix things? Surely a length check of the timer wheel would be straightforward, and less noisy than heap size information - it should even be feasible to check the exact length (two iterations should be sufficient, could be increased a little 'just in case').
Also, the question on speed remains unanswered.