33
33
:as py-proto]
34
34
[libpython-clj.jna.base :as libpy-base]
35
35
[libpython-clj.jna :as libpy]
36
+ [libpython-clj.python.gc :as pygc]
36
37
[clojure.stacktrace :as st]
37
38
[tech.jna :as jna]
38
- [tech.resource :as resource]
39
39
[tech.v2.datatype :as dtype]
40
40
[tech.v2.datatype.protocols :as dtype-proto]
41
41
[tech.v2.datatype.casting :as casting]
42
+ [tech.resource :as resource]
42
43
[tech.v2.tensor]
43
44
[clojure.tools.logging :as log])
44
45
(:import [com.sun.jna Pointer CallbackReference]
96
97
(py-proto/->jvm item options)))
97
98
98
99
99
- (def ^:dynamic *object-reference-logging* false )
100
-
100
+ (def object-reference-logging nil )
101
101
102
- (def ^:dynamic *object-reference-tracker* nil )
103
102
104
-
105
- (def ^:dynamic *pyobject-tracking-flags* [:gc ])
103
+ (def object-reference-tracker nil )
106
104
107
105
108
106
(defn incref
130
128
(if (and pyobj
131
129
(not= (Pointer/nativeValue (libpy/as-pyobj pyobj))
132
130
(Pointer/nativeValue (libpy/as-pyobj (libpy/Py_None )))))
133
- (let [interpreter (ensure-bound-interpreter )
134
- pyobj-value (Pointer/nativeValue (libpy/as-pyobj pyobj))
135
- py-type-name (name (python-type pyobj))]
136
- (when *object-reference-logging*
137
- (let [obj-data (PyObject. (Pointer. pyobj-value))]
138
- (println (format " tracking object - 0x%x:%4d:%s"
139
- pyobj-value
140
- (.ob_refcnt obj-data)
141
- py-type-name))))
142
- (when *object-reference-tracker*
143
- (swap! *object-reference-tracker*
144
- update pyobj-value #(inc (or % 0 ))))
145
- ; ;We ask the garbage collector to track the python object and notify
146
- ; ;us when it is released. We then decref on that event.
147
- (resource/track pyobj
148
- #(with-gil
149
- (try
150
- (let [refcount (refcount pyobj)
151
- obj-data (PyObject. (Pointer. pyobj-value))]
152
- (if (< refcount 1 )
153
- (log/errorf " Fatal error -- releasing object - 0x%x:%4d:%s
131
+ (do
132
+ (ensure-bound-interpreter )
133
+ (let [pyobj-value (Pointer/nativeValue (libpy/as-pyobj pyobj))
134
+ py-type-name (name (python-type pyobj))]
135
+ (when object-reference-logging
136
+ (let [obj-data (PyObject. (Pointer. pyobj-value))]
137
+ (println (format " tracking object - 0x%x:%4d:%s"
138
+ pyobj-value
139
+ (.ob_refcnt obj-data)
140
+ py-type-name))))
141
+ (when object-reference-tracker
142
+ (swap! object-reference-tracker
143
+ update pyobj-value #(inc (or % 0 ))))
144
+ ; ;We ask the garbage collector to track the python object and notify
145
+ ; ;us when it is released. We then decref on that event.
146
+ (pygc/track pyobj
147
+ ; ;No longer with-gil. Because cleanup is cooperative, the gil is
148
+ ; ;guaranteed to be captured here already.
149
+ #(try
150
+ ; ;Intentionally overshadow pyobj. We cannot access it here.
151
+ (let [pyobj (Pointer. pyobj-value)
152
+ refcount (refcount pyobj)
153
+ obj-data (PyObject. pyobj)]
154
+ (if (< refcount 1 )
155
+ (log/errorf " Fatal error -- releasing object - 0x%x:%4d:%s
154
156
Object's refcount is bad. Crash is imminent" pyobj-value refcount py-type-name)
155
- (when *object-reference-logging*
156
- (println (format " releasing object - 0x%x:%4d:%s"
157
- pyobj-value
158
- (.ob_refcnt obj-data)
159
- py-type-name))))
160
- (when *object-reference-tracker*
161
- (swap! *object-reference-tracker*
162
- update pyobj-value (fn [arg]
163
- (dec (or arg 0 ))))))
164
- (libpy/Py_DecRef (Pointer. pyobj-value))
165
- (catch Throwable e
166
- (log/error e " Exception while releasing object" ))))
167
- *pyobject-tracking-flags*))
157
+ (when object-reference-logging
158
+ (println (format " releasing object - 0x%x:%4d:%s"
159
+ pyobj-value
160
+ (.ob_refcnt obj-data)
161
+ py-type-name))))
162
+ (when object-reference-tracker
163
+ (swap! object-reference-tracker
164
+ update pyobj-value (fn [arg]
165
+ (dec (or arg 0 ))))))
166
+ (libpy/Py_DecRef (Pointer. pyobj-value))
167
+ (catch Throwable e
168
+ (log/error e " Exception while releasing object" ))))))
168
169
(do
169
170
; ;Special handling for PyNone types
170
171
(libpy/Py_DecRef pyobj)
@@ -173,9 +174,8 @@ Object's refcount is bad. Crash is imminent" pyobj-value refcount py-type-name)
173
174
174
175
(defmacro stack-resource-context
175
176
[& body]
176
- `(with-bindings {#'*pyobject-tracking-flags* [:stack :gc ]}
177
- (resource/stack-resource-context
178
- ~@body)))
177
+ `(pygc/with-stack-context
178
+ ~@body))
179
179
180
180
181
181
(defn incref-wrap-pyobject
@@ -391,37 +391,37 @@ Object's refcount is bad. Crash is imminent" pyobj-value refcount py-type-name)
391
391
doc
392
392
function]
393
393
:as method-data}]
394
- ( resource/ stack-resource- context
395
- (when-not (cfunc-instance? function)
396
- (throw (Exception.
397
- (format " Callbacks must implement one of the CFunction interfaces:
394
+ ; ;Here we really do need a resource stack context
395
+ (when-not (cfunc-instance? function)
396
+ (throw (Exception.
397
+ (format " Callbacks must implement one of the CFunction interfaces:
398
398
%s" (type function)))))
399
- (let [meth-flags (long (cond
400
- (instance? CFunction$NoArgFunction function)
401
- @libpy/METH_NOARGS
402
-
403
- (instance? CFunction$TupleFunction function)
404
- @libpy/METH_VARARGS
405
-
406
- (instance? CFunction$KeyWordFunction function)
407
- (bit-or @libpy/METH_KEYWORDS @libpy/METH_VARARGS)
408
- :else
409
- (throw (ex-info (format " Failed due to type: %s"
410
- (type function))
411
- {}))))
412
- name-ptr (jna/string->ptr name)
413
- doc-ptr (jna/string->ptr doc)]
414
- (set! (.ml_name method-def) name-ptr)
415
- (set! (.ml_meth method-def) (CallbackReference/getFunctionPointer function))
416
- (set! (.ml_flags method-def) (int meth-flags))
417
- (set! (.ml_doc method-def) doc-ptr)
418
- (.write method-def)
419
- (pyinterp/conj-forever! (assoc method-data
420
- :name-ptr name-ptr
421
- :doc-ptr doc-ptr
422
- :callback-object function
423
- :method-definition method-def))
424
- method-def) ))
399
+ (let [meth-flags (long (cond
400
+ (instance? CFunction$NoArgFunction function)
401
+ @libpy/METH_NOARGS
402
+
403
+ (instance? CFunction$TupleFunction function)
404
+ @libpy/METH_VARARGS
405
+
406
+ (instance? CFunction$KeyWordFunction function)
407
+ (bit-or @libpy/METH_KEYWORDS @libpy/METH_VARARGS)
408
+ :else
409
+ (throw (ex-info (format " Failed due to type: %s"
410
+ (type function))
411
+ {}))))
412
+ name-ptr (jna/string->ptr-untracked name)
413
+ doc-ptr (jna/string->ptr-untracked doc)]
414
+ (set! (.ml_name method-def) name-ptr)
415
+ (set! (.ml_meth method-def) (CallbackReference/getFunctionPointer function))
416
+ (set! (.ml_flags method-def) (int meth-flags))
417
+ (set! (.ml_doc method-def) doc-ptr)
418
+ (.write method-def)
419
+ (pyinterp/conj-forever! (assoc method-data
420
+ :name-ptr name-ptr
421
+ :doc-ptr doc-ptr
422
+ :callback-object function
423
+ :method-definition method-def))
424
+ method-def))
425
425
426
426
427
427
(defn method-def-data->method-def
0 commit comments