diff --git a/knots.scm b/knots.scm index 0baaf3a..304931e 100644 --- a/knots.scm +++ b/knots.scm @@ -29,6 +29,11 @@ spawn-fiber/knots)) (define (call-with-default-io-waiters thunk) + "Run THUNK with Guile's default blocking I/O waiters active. + +This is useful when restoring the default Guile I/O waiters from +within a context (like Fibers) where different I/O waiters are used, +for example when creating a new thread from a fiber." (parameterize ((current-read-waiter (@@ (ice-9 suspendable-ports) default-read-waiter)) @@ -37,6 +42,11 @@ (thunk))) (define (wait-when-system-clock-behind) + "Block until the system clock reads at least 2001-01-02. + +Useful at startup in environments (virtual machines, embedded systems) +where the clock may start at or near the Unix epoch. Prints a warning +to the current error port every 20 seconds while waiting." ;; Jan 02 2001 02:00:00 (let ((start-of-the-year-2001 978400800)) (while (< (current-time) @@ -47,6 +57,18 @@ ;; Copied from (fibers web server) (define (call-with-sigint thunk cvar) + "Run THUNK with a SIGINT handler that signals the Fibers condition +CVAR. Restores the previous handler when THUNK returns. + +Typical usage is to pass a condition variable to this procedure and +wait on CVAR in a fiber to implement clean shutdown on Ctrl-C: + +@example +(let ((quit-cvar (make-condition))) + (call-with-sigint + (lambda () (wait quit-cvar)) + quit-cvar)) +@end example" (let ((handler #f)) (dynamic-wind (lambda () @@ -97,6 +119,11 @@ (raise-exception exn))))) (define* (display/knots obj #:optional (port (current-output-port))) + "Write OBJ to PORT (default: current output port) as a UTF-8 byte +sequence via @code{put-bytevector}. + +When used with ports without buffering, this should be safer than +display." (put-bytevector port (string->utf8 @@ -105,6 +132,8 @@ (display obj port)))))) (define (simple-format/knots port s . args) + "Like @code{simple-format} but should be safer when used with a port +without buffering." (let ((str (apply simple-format #f s args))) (if (eq? #f port) str @@ -115,6 +144,8 @@ port))))) (define (format/knots port s . args) + "Like @code{format} but should be safer when used with a port +without buffering." (let ((str (apply format #f s args))) (if (eq? #f port) str @@ -233,6 +264,10 @@ (display/knots error-string port))) (define* (spawn-fiber/knots thunk #:optional scheduler #:key parallel?) + "Spawn a fiber to run THUNK, with knots exception handling. + +Accepts the same optional SCHEDULER and @code{#:parallel?} arguments +as @code{spawn-fiber}." (spawn-fiber (lambda () (with-exception-handler diff --git a/knots/non-blocking.scm b/knots/non-blocking.scm index 4473b63..cd029fe 100644 --- a/knots/non-blocking.scm +++ b/knots/non-blocking.scm @@ -32,6 +32,16 @@ (define* (non-blocking-open-socket-for-uri uri #:key (verify-certificate? #t)) + "Open a socket for URI and return it as a non-blocking port. + +For HTTPS URIs the TLS handshake is completed while the socket is +still blocking (required because Guile's TLS wrapper does not support +non-blocking handshakes), then the underlying socket is made +non-blocking. For plain HTTP the socket is made non-blocking +immediately. + +@code{#:verify-certificate?} controls TLS certificate verification +and defaults to @code{#t}." (define tls-wrap (@@ (web client) tls-wrap)) diff --git a/knots/parallelism.scm b/knots/parallelism.scm index e1e1d90..e78e6e2 100644 --- a/knots/parallelism.scm +++ b/knots/parallelism.scm @@ -267,6 +267,16 @@ invocation of PROC finishes. REPORT is passed the results for each #:key (parallelism 1) (input-channel (make-channel)) (process-channel input-channel)) + "Convert PROC into a procedure backed by @code{#:parallelism} +(default: 1) background fibers. Returns a wrapper that sends its +arguments to one of the fibers and blocks until the result is +returned. + +@code{#:input-channel} is the channel that callers write requests to; +defaults to a fresh channel. @code{#:process-channel} is the channel +the fibers read from; defaults to @code{#:input-channel}. Setting +them differently allows external parties to bypass the wrapper and +write directly to @code{process-channel}." (for-each (lambda _ (spawn-fiber diff --git a/knots/resource-pool.scm b/knots/resource-pool.scm index 5a1332e..f06a156 100644 --- a/knots/resource-pool.scm +++ b/knots/resource-pool.scm @@ -1252,6 +1252,10 @@ to the current scheduler. pool) (define (destroy-resource-pool pool) + "Destroy POOL, preventing any new checkouts. Blocks until all +checked-out resources have been returned, running the pool's +@code{#:destructor} on each. Any fibers waiting for a resource +receive @code{&resource-pool-destroyed}." (perform-operation (choice-operation (wrap-operation @@ -1468,6 +1472,23 @@ available. Return the resource once PROC has returned." (lambda (resource) exp ...))) (define* (resource-pool-stats pool #:key (timeout 5)) + "Return an alist of statistics for POOL with the following keys: + +@table @code +@item resources +Total number of resources currently held by the pool. +@item available +Number of resources not currently checked out. +@item waiters +Number of fibers currently queued waiting for a resource. +@item checkout-failure-count +Cumulative number of checkouts where an exception was raised inside +the proc. +@end table + +Blocks waiting for the pool fiber to respond. @code{#:timeout} is +the number of seconds to wait; defaults to @code{5}. Raises +@code{&resource-pool-timeout} if the pool does not respond in time." (define channel (resource-pool-channel pool)) diff --git a/knots/sort.scm b/knots/sort.scm index dcad052..94d49f8 100644 --- a/knots/sort.scm +++ b/knots/sort.scm @@ -54,6 +54,15 @@ rest))))) (define* (fibers-sort! items less #:key parallelism) + "Sort ITEMS destructively using LESS as the comparison procedure, +using a parallel merge sort. Returns the sorted list. + +Splits ITEMS into chunks, sorts each in an eager fiber-promise in +parallel, then merges pairs of sorted chunks in parallel until one +sorted list remains. + +@code{#:parallelism} sets the number of initial chunks. Defaults to +the current fibers parallelism." (define requested-chunk-count (or parallelism (+ 1 (length (scheduler-remote-peers (current-scheduler))))))