foreign.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. ;;; Copyright (C) 2010-2011,2013-2014,2024 Free Software Foundation, Inc.
  2. ;;;
  3. ;;; This library is free software: you can redistribute it and/or modify
  4. ;;; it under the terms of the GNU Lesser General Public License as
  5. ;;; published by the Free Software Foundation, either version 3 of the
  6. ;;; License, or (at your option) any later version.
  7. ;;;
  8. ;;; This library is distributed in the hope that it will be useful, but
  9. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;; Lesser General Public License for more details.
  12. ;;;
  13. ;;; You should have received a copy of the GNU Lesser General Public
  14. ;;; License along with this program. If not, see
  15. ;;; <http://www.gnu.org/licenses/>.
  16. (define-module (system foreign)
  17. #:use-module (ice-9 match)
  18. #:use-module (rnrs bytevectors)
  19. #:use-module (srfi srfi-1)
  20. #:use-module (srfi srfi-9)
  21. #:use-module (srfi srfi-9 gnu)
  22. #:use-module (srfi srfi-11)
  23. #:use-module (system base target)
  24. #:export (void
  25. float double
  26. complex-float complex-double
  27. short
  28. unsigned-short
  29. int unsigned-int long unsigned-long size_t ssize_t ptrdiff_t
  30. int8 uint8
  31. uint16 int16
  32. uint32 int32
  33. uint64 int64
  34. intptr_t uintptr_t
  35. sizeof alignof
  36. %null-pointer
  37. null-pointer?
  38. pointer?
  39. make-pointer
  40. pointer->scm
  41. scm->pointer
  42. pointer-address
  43. pointer->bytevector
  44. bytevector->pointer
  45. set-pointer-finalizer!
  46. dereference-pointer
  47. string->pointer
  48. pointer->string
  49. pointer->procedure
  50. ;; procedure->pointer (see below)
  51. read-c-struct write-c-struct
  52. make-c-struct parse-c-struct
  53. define-wrapped-pointer-type))
  54. (eval-when (expand load eval)
  55. (load-extension (string-append "libguile-" (effective-version))
  56. "scm_init_foreign"))
  57. ;;;
  58. ;;; Pointers.
  59. ;;;
  60. (define (null-pointer? pointer)
  61. "Return true if POINTER is the null pointer."
  62. (= (pointer-address pointer) 0))
  63. (if (defined? 'procedure->pointer)
  64. (export procedure->pointer))
  65. ;;;
  66. ;;; Structures.
  67. ;;;
  68. (define-syntax compile-time-eval
  69. (lambda (stx)
  70. "Evaluate the target-dependent expression EXP at compile-time if we are
  71. not cross-compiling; otherwise leave it to be evaluated at run-time."
  72. (syntax-case stx ()
  73. ((_ exp)
  74. (if (equal? (target-type) %host-type)
  75. #`(quote
  76. #,(datum->syntax #'here
  77. (primitive-eval (syntax->datum #'exp))))
  78. #'exp)))))
  79. ;; Note that in a cross-compiled Guile, the host and the target may have
  80. ;; different values of, say, `long'. However the explicitly-sized types
  81. ;; int8, float, etc have the same value on all platforms. sizeof on
  82. ;; these types is also a target-invariant primitive. alignof is notably
  83. ;; *not* target-invariant.
  84. (define-syntax switch/compile-time-keys
  85. (syntax-rules (else)
  86. ((_ x (k expr) ... (else alt))
  87. (let ((t x))
  88. (cond
  89. ((eq? t (compile-time-eval k)) expr)
  90. ...
  91. (else alt))))))
  92. (define-syntax-rule (align off alignment)
  93. (1+ (logior (1- off) (1- alignment))))
  94. (define bytevector-pointer-ref
  95. (case (sizeof '*)
  96. ((8) (lambda (bv offset)
  97. (make-pointer (bytevector-u64-native-ref bv offset))))
  98. ((4) (lambda (bv offset)
  99. (make-pointer (bytevector-u32-native-ref bv offset))))
  100. (else (error "what machine is this?"))))
  101. (define bytevector-pointer-set!
  102. (case (sizeof '*)
  103. ((8) (lambda (bv offset ptr)
  104. (bytevector-u64-native-set! bv offset (pointer-address ptr))))
  105. ((4) (lambda (bv offset ptr)
  106. (bytevector-u32-native-set! bv offset (pointer-address ptr))))
  107. (else (error "what machine is this?"))))
  108. (define-syntax-rule (define-complex-accessors (read write) (%read %write size))
  109. (begin
  110. (define (read bv offset)
  111. (make-rectangular
  112. (%read bv offset)
  113. (%read bv (+ offset size))))
  114. (define (write bv offset val)
  115. (%write bv offset (real-part val))
  116. (%write bv (+ offset size) (imag-part val)))))
  117. (define-complex-accessors
  118. (bytevector-complex-single-native-ref bytevector-complex-single-native-set!)
  119. (bytevector-ieee-single-native-ref bytevector-ieee-single-native-set! 4))
  120. (define-complex-accessors
  121. (bytevector-complex-double-native-ref bytevector-complex-double-native-set!)
  122. (bytevector-ieee-double-native-ref bytevector-ieee-double-native-set! 8))
  123. (define-syntax-rule (read-field %bv %offset %type)
  124. (let ((bv %bv)
  125. (offset %offset)
  126. (type %type))
  127. (define-syntax-rule (%read type reader)
  128. (let* ((offset (align offset (compile-time-eval (alignof type))))
  129. (val (reader bv offset)))
  130. (values val
  131. (+ offset (compile-time-eval (sizeof type))))))
  132. (define-syntax-rule (dispatch-read type (%%type reader) (... ...))
  133. (switch/compile-time-keys
  134. type
  135. (%%type (%read %%type reader))
  136. (... ...)
  137. (else
  138. (let ((offset (align offset (alignof type))))
  139. (values (%read-c-struct bv offset type)
  140. (+ offset (sizeof type)))))))
  141. (dispatch-read
  142. type
  143. (int8 bytevector-s8-ref)
  144. (uint8 bytevector-u8-ref)
  145. (int16 bytevector-s16-native-ref)
  146. (uint16 bytevector-u16-native-ref)
  147. (int32 bytevector-s32-native-ref)
  148. (uint32 bytevector-u32-native-ref)
  149. (int64 bytevector-s64-native-ref)
  150. (uint64 bytevector-u64-native-ref)
  151. (float bytevector-ieee-single-native-ref)
  152. (double bytevector-ieee-double-native-ref)
  153. (complex-float bytevector-complex-single-native-ref)
  154. (complex-double bytevector-complex-double-native-ref)
  155. ('* bytevector-pointer-ref))))
  156. (define-syntax-rule (read-c-struct %bv %offset ((field type) ...) k)
  157. (let ((bv %bv)
  158. (offset %offset)
  159. (size (compile-time-eval (sizeof (list type ...)))))
  160. (unless (<= (bytevector-length bv) (+ offset size))
  161. (error "destination bytevector too small"))
  162. (let*-values (((field offset)
  163. (read-field bv offset (compile-time-eval type)))
  164. ...)
  165. (k field ...))))
  166. (define-syntax-rule (write-field %bv %offset %type %value)
  167. (let ((bv %bv)
  168. (offset %offset)
  169. (type %type)
  170. (value %value))
  171. (define-syntax-rule (%write type writer)
  172. (let ((offset (align offset (compile-time-eval (alignof type)))))
  173. (writer bv offset value)
  174. (+ offset (compile-time-eval (sizeof type)))))
  175. (define-syntax-rule (dispatch-write type (%%type writer) (... ...))
  176. (switch/compile-time-keys
  177. type
  178. (%%type (%write %%type writer))
  179. (... ...)
  180. (else
  181. (let ((offset (align offset (alignof type))))
  182. (%write-c-struct bv offset type value)
  183. (+ offset (sizeof type))))))
  184. (dispatch-write
  185. type
  186. (int8 bytevector-s8-set!)
  187. (uint8 bytevector-u8-set!)
  188. (int16 bytevector-s16-native-set!)
  189. (uint16 bytevector-u16-native-set!)
  190. (int32 bytevector-s32-native-set!)
  191. (uint32 bytevector-u32-native-set!)
  192. (int64 bytevector-s64-native-set!)
  193. (uint64 bytevector-u64-native-set!)
  194. (float bytevector-ieee-single-native-set!)
  195. (double bytevector-ieee-double-native-set!)
  196. (complex-float bytevector-complex-single-native-set!)
  197. (complex-double bytevector-complex-double-native-set!)
  198. ('* bytevector-pointer-set!))))
  199. (define-syntax-rule (write-c-struct %bv %offset ((field type) ...))
  200. (let ((bv %bv)
  201. (offset %offset)
  202. (size (compile-time-eval (sizeof (list type ...)))))
  203. (unless (<= (bytevector-length bv) (+ offset size))
  204. (error "destination bytevector too small"))
  205. (let* ((offset (write-field bv offset (compile-time-eval type) field))
  206. ...)
  207. (values))))
  208. ;; Same as write-c-struct, but with run-time dispatch.
  209. (define (%write-c-struct bv offset types vals)
  210. (let lp ((offset offset) (types types) (vals vals))
  211. (match types
  212. (() (match vals
  213. (() #t)
  214. (_ (error "too many values" vals))))
  215. ((type . types)
  216. (match vals
  217. ((val . vals)
  218. (lp (write-field bv offset type val) types vals))
  219. (() (error "too few values" vals)))))))
  220. ;; Same as read-c-struct, but with run-time dispatch.
  221. (define (%read-c-struct bv offset types)
  222. (let lp ((offset offset) (types types))
  223. (match types
  224. (() '())
  225. ((type . types)
  226. (call-with-values (lambda () (read-field bv offset type))
  227. (lambda (val offset)
  228. (cons val (lp offset types))))))))
  229. (define (make-c-struct types vals)
  230. (let ((bv (make-bytevector (sizeof types) 0)))
  231. (%write-c-struct bv 0 types vals)
  232. (bytevector->pointer bv)))
  233. (define (parse-c-struct foreign types)
  234. (%read-c-struct (pointer->bytevector foreign (sizeof types)) 0 types))
  235. ;;;
  236. ;;; Wrapped pointer types.
  237. ;;;
  238. (define-syntax define-wrapped-pointer-type
  239. (lambda (stx)
  240. "Define helper procedures to wrap pointer objects into Scheme
  241. objects with a disjoint type. Specifically, this macro defines PRED, a
  242. predicate for the new Scheme type, WRAP, a procedure that takes a
  243. pointer object and returns an object that satisfies PRED, and UNWRAP
  244. which does the reverse. PRINT must name a user-defined object printer."
  245. (syntax-case stx ()
  246. ((_ type-name pred wrap unwrap print)
  247. (with-syntax ((%wrap (datum->syntax #'wrap (gensym "wrap"))))
  248. #'(begin
  249. (define-record-type type-name
  250. (%wrap pointer)
  251. pred
  252. (pointer unwrap))
  253. (define wrap
  254. ;; Use a weak hash table to preserve pointer identity, i.e.,
  255. ;; PTR1 == PTR2 <-> (eq? (wrap PTR1) (wrap PTR2)).
  256. (let ((ptr->obj (make-weak-value-hash-table 3000)))
  257. (lambda (ptr)
  258. (or (hash-ref ptr->obj ptr)
  259. (let ((o (%wrap ptr)))
  260. (hash-set! ptr->obj ptr o)
  261. o)))))
  262. (set-record-type-printer! type-name print)))))))