~shunter/posix-shm

POSIX shared memory bindings for Common Lisp

6153655 Expand unit test suite

3 days ago

e251dda Quickfix test case trips new type assertion

4 days ago

#POSIX shared memory for Common Lisp

builds.sr.ht status Quicklisp status

Common Lisp bindings and wrapper for the POSIX shared memory API.

The POSIX shared memory (or shm) API "allows processes to communicate information by sharing a region of memory." (shm_overview(7)). This library provides two strata to access the POSIX shm API:

  • The package posix-shm/ffi, a collection of slim bindings to the POSIX API. FFI Reference
  • The package posix-shm, a lispy wrapper around the FFI that integrates more closely to the features of Common Lisp, and provides a handful of utilities and macros. API Reference

Features include:

  • Open, close, create, resize, change ownership of, change permissions of, and memory map to shared memory objects.
  • open-shm appears more like open from the standard library.
  • open-shm*, for creating anonymous shm objects.
  • with-open-shm, with-mmap and similar with- macros for safely accessing resources with dynamic extent.

#Installation and Usage

Install posix-shm with Quicklisp:

* (ql:quickload :posix-shm)
* (use-package :posix-shm)

* (defparameter +shm-size+
    (* 10 (cffi:foreign-type-size :int)))
+SHM-SIZE+

* (defvar *shm*)
*SHM*
* (setf *shm* (open-shm "/foobar-shm" :direction :io :if-does-not-exist :create
                        :permissions '(:user-read :user-write)))
#<SHM for "/foobar-shm" {10056A8F03}>
* (print (shm-file-descriptor *shm*)) ;; Your mileage may vary
4

* (truncate-shm *shm* +shm-size+)

* (defparameter *ptr1*
    (mmap-shm (cffi:null-pointer) +shm-size+ '(:write) *shm* 0))
*PTR1*

* (defparameter *ptr2*
    (mmap-shm (cffi:null-pointer) +shm-size+ '(:read) *shm* 0))
*PTR2*

* (dotimes (i 10)
    (setf (cffi:mem-aref *ptr1* :int i) (* i 10)))
* (dotimes (i 10)
    (print (cffi:mem-aref *ptr2* :int i)))
0
10
20
30
40
50
60
70
80
90
NIL

* (munmap *ptr1* +shm-size+)
* (munmap *ptr2* +shm-size+)
* (close-shm *shm*)
T
* (delete-shm "/foobar-shm")

Use with-open-shm and with-mmap to automatically close and munmap when the program leaves scope:

(with-open-shm (shm "/foobar-shm" :direction :io)
  (truncate-shm shm 100)
  (with-mmap (ptr (cffi:null-pointer) 100 '(:read :write) shm 0)
    ;; do your thing...
    ))

with-open-shm-and-mmap opens a shm, truncates it, and then maps it to a pointer all in one:

(with-mmapped-shm (shm ptr ("/foobar-shm" :direction :io)
	               ((cffi:null-pointer) 100 '(:read :write) 0))
  ;; do your thing...
  )

Use open-shm* and with-open-shm* to create anonymous shm objects that are unlinked the moment they are created:

(defvar *anon-shm* (open-shm* :direction :io :permissions '(:user-all))
;; do your thing...
(close-shm *anon-shm*)

(with-open-shm* (anon-shm :direction :io :permissions '(:user-all))
  ;; do your thing...
  )

#Contributing

Any comments, questions, issues, or patches are greatly appreciated! I do my main development on Sourcehut, with a mailing list and issue tracker.

#Reference

Descriptions of types, classes, functions, and macros of the high-level API are in the API Reference.

Descriptions of the lower-level foreign types and bindings are in the FFI Reference.