aboutsummaryrefslogtreecommitdiff
path: root/gnu/gnunet/concurrency/update.scm
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/gnunet/concurrency/update.scm')
-rw-r--r--gnu/gnunet/concurrency/update.scm107
1 files changed, 107 insertions, 0 deletions
diff --git a/gnu/gnunet/concurrency/update.scm b/gnu/gnunet/concurrency/update.scm
new file mode 100644
index 0000000..6a487cf
--- /dev/null
+++ b/gnu/gnunet/concurrency/update.scm
@@ -0,0 +1,107 @@
1;; This file is part of scheme-GNUnet.
2;; Copyright (C) 2021 Maxime Devos
3;;
4;; scheme-GNUnet is free software: you can redistribute it and/or modify it
5;; under the terms of the GNU Affero General Public License as published
6;; by the Free Software Foundation, either version 3 of the License,
7;; or (at your option) any later version.
8;;
9;; scheme-GNUnet is distributed in the hope that it will be useful, but
10;; WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12;; Affero General Public License for more details.
13;;
14;; You should have received a copy of the GNU Affero General Public License
15;; along with this program. If not, see <http://www.gnu.org/licenses/>.
16;;
17;; SPDX-License-Identifier: AGPL3.0-or-later
18
19;; (Can be relicensed for use in guile-fibers on request)
20
21;; A stream of values, of which the next value might not
22;; yet be determined, but can be waited upon. All can wait
23;; for an update and read the new value, but only the creator
24;; of the original update object can add new values.
25
26;; TODO implement a time machine for exploring alternate
27;; time-lines (maybe with a @code{time-machine} parameter,
28;; if time machines can be nested this way).
29
30;; Old updates are reclaimed by the garbage collector.
31;; TODO an implementation *not* relying on a garbage collector,
32;; at the cost of only allowing access to the latest value,
33;; would be nice to compare with.
34
35;; Example uses:
36;; - network-size estimation client (TODO)
37
38(define-library (gnu gnunet concurrency update)
39 (export make-update update? update-value wait-for-update-operation
40 next-update next-update-peek
41
42 &double-update double-update? make-double-update-violation)
43 (import (rnrs records syntactic)
44 (rnrs conditions)
45 (rnrs base)
46 (rnrs exceptions)
47 (srfi srfi-8)
48 (fibers conditions)
49 (fibers operations)
50 (ice-9 atomic))
51 (begin
52 (define-condition-type &double-update &violation
53 make-double-update-violation double-update?)
54
55 (define (double-update-violation)
56 (raise (condition
57 (make-who-condition 'update!)
58 (make-double-update-violation)
59 (make-message-condition "An update already exists!"))))
60
61 (define-record-type (<update> make-update update?)
62 (fields (immutable value update-value)
63 ;; value in box is #f if not yet updated,
64 ;; otherwise it is an <update>
65 (immutable next next-update-box)
66 (immutable when-next next-update-condition))
67 (protocol
68 (lambda (%make)
69 (lambda (initial)
70 "Create an update object, initialised to @var{initial}.
71Two values are returned: the update object and the update procedure."
72 (let ((update (%make initial (make-atomic-box #f)
73 (make-condition))))
74 (define (update! next-value)
75 "Update the update object to the value @var{next-value}.
76
77If the update object was already updated, raise a @code{&double-update}
78instead. If the object was updated successfully, return the next update
79object and updater."
80 (receive (next-update next-update!) (make-update next-value)
81 (case (atomic-box-compare-and-swap!
82 (next-update-box update) #f next-update)
83 ((#f)
84 (signal-condition! (next-update-condition update))
85 (values next-update next-update!))
86 (else (double-update-violation)))))
87 (values update update!)))))
88 (opaque #t)
89 (sealed #t))
90
91 (define (wait-for-update-operation update)
92 "Return an operation for waiting for the next value
93of the update @var{update}. The return value of the
94operation is the next @code{update?}."
95 (wrap-operation
96 (wait-operation (next-update-condition update))
97 (lambda ()
98 (atomic-box-ref (next-update-box update)))))
99
100 (define (next-update update)
101 "Return the next update of @var{update}."
102 (perform-operation (wait-for-update-operation update)))
103
104 (define (next-update-peek update)
105 "If the next update of @var{update} is known, return it,
106otherwise return @code{#f}."
107 (atomic-box-ref (next-update-box update)))))