Idiomatic Clojure references for BPF data structures.
This namespace provides Clojure reference types that implement standard protocols (IDeref, IBlockingDeref, IAtom, ITransientCollection), enabling natural use of @, deref, reset!, swap!, and conj! with BPF maps.
== Read-Only References ==
RingBufRef - Blocking reads from ring buffers @ref ; blocks until event available (deref ref 1000 nil) ; 1s timeout
QueueRef/StackRef - Blocking pops from queue/stack maps @ref ; blocks until item available
MapWatcher - Watch for a key to appear/change @ref ; blocks until key exists
== Writable References ==
MapEntryRef - Atom-like access to map entries @ref ; read value (reset! ref val) ; write value (swap! ref inc) ; read-modify-write
QueueWriter/StackWriter - Push to queues/stacks (conj! ref val) ; push value @ref ; peek (non-blocking)
QueueChannel/StackChannel - Bidirectional access (conj! ref val) ; push @ref ; blocking pop
Idiomatic Clojure references for BPF data structures. This namespace provides Clojure reference types that implement standard protocols (IDeref, IBlockingDeref, IAtom, ITransientCollection), enabling natural use of @, deref, reset!, swap!, and conj! with BPF maps. == Read-Only References == 1. RingBufRef - Blocking reads from ring buffers @ref ; blocks until event available (deref ref 1000 nil) ; 1s timeout 2. QueueRef/StackRef - Blocking pops from queue/stack maps @ref ; blocks until item available 3. MapWatcher - Watch for a key to appear/change @ref ; blocks until key exists == Writable References == 4. MapEntryRef - Atom-like access to map entries @ref ; read value (reset! ref val) ; write value (swap! ref inc) ; read-modify-write 5. QueueWriter/StackWriter - Push to queues/stacks (conj! ref val) ; push value @ref ; peek (non-blocking) 6. QueueChannel/StackChannel - Bidirectional access (conj! ref val) ; push @ref ; blocking pop
(map-entry-ref bpf-map key & {:keys [validator]})Create an atom-like reference to a specific key in a BPF map.
Supports standard Clojure atom operations:
Note: swap! and compare-and-set! are NOT truly atomic at the kernel level for hash maps. For true atomicity with concurrent BPF programs, use atomic BPF map operations within the BPF program itself.
Options:
Example: (let [counter (map-entry-ref stats-map :packet-count)] ;; Read (println "Count:" @counter)
;; Write
(reset! counter 0)
;; Read-modify-write
(swap! counter inc)
(swap! counter + 10)
(.close counter))
Create an atom-like reference to a specific key in a BPF map.
Supports standard Clojure atom operations:
- @ref / (deref ref) - read current value
- (reset! ref val) - set new value
- (swap! ref f) - read-modify-write
- (compare-and-set! ref old new) - conditional update
Note: swap! and compare-and-set! are NOT truly atomic at the kernel level
for hash maps. For true atomicity with concurrent BPF programs, use
atomic BPF map operations within the BPF program itself.
Options:
- :validator - Function to validate new values (throws on invalid)
Example:
(let [counter (map-entry-ref stats-map :packet-count)]
;; Read
(println "Count:" @counter)
;; Write
(reset! counter 0)
;; Read-modify-write
(swap! counter inc)
(swap! counter + 10)
(.close counter))(map-watch bpf-map key & {:keys [poll-interval-ms] :or {poll-interval-ms 10}})Create a deref-able watcher for a specific key in a BPF map.
The returned reference blocks until the key has a value:
@ref ; blocks until key exists in map (deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
Example: ;; Wait for a counter to be initialized (let [watcher (map-watch stats-map :packet-count)] (try (let [initial-count (deref watcher 5000 0)] (println "Initial count:" initial-count)) (finally (.close watcher))))
Create a deref-able watcher for a specific key in a BPF map.
The returned reference blocks until the key has a value:
@ref ; blocks until key exists in map
(deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
- :poll-interval-ms - How often to check the map (default: 10ms)
Example:
;; Wait for a counter to be initialized
(let [watcher (map-watch stats-map :packet-count)]
(try
(let [initial-count (deref watcher 5000 0)]
(println "Initial count:" initial-count))
(finally
(.close watcher))))(map-watch-changes bpf-map
key
&
{:keys [poll-interval-ms initial-value]
:or {poll-interval-ms 10 initial-value nil}})Create a watcher that blocks until a map value changes.
Unlike map-watch which returns when any value exists, this watcher only returns when the value differs from the last observed value.
@ref ; blocks until value changes (deref ref 1000 nil) ; waits up to 1000ms for change
Options:
Example: ;; Watch for counter updates (let [watcher (map-watch-changes stats-map :counter)] (try (loop [count 0] (when (< count 10) (let [new-val @watcher] (println "Counter changed to:" new-val) (recur (inc count))))) (finally (.close watcher))))
Create a watcher that blocks until a map value changes.
Unlike map-watch which returns when any value exists, this watcher
only returns when the value differs from the last observed value.
@ref ; blocks until value changes
(deref ref 1000 nil) ; waits up to 1000ms for change
Options:
- :poll-interval-ms - How often to check the map (default: 10ms)
- :initial-value - Consider this the 'last' value initially
Example:
;; Watch for counter updates
(let [watcher (map-watch-changes stats-map :counter)]
(try
(loop [count 0]
(when (< count 10)
(let [new-val @watcher]
(println "Counter changed to:" new-val)
(recur (inc count)))))
(finally
(.close watcher))))(queue-channel bpf-map & {:keys [poll-interval-ms] :or {poll-interval-ms 10}})Create a bidirectional channel-like reference to a BPF queue.
Combines reading and writing:
This is useful for producer-consumer patterns where userspace both reads and writes to the same queue.
Options:
Example: (let [ch (queue-channel work-queue)] ;; Producer thread (future (dotimes [i 100] (conj! ch {:task i})))
;; Consumer thread
(future
(loop []
(when-let [task (deref ch 5000 nil)]
(process task)
(recur))))
(.close ch))
Create a bidirectional channel-like reference to a BPF queue.
Combines reading and writing:
- @ref / (deref ref timeout val) - blocking pop (FIFO)
- (conj! ref val) - push to queue
This is useful for producer-consumer patterns where userspace
both reads and writes to the same queue.
Options:
- :poll-interval-ms - How often to poll when waiting (default: 10ms)
Example:
(let [ch (queue-channel work-queue)]
;; Producer thread
(future
(dotimes [i 100]
(conj! ch {:task i})))
;; Consumer thread
(future
(loop []
(when-let [task (deref ch 5000 nil)]
(process task)
(recur))))
(.close ch))(queue-ref bpf-map & {:keys [poll-interval-ms] :or {poll-interval-ms 10}})Create a deref-able reference to a queue map.
The returned reference supports blocking pop operations via deref:
@ref ; blocks until item available (FIFO pop) (deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
Example: (let [ref (queue-ref my-queue)] (try (loop [] (when-let [item @ref] (process item) (recur))) (finally (.close ref))))
Create a deref-able reference to a queue map.
The returned reference supports blocking pop operations via deref:
@ref ; blocks until item available (FIFO pop)
(deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
- :poll-interval-ms - How often to check for items (default: 10ms)
Example:
(let [ref (queue-ref my-queue)]
(try
(loop []
(when-let [item @ref]
(process item)
(recur)))
(finally
(.close ref))))(queue-seq ref
&
{:keys [timeout-ms timeout-val]
:or {timeout-ms Long/MAX_VALUE timeout-val :clj-ebpf.refs/timeout}})Returns a lazy sequence that pops items from a queue.
Each element retrieval blocks until an item is available.
Options:
Example: (let [ref (queue-ref my-queue)] (try (doseq [item (take 50 (queue-seq ref))] (process item)) (finally (.close ref))))
Returns a lazy sequence that pops items from a queue.
Each element retrieval blocks until an item is available.
Options:
- :timeout-ms - Timeout for each pop (default: infinite)
- :timeout-val - Value returned on timeout (stops sequence if ::timeout)
Example:
(let [ref (queue-ref my-queue)]
(try
(doseq [item (take 50 (queue-seq ref))]
(process item))
(finally
(.close ref))))(queue-writer bpf-map)Create a writable reference to a BPF queue map.
Supports conj! for adding items:
For blocking pop, use queue-ref instead.
Example: (let [q (queue-writer my-queue)] ;; Add items (-> q (conj! {:event :start}) (conj! {:event :data :value 42}) (conj! {:event :end}))
;; Peek (non-blocking)
(println "Front:" @q)
(.close q))
Create a writable reference to a BPF queue map.
Supports conj! for adding items:
- (conj! ref val) - push value to queue (enqueue)
- @ref - peek at front value without removing
For blocking pop, use queue-ref instead.
Example:
(let [q (queue-writer my-queue)]
;; Add items
(-> q
(conj! {:event :start})
(conj! {:event :data :value 42})
(conj! {:event :end}))
;; Peek (non-blocking)
(println "Front:" @q)
(.close q))(ringbuf-ref ringbuf-map & {:keys [deserializer] :or {deserializer identity}})Create a deref-able reference to a ring buffer.
The returned reference supports the @ reader macro for blocking reads:
@ref ; blocks indefinitely until event available (deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
The reference must be closed when done to release resources:
(.close ref)
Example: (let [ref (ringbuf-ref my-ringbuf :deserializer parse-event)] (try (loop [] (when-let [event (deref ref 5000 nil)] (process event) (recur))) (finally (.close ref))))
Create a deref-able reference to a ring buffer.
The returned reference supports the @ reader macro for blocking reads:
@ref ; blocks indefinitely until event available
(deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
- :deserializer - Function to transform raw event bytes (default: identity)
The reference must be closed when done to release resources:
(.close ref)
Example:
(let [ref (ringbuf-ref my-ringbuf :deserializer parse-event)]
(try
(loop []
(when-let [event (deref ref 5000 nil)]
(process event)
(recur)))
(finally
(.close ref))))(ringbuf-seq ref
&
{:keys [timeout-ms timeout-val]
:or {timeout-ms Long/MAX_VALUE
timeout-val :clj-ebpf.refs/timeout}})Returns a lazy sequence of ring buffer events.
Each call to the sequence blocks until an event is available. The sequence is infinite - use take or other limiting functions.
Options:
Example: ;; Process 100 events (let [ref (ringbuf-ref my-ringbuf)] (try (doseq [event (take 100 (ringbuf-seq ref))] (process event)) (finally (.close ref))))
;; With timeout - sequence ends on timeout (doseq [event (ringbuf-seq ref :timeout-ms 5000)] (process event))
Returns a lazy sequence of ring buffer events.
Each call to the sequence blocks until an event is available.
The sequence is infinite - use take or other limiting functions.
Options:
- :deserializer - Function to transform raw event bytes
- :timeout-ms - Timeout for each read (default: infinite)
- :timeout-val - Value returned on timeout (stops sequence if nil)
Example:
;; Process 100 events
(let [ref (ringbuf-ref my-ringbuf)]
(try
(doseq [event (take 100 (ringbuf-seq ref))]
(process event))
(finally
(.close ref))))
;; With timeout - sequence ends on timeout
(doseq [event (ringbuf-seq ref :timeout-ms 5000)]
(process event))(stack-channel bpf-map & {:keys [poll-interval-ms] :or {poll-interval-ms 10}})Create a bidirectional channel-like reference to a BPF stack.
Combines reading and writing:
Options:
Example: (let [ch (stack-channel undo-stack)] ;; Push operations (conj! ch {:action :insert :pos 0 :text "Hello"}) (conj! ch {:action :insert :pos 5 :text " World"})
;; Pop to undo (LIFO)
(let [last-op @ch]
(undo last-op))
(.close ch))
Create a bidirectional channel-like reference to a BPF stack.
Combines reading and writing:
- @ref / (deref ref timeout val) - blocking pop (LIFO)
- (conj! ref val) - push to stack
Options:
- :poll-interval-ms - How often to poll when waiting (default: 10ms)
Example:
(let [ch (stack-channel undo-stack)]
;; Push operations
(conj! ch {:action :insert :pos 0 :text "Hello"})
(conj! ch {:action :insert :pos 5 :text " World"})
;; Pop to undo (LIFO)
(let [last-op @ch]
(undo last-op))
(.close ch))(stack-ref bpf-map & {:keys [poll-interval-ms] :or {poll-interval-ms 10}})Create a deref-able reference to a stack map.
The returned reference supports blocking pop operations via deref:
@ref ; blocks until item available (LIFO pop) (deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
Example: (let [ref (stack-ref my-stack)] (try (when-let [item (deref ref 5000 :empty)] (process item)) (finally (.close ref))))
Create a deref-able reference to a stack map.
The returned reference supports blocking pop operations via deref:
@ref ; blocks until item available (LIFO pop)
(deref ref 1000 nil) ; waits up to 1000ms, returns nil on timeout
Options:
- :poll-interval-ms - How often to check for items (default: 10ms)
Example:
(let [ref (stack-ref my-stack)]
(try
(when-let [item (deref ref 5000 :empty)]
(process item))
(finally
(.close ref))))(stack-writer bpf-map)Create a writable reference to a BPF stack map.
Supports conj! for adding items:
For blocking pop, use stack-ref instead.
Example: (let [s (stack-writer my-stack)] ;; Push items (conj! s :first) (conj! s :second) (conj! s :third)
;; Peek (non-blocking)
(println "Top:" @s) ; => :third
(.close s))
Create a writable reference to a BPF stack map.
Supports conj! for adding items:
- (conj! ref val) - push value to stack
- @ref - peek at top value without removing
For blocking pop, use stack-ref instead.
Example:
(let [s (stack-writer my-stack)]
;; Push items
(conj! s :first)
(conj! s :second)
(conj! s :third)
;; Peek (non-blocking)
(println "Top:" @s) ; => :third
(.close s))(with-map-entry-ref [binding bpf-map key & opts] & body)Create a map entry reference with automatic cleanup.
Example: (with-map-entry-ref [counter stats-map :packet-count] (println "Before:" @counter) (swap! counter inc) (println "After:" @counter))
Create a map entry reference with automatic cleanup.
Example:
(with-map-entry-ref [counter stats-map :packet-count]
(println "Before:" @counter)
(swap! counter inc)
(println "After:" @counter))(with-map-watcher [binding bpf-map key & opts] & body)Create a map watcher with automatic cleanup.
Example: (with-map-watcher [w stats-map :packet-count] (println "Packets:" @w))
Create a map watcher with automatic cleanup.
Example:
(with-map-watcher [w stats-map :packet-count]
(println "Packets:" @w))(with-queue-channel [binding queue-map & opts] & body)Create a queue channel with automatic cleanup.
Example: (with-queue-channel [ch work-queue] (conj! ch {:task :process}) (let [result @ch] (handle result)))
Create a queue channel with automatic cleanup.
Example:
(with-queue-channel [ch work-queue]
(conj! ch {:task :process})
(let [result @ch]
(handle result)))(with-queue-ref [binding queue-map & opts] & body)Create a queue reference with automatic cleanup.
Example: (with-queue-ref [ref my-queue] (when-let [item (deref ref 5000 nil)] (process item)))
Create a queue reference with automatic cleanup.
Example:
(with-queue-ref [ref my-queue]
(when-let [item (deref ref 5000 nil)]
(process item)))(with-queue-writer [binding queue-map] & body)Create a queue writer with automatic cleanup.
Example: (with-queue-writer [q my-queue] (conj! q {:event :start}) (conj! q {:event :end}))
Create a queue writer with automatic cleanup.
Example:
(with-queue-writer [q my-queue]
(conj! q {:event :start})
(conj! q {:event :end}))(with-ringbuf-ref [binding ringbuf-map & opts] & body)Create a ring buffer reference with automatic cleanup.
Example: (with-ringbuf-ref [ref my-ringbuf :deserializer parse-event] (dotimes [_ 10] (println @ref)))
Create a ring buffer reference with automatic cleanup.
Example:
(with-ringbuf-ref [ref my-ringbuf :deserializer parse-event]
(dotimes [_ 10]
(println @ref)))(with-stack-channel [binding stack-map & opts] & body)Create a stack channel with automatic cleanup.
Example: (with-stack-channel [ch undo-stack] (conj! ch {:op :insert}) (when-let [op (deref ch 1000 nil)] (undo op)))
Create a stack channel with automatic cleanup.
Example:
(with-stack-channel [ch undo-stack]
(conj! ch {:op :insert})
(when-let [op (deref ch 1000 nil)]
(undo op)))(with-stack-ref [binding stack-map & opts] & body)Create a stack reference with automatic cleanup.
Example: (with-stack-ref [ref my-stack] (when-let [item @ref] (process item)))
Create a stack reference with automatic cleanup.
Example:
(with-stack-ref [ref my-stack]
(when-let [item @ref]
(process item)))(with-stack-writer [binding stack-map] & body)Create a stack writer with automatic cleanup.
Example: (with-stack-writer [s my-stack] (conj! s :a) (conj! s :b))
Create a stack writer with automatic cleanup.
Example:
(with-stack-writer [s my-stack]
(conj! s :a)
(conj! s :b))cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |