/[cffi-objects]/freeable.lisp
ViewVC logotype

Diff of /freeable.lisp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 5 by rklochkov, Sun Jul 29 15:15:41 2012 UTC revision 18 by rklochkov, Sat Jan 12 21:26:46 2013 UTC
# Line 1  Line 1 
1  ;;;; -*- Mode: lisp -*-  ;;;;<author>Roman Klochkov, monk@slavsoft.surgut.ru</author>
2  ;;;  ;;;; Base classes for freeable and changeable CFFI types
 ;;; freeable.lisp --- Interface for objects, that may be freed after use  
 ;;;  
 ;;; Copyright (C) 2011, Roman Klochkov <kalimehtar@mail.ru>  
 ;;;  
3    
4  (in-package #:cffi-objects)  (in-package #:cffi-objects)
5    
6    ;;;[ [[* Memory freeing automation *]]
7    
8    #|<doc>
9    Most of new CFFI types introduced in my library will live in the dynamic
10    memory. There are different policies of memory control in different languages
11    and libraries. Sometimes caller should clean memory (like in GTK), sometimes
12    callee.
13    
14    In any case programmer should have possibility to say, if he would
15    like to free memory after function call. For example, in GTK it is common
16    for callback to return a newly-allocated string or structure, but in
17    parameters responsibility to clean memory remains to caller.
18    
19    Another common option for any type is a flag, that it is out-paramter,
20    so value of it should be translated back before freeing,
21    
22    For uniformity with CFFI :string I chose :free-from-foreign and
23    :free-to-foreign boolean flags to show, when we want to free memory. By default
24    "caller frees" model is used.
25    |#
26    
27    ;;;[ <class freeable-base>
28    
29    #|<doc> I divided freeable functional to two classes:
30    \begin{itemize}
31    \item [[freeable-base]] introduces all necessary fields and handlers
32    \item [[freeable]] have ready cffi-translator methods
33    \end{itemize}
34    |#
35    
36  (define-foreign-type freeable-base ()  (define-foreign-type freeable-base ()
37    ((free :accessor object-free :initarg :free :initform :no-transfer    ;; Should we free after translating from foreign?
38           :type (member nil :none t :all :no-transfer :transfer :container)    ((free-from-foreign :initarg :free-from-foreign
39           :documentation "Free returned or sent value.                        :reader fst-free-from-foreign-p
40  :NONE, nil -- no free at all                        :initform nil :type boolean)
41  :ALL, t -- free always (after sending to FFI, or after recieved translation)     ;; Should we free after translating to foreign?
42  :TRANSFER -- client frees, so free after recieve     (free-to-foreign :initarg :free-to-foreign
43  :NO-TRANSFER -- host frees, so free after sending to FFI.                      :reader fst-free-to-foreign-p
44  :CONTAINER -- the object is a container, ALL for container and NO-TRANSFER for                      :initform t :type boolean)))
45  contained items  
46  You should call FREE-RETURNED-IF-NEEDED and FREE-SENT-IF-NEEDED in  #|<doc>
47  appropriate places of your CFFI translators")))  Interface to [[freeable-base]] consists of three generics for describing,
48    how to free particular type: [[free-ptr]], [[free-sent-ptr]] and
49    [[free-returned-ptr]], and two functions to use in CFFI translators:
50    [[free-returned-if-needed]] and [[free-sent-if-needed]].
51    |#
52    
53    ;;;[ <generic free-ptr (type ptr)>
54    
55    #|<doc>
56    This generic describes, how to free an object with CFFI type [[type]] and
57    pointer [[ptr]]. As [[type]] should be a symbol, you should specialize
58    this generic with EQL specifier if your objects shouldn't be freed with
59    [[foreign-free]].
60    
61    One can ask, why normal specializer by type of object and [[object]] as
62    a first parameter is not used. Such strange API is developed,
63    because [[free-ptr]] is used in [[trivial-garbage:finalize]] and in some
64    implementation (for example, SBCL) finalizer shouldn't have reference
65    to finalized object.
66    
67    If you dislike it and you will not use finalizers, simply specialize or
68    redefine [[free-sent-ptr]] and [[free-returned-ptr]]
69    |#
70    
71  (defgeneric free-ptr (type ptr)  (defgeneric free-ptr (type ptr)
72    (:documentation "Called to free ptr, unless overriden free-sent-ptr    (:documentation "Called to free ptr, unless overriden free-sent-ptr
73  or free-returned-ptr.")  or free-returned-ptr. TYPE should be symbol and be specialized with EQL")
74    (:method (type ptr)    (:method (type ptr) (foreign-free ptr)))
75      (foreign-free ptr)))  
76    ;;;[ <generic free-sent-ptr>
77  (defgeneric free-sent-ptr (type ptr param)  
78    (:method ((type freeable-base) ptr param)  #|<doc>
79      (declare (ignore param))  This generic describes, how to free an object with CFFI type [[type]] and
80  ;    (format t "Free-sent-ptr: ~a ~a ~%" type ptr)  pointer [[ptr]] after sending to foreign space. It has the same parameters
81    as [[cffi:free-translated-object]]. If complex foreign type has additional
82    conditionals or any additional actions when freeing, specialize it on you type.
83    
84    Please, don't call it directly. Use [[free-sent-if-needed]] instead.
85    |#
86    
87    (defgeneric free-sent-ptr (cffi-type ptr param)
88      (:documentation "Will be called in free-translated-object.
89    CFFI-TYPE: type defined with define-foreign-type.
90    PTR: foreign pointer
91    PARAM: third parameter of free-translated-object ==
92           returned second value of translate-to-foreign.")
93      (:method ((cffi-type freeable-base) ptr param)
94      (unless (null-pointer-p ptr)      (unless (null-pointer-p ptr)
95        (free-ptr type ptr))))        (free-ptr (type-of cffi-type) ptr))))
96    
97    ;;;[ <generic free-returned-ptr>
98    
99    #|<doc>
100    This generic describes, how to free an object with CFFI type [[type]] and
101    pointer [[ptr]] after receiving from foreign space. It has the same parameters
102    as [[cffi:translate-to-foreign]]. If complex foreign type has additional
103    conditionals or any additional actions when freeing, specialize it on you type.
104    
105  (defgeneric free-returned-ptr (type ptr)  Please, don't call it directly. Use [[free-returned-if-needed]] instead.
106    (:method ((type freeable-base) ptr)  |#
107  ;    (format t "Free-returned-ptr: ~a ~a ~%" type ptr)  
108    
109    (defgeneric free-returned-ptr (cffi-type ptr)
110      (:documentation "Will be called in translate-from-foreign after conversion.
111    CFFI-TYPE: type defined with define-foreign-type.
112    PTR: foreign pointer")
113      (:method ((cffi-type freeable-base) ptr)
114      (unless (null-pointer-p ptr)      (unless (null-pointer-p ptr)
115        (free-ptr type ptr))))        (free-ptr (type-of cffi-type) ptr))))
116    
117    ;;;[ <function free-sent-if-needed
118    
119  (defun free-sent-if-needed (type ptr param)  (defun free-sent-if-needed (cffi-type ptr param)
120    (when (member (object-free type) '(t :all :container :no-transfer))    "This function should be placed in appropriate place of
121      (free-sent-ptr type ptr param)))  free-translated-object"
122      (when (fst-free-to-foreign-p cffi-type)
123  (defun free-returned-if-needed (type ptr)      (free-sent-ptr cffi-type ptr param)))
124    (when (member (object-free type) '(t :all :container :transfer))  
125      (free-returned-ptr type ptr)))  ;;;[ <function free-returned-if-needed
126    
127    (defun free-returned-if-needed (cffi-type ptr)
128      "This function should be placed in appropriate place of
129    translate-from-foreign"
130      (when (fst-free-from-foreign-p cffi-type)
131        (free-returned-ptr cffi-type ptr)))
132    
133    ;;;[ <class freeable>
134    
135    #|<doc>
136    This is standard base class for freeable pointers. If you happy with
137    default free algorithm, which implies, that [[free-sent-ptr]] is called after
138    [[free-translated-object]] when type described with [[:free-to-foreign t]]
139    and [[free-returned-ptr]] is called when type described with
140    [[:free-from-foreign t]] after [[translate-from-foreign]].
141    
142    If you need more complicated logic (for example, to free object in
143    translate-from-foreign, not after), you should inherit your class from
144    [[freeable-base]] and
145    call [[free-sent-if-needed]] from [[free-translated-object]]
146    and [[free-returned-if-needed]] from [[translate-from-foreign]].
147    |#
148    
149  (defclass freeable (freeable-base) ()  (defclass freeable (freeable-base) ()
150    (:documentation "Mixing to auto-set translators"))    (:documentation "Mixing to auto-set translators"))
# Line 56  or free-returned-ptr.") Line 155  or free-returned-ptr.")
155  (defmethod translate-from-foreign :after (ptr (type freeable))  (defmethod translate-from-foreign :after (ptr (type freeable))
156    (free-returned-if-needed type ptr))    (free-returned-if-needed type ptr))
157    
158    ;;;[ <class freeable-out>
159    
160    #|<doc>
161    This is standard base class for objects, that should be copied back
162    to lisp after foreign function: so-called ``out parameters''.
163    
164    For every class, inherited from [[freeable-out]], you must
165    implement method [[copy-from-foreign]].
166    
167    Then user of your class may set [[:out t]] in initargs for your class
168    and be sure, that all changed data will be copied back to the variables.
169    
170    When implementing [[translate-to-foreign]] you must return (values ptr value),
171    because second value will be passed to [[free-translated-object]], and then
172    as PLACE to [[copy-from-foreign]].
173    |#
174    
175  (define-foreign-type freeable-out (freeable)  (define-foreign-type freeable-out (freeable)
176    ((out :accessor object-out :initarg :out :initform t    ((out :accessor object-out :initarg :out :initform nil
177          :documentation "This is out param (for fill in foreign side)"))          :documentation "This is out param (for fill in foreign side)"))
178    (:documentation "For returning data in out params.    (:documentation "For returning data in out params.
179  To use translate-to-foreign MUST return (values ptr place)"))  If OUT is t, then translate-to-foreign MUST return (values ptr place)"))
180    
181    ;;;[ <generic copy-from-foreign>
182    
183  (defgeneric copy-from-foreign (type ptr place)  #|<doc>
184    (:documentation "Transfers data from pointer PTR to PLACE"))  This generic must have an implementation for every class inherited from [[freeable-out]].
185    |#
186    
187    (defgeneric copy-from-foreign (cffi-type ptr place)
188      (:documentation "Transfers data from pointer PTR to PLACE.
189    CFFI-TYPE: type defined with define-foreign-type.
190    PTR: foreign pointer
191    PLACE: third parameter of free-translated-object ==
192           returned second value of translate-to-foreign"))
193    
194  (defmethod free-translated-object :before (ptr (type freeable-out) place)  (defmethod free-translated-object :before (ptr (type freeable-out) place)
195    (when (object-out type)    (when (object-out type)

Legend:
Removed from v.5  
changed lines
  Added in v.18

  ViewVC Help
Powered by ViewVC 1.1.5