1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Early definitions.
6 (in-package :iolib.syscalls
)
8 ;;;; Sizes of Standard Types
10 (defconstant size-of-char
(foreign-type-size :char
))
11 (defconstant size-of-int
(foreign-type-size :int
))
12 (defconstant size-of-long
(foreign-type-size :long
))
13 (defconstant size-of-long-long
(foreign-type-size :long-long
))
14 (defconstant size-of-pointer
(foreign-type-size :pointer
))
15 (defconstant size-of-short
(foreign-type-size :short
))
18 ;;; Error predicate that always returns NIL. Not actually used
19 ;;; because the RETURN-WRAPPER optimizes this call away.
20 (defun never-fails (errcode)
21 (declare (ignore errcode
))
24 ;;; NOTE: This is a pretty neat type that probably deserves to be
25 ;;; included in CFFI. --luis
27 ;;; This type is used by DEFSYSCALL to automatically check for errors
28 ;;; using the ERROR-PREDICATE function which is passed the foreign
29 ;;; function's return value (after going through RETURN-FILTER). If
30 ;;; ERROR-PREDICATE returns true, ERROR-GENERATOR is invoked. See the
31 ;;; RETURN-WRAPPER parse method and type translation.
32 (define-foreign-type syscall-wrapper
()
33 ((error-predicate :initarg
:error-predicate
:reader error-predicate-of
)
34 (error-location :initarg
:error-location
:reader error-location-of
)
35 (return-filter :initarg
:return-filter
:reader return-filter-of
)
36 (error-generator :initarg
:error-generator
:reader error-generator-of
)
37 (restart :initarg
:restart
:reader syscall-restart-p
)
38 (handle :initarg
:handle
:reader handle-of
)
39 (handle2 :initarg
:handle2
:reader handle2-of
)
40 (base-type :initarg
:base-type
:reader base-type-of
)))
42 (defun default-error-predicate (base-type)
45 '(lambda (s) (not (stringp s
))))
47 (case (cffi::canonicalize-foreign-type base-type
)
50 ((:char
:short
:int
:long
:long-long
)
52 ;; FIXME: go here if the canonical type is unsigned.
53 ((:unsigned-char
:unsigned-short
:unsigned-int
54 :unsigned-long
:unsigned-long-long
:void
)
57 (error "Could not choose an error-predicate function."))))))
59 (define-parse-method syscall-wrapper
60 (base-type &key handle handle2
(restart nil restart-p
)
61 (error-predicate 'never-fails error-predicate-p
)
62 (error-location :errno
)
63 (return-filter 'identity
)
64 (error-generator 'signal-syscall-error
))
65 ;; pick a default error-predicate
66 (unless error-predicate-p
67 (setf error-predicate
(default-error-predicate base-type
)))
68 (when (and (not restart-p
) (eql 't restart
))
69 (setf error-generator
'signal-syscall-error
/restart
))
70 (unless (or (eql 'never-fails error-predicate
) error-generator
)
71 (error "Function can fail but no error-generator suplied."))
72 (make-instance 'syscall-wrapper
73 :actual-type base-type
78 :error-predicate error-predicate
79 :error-location error-location
80 :return-filter return-filter
81 :error-generator error-generator
))
83 ;;; This type translator sets up the appropriate calls to
84 ;;; RETURN-FILTER, ERROR-PREDICATE and ERROR-GENERATOR around the
85 ;;; foreign function call.
86 (defmethod expand-from-foreign (value (type syscall-wrapper
))
87 (if (and (eql 'identity
(return-filter-of type
))
88 (eql 'never-fails
(error-predicate-of type
)))
90 (with-gensyms (retval errno block
)
92 `(let* ,(remove-if 'null
93 `((,retval
(convert-from-foreign ,value
',(base-type-of type
)))
94 ,(case (error-location-of type
)
95 (:errno
`(,errno
(%sys-errno
)))
96 (:return
`(,errno
,retval
)))))
97 ,(let* ((return-val-exp
98 (if (eql 'identity
(return-filter-of type
))
100 `(,(return-filter-of type
) ,retval
)))
102 (if (eql 'never-fails
(error-predicate-of type
))
104 `(if (,(error-predicate-of type
) ,retval
)
105 (,(error-generator-of type
) ,errno
106 ,(handle-of type
) ,(handle2-of type
))
108 (if (syscall-restart-p type
)
109 `(return-from ,block
,return-exp
)
111 (if (syscall-restart-p type
)
117 (defmacro signal-syscall-error
/restart
(errno)
118 `(if (= eintr
,errno
)
120 (signal-syscall-error ,errno
)))
123 (defun foreign-name (spec &optional varp
)
124 (declare (ignore varp
))
125 (check-type spec list
)
126 (destructuring-bind (first second
) spec
129 (foreign-name (list second
(ensure-list first
))))
131 (setf second
(ensure-list second
))
132 (assert (every #'stringp second
))
133 (loop :for sym
:in second
134 :if
(foreign-symbol-pointer sym
) :do
(return sym
)
136 (error "None of these foreign symbols is defined: ~{~S~^, ~}"
139 (defun parse-name-and-options (spec &optional varp
)
140 (values (cffi::lisp-name spec varp
)
141 (foreign-name spec varp
)
142 (cffi::foreign-options spec varp
)))
145 (defmacro defentrypoint
(name (&rest args
) &body body
)
147 (declaim (inline ,name
))
148 (defun ,name
,args
,@body
)))
150 (defmacro defcfun
* (name-and-opts return-type
&body args
)
151 (multiple-value-bind (lisp-name c-name options
)
152 (parse-name-and-options name-and-opts
)
154 (declaim (inline ,lisp-name
))
155 (defcfun (,c-name
,lisp-name
,@options
) ,return-type
158 (defmacro defsyscall
(name-and-opts return-type
&body args
)
159 (multiple-value-bind (lisp-name c-name options
)
160 (parse-name-and-options name-and-opts
)
162 (declaim (inline ,lisp-name
))
163 (defcfun (,c-name
,lisp-name
,@options
)
164 (syscall-wrapper ,@(ensure-list return-type
))