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

Diff of /freeable.lisp

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

revision 1 by rklochkov, Thu Feb 9 15:53:55 2012 UTC revision 13 by rklochkov, Sat Dec 22 19:24:45 2012 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    |#
34    
35  (define-foreign-type freeable-base ()  (define-foreign-type freeable-base ()
36    ((free :accessor object-free :initarg :free :initform :no-transfer    ;; Should we free after translating from foreign?
37           :type (member :none :all :no-transfer :transfer)    ((free-from-foreign :initarg :free-from-foreign
38           :documentation "Free returned or sent value.                        :reader fst-free-from-foreign-p
39  :NONE -- no free at all                        :initform nil :type boolean)
40  :ALL -- free always (after sending to FFI, or after recieved translation)     ;; Should we free after translating to foreign?
41  :TRANSFER -- client frees, so free after recieve     (free-to-foreign :initarg :free-to-foreign
42  :NO-TRANSFER -- host frees, so free after sending to FFI.                      :reader fst-free-to-foreign-p
43  You should call FREE-RETURNED-IF-NEEDED and FREE-SENT-IF-NEEDED in                      :initform t :type boolean)))
44  appropriate places of your CFFI translators")))  
45    #|<doc>
46    Interface to [[freeable-base]] consists of three generics for describing,
47    how to free particular type: [[free-ptr]], [[free-sent-ptr]] and
48    [[free-returned-ptr]], and two functions to use in CFFI translators:
49    [[free-returned-if-needed]] and [[free-sent-if-needed]].
50    |#
51    
52    ;;;[ <generic free-ptr (type ptr)>
53    
54    #|<doc>
55    This generic describes, how to free an object with CFFI type [[type]] and
56    pointer [[ptr]]. As [[type]] should be a symbol, you should specialize
57    this generic with EQL specifier if your objects shouldn't be freed with
58    [[foreign-free].
59    
60    One can ask, why normal specializer by type of object and [[object] as
61    a first parameter is not used. Such strange API is developed,
62    because [[free-ptr]] is used in [[trivial-garbage:finalize]] and in some
63    implementation (for example, SBCL) finalizer shouldn't have reference
64    to finalized object.
65    
66    If you dislike it and you will not use finalizers, simply specialize or
67    redefine [[free-sent-ptr]] and [[free-returned-ptr]]
68    |#
69    
70  (defgeneric free-ptr (type ptr)  (defgeneric free-ptr (type ptr)
71    (:documentation "Called to free ptr, unless overriden free-sent-ptr or free-returned-ptr.")    (:documentation "Called to free ptr, unless overriden free-sent-ptr
72    (:method (type ptr)  or free-returned-ptr. TYPE should be specialized with EQL")
73      (foreign-free ptr)))    (:method (type ptr) (foreign-free ptr)))
74    
75  (defgeneric free-sent-ptr (type ptr)  ;;;[ <generic free-sent-ptr>
76    (:method ((type freeable-base) ptr)  
77      (free-ptr type ptr)))  (defgeneric free-sent-ptr (cffi-type ptr param)
78      (:method ((cffi-type freeable-base) ptr param)
79  (defgeneric free-returned-ptr (type ptr)      (unless (null-pointer-p ptr)
80    (:method ((type freeable-base) ptr)        (free-ptr (type-of cffi-type) ptr))))
81      (free-ptr type ptr)))  
82    ;;;[ <generic free-returned-ptr>
83  (defun free-sent-if-needed (type ptr)  
84    (when (member (object-free type) '(:all :no-transfer))  (defgeneric free-returned-ptr (cffi-type ptr)
85      (free-sent-ptr type ptr)))    (:method ((cffi-type freeable-base) ptr)
86        (unless (null-pointer-p ptr)
87  (defun free-returned-if-needed (type ptr)        (free-ptr (type-of cffi-type) ptr))))
88    (when (member (object-free type) '(:all :transfer))  
89      (free-returned-ptr type ptr)))  ;;;[ <function free-sent-if-needed
90    
91    (defun free-sent-if-needed (cffi-type ptr param)
92      (when (fst-free-to-foreign-p cffi-type)
93        (free-sent-ptr cffi-type ptr param)))
94    
95    ;;;[ <function free-returned-if-needed
96    
97    (defun free-returned-if-needed (cffi-type ptr)
98      (when (fst-free-from-foreign-p cffi-type)
99        (free-returned-ptr cffi-type ptr)))
100    
101    ;;;[ <class freeable>
102    
103  (defclass freeable (freeable-base) ()  (defclass freeable (freeable-base) ()
104    (:documentation "Mixing to auto-set translators"))    (:documentation "Mixing to auto-set translators"))
105    
106    
107    
108  (defmethod free-translated-object :after (ptr (type freeable) param)  (defmethod free-translated-object :after (ptr (type freeable) param)
109    (declare (ignore param))    (free-sent-if-needed type ptr param))
   (free-sent-if-needed type ptr))  
110    
111  (defmethod translate-from-foreign :after (ptr (type freeable))  (defmethod translate-from-foreign :after (ptr (type freeable))
112    (free-returned-if-needed type ptr))    (free-returned-if-needed type ptr))
113    
114    ;;;[ <class freeable-out>
115    
116  (define-foreign-type freeable-out (freeable)  (define-foreign-type freeable-out (freeable)
117    ((out :accessor object-out :initarg :out :initform t    ((out :accessor object-out :initarg :out :initform nil
118          :documentation "This is out param (for fill in foreign side)"))          :documentation "This is out param (for fill in foreign side)"))
119    (:documentation "For returning data in out params.    (:documentation "For returning data in out params.
120  To use translate-to-foreign MUST return (values ptr place)"))  If OUT is t, then translate-to-foreign MUST return (values ptr place)"))
121    
122  (defgeneric copy-from-foreign (type ptr place)  (defgeneric copy-from-foreign (type ptr place)
123    (:documentation "Transfers data from pointer PTR to PLACE"))    (:documentation "Transfers data from pointer PTR to PLACE"))

Legend:
Removed from v.1  
changed lines
  Added in v.13

  ViewVC Help
Powered by ViewVC 1.1.5