[[tags: egg]] == simple-timer Simple, cancel-able, efficient timers. Currently only a low level interface is provided. TBD: Support [[https://srfi.schemers.org/srfi-120/srfi-120.html|srfi-120]] too. == Rationale The srfi-120 API incurs just too much overhead for many use cases to settle upon. (The issue: srfi120's task identifiers as returned by {{timer-schedule!}} are defined to be readable object, which adds undue overhead for cancellation.) Every other egg implements it's own idea of timers, which makes for a hell to mix them. This should be(come) a low level enough interface to support most needs while having all timers in one place. Another issue frequently coming up with CHICKEN is the false deadlock detection when signal handlers are used to unlock the situation. The common work around to load yet another thread looping for some time puts load at the core's timeout queue. Simply using this egg should install one such timer once and for all. (TBD: make sure this works over forks too. Should this cancel timeouts?) The timers here are assumed mostly timeouts or regular background jobs and hence rarely run. They should not be sensitive to precise timings. (It is the job of this eggs timers to reduce the load on the timeout queue in chickens core and optimize for minimal overhead for timers canceled within less than a {{timer-period}}.) Timeouts fire only if they are not canceled before at least a full {{timer-period}} passed. A {{timer-period}} defaults to one second. Timers are run in batches rounded to {{timer-epsilon}} of it's scheduled time every {{timer-period}}. == Requirements Requires [[llrb-tree]], [[pigeon-hole]]. Notes: * Could use any other priority queue conforming to the srfi-69 API instead of llrb-tree * pigeon-hole is merely for historical reasons == API (timer-period . new) -> PERIOD Without argument queries the current period. With argument chances the period at which timers are fired. (timer-epsilon . new) -> PERIOD Without argument queries the current epsilon. With argument chances the epsilon for grouping timers by due time. (timer-condition? obj) -> boolean Predicate to test for timer conditions. (make-timer-condition) Creates a timer condition. (register-timer-task! time job) -> TASK Registers {{JOB}} to be run after {{TIME}} has passed. Returns a reference to the task. The reference is opaque by definition - unlike srfi-120 {{timer-schedule!}}'s task identifiers. In fact it is a pair. The job is typically a thunk to be executed. This thunk MUST NOT raise exceptions, MAY NOT block and SHOULD return ASAP. So except for simple, fast operations it should schedule the actual operation, e.g. by starting a fresh thread, and return. If a thread is given as {{JOB}}, it will receive a {{timer-condition?}} via {{thread-signal!}}. Undocumented: if a {{pigeon-hole}} is given as {{JOB}} a {{timer-condition?}} is unconditionally queued. (cancel-timer-task! TASK) -> boolean Cancels the TASK (must be a reference obtained from {{register-timer-task!}}). (In fact it atomically sets the cdr of the reference to {{#f}} and returns the old value.) Returns {{#f}} if the {{TASK}} was already canceled or fired. == Examples (handle-exceptions ex (cond ((timer-condition? ex) #t) (else ex)) (register-timer-task! 1 (current-thread)) (thread-sleep! 3) 'timer-exceptions-should-have-occurred-before) => #t Cancelation: {{set! b #t}} is never invoked. (or (cancel-timer-task! (register-timer-task! 0.03 (lambda () (set! b #t)))) (error "too late to cancel timer")) Best practice using thread signals: (let ((task #f)) (handle-exceptions ex (cond ((timer-condition? ex) ;; clean up after timeout here #t) (else (or (cancel-timer-task! task) (error "too late to cancel, that's bad")) ex)) ... (set! task (register-timer-task! 1 (current-thread))) (let ((result (do-some-work-within-time-limit))) (cancel-timer-task! task) ... result))) Best practice using messages (try to avoid needless {{dynamic-wind}}s in this context): (let* ((chan (gochan 0)) (task (register-timer-task! 1 (lambda () (go (gochan-send chan (make-timer-condition))))) ) (result (do-some-work-with chan))) (cancel-timer-task! task) result) == About this egg === Source Latest version: [[http://github.com/0-8-15/simple-timer]] === Version History 0.1: Initial version. === Authors Jörg F. Wittenberger === License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ASIS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.