Skip to content

Commit f070fd3

Browse files
committed
Fixes #220
1 parent 5884e5d commit f070fd3

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# Time for a ChangeLog!
2+
## 2.020
3+
* Better support for running with `-Dlibpython_clj.manual_gil=true` - `with-manual-gil`.
4+
Addresses [issue 221](https://github.com/clj-python/libpython-clj/issues/221).
5+
26
## 2.019
37
* Upgrade to clojure 1.11 as development version.
48
* Upgrade dtype-next to get rid of 1.11 warnings (and for unary min,max).

src/libpython_clj2/python.clj

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ user> (py/py. np linspace 2 3 :num 10)
126126

127127
(defmacro with-gil
128128
"Capture the gil for an extended amount of time. This can greatly speed up
129-
operations as the mutex is captured and held once as opposed to find grained
129+
operations as the mutex is captured and held once as opposed to fine grained
130130
grabbing/releasing of the mutex."
131131
[& body]
132132
`(py-ffi/with-gil
@@ -146,6 +146,33 @@ user> (py/py. np linspace 2 3 :num 10)
146146
(pygc/with-stack-context
147147
~@body)))
148148

149+
150+
(defmacro with-manual-gil
151+
"When running with -Dlibpython_clj.manual_gil=true, you need to wrap all accesses to
152+
the python runtime with this locker. This includes calls to require-python or any other
153+
pathways.
154+
155+
```clojure
156+
(with-manual-gil
157+
...)
158+
```
159+
"
160+
[& body]
161+
`(with-open [locker# (py-ffi/manual-gil-locker)]
162+
~@body))
163+
164+
165+
(defmacro with-manual-gil-stack-rc-context
166+
"When running with -Dlibpython_clj.manual_gil=true, you need to wrap all accesses to
167+
the python runtime with this locker. This includes calls to require-python or any other
168+
pathways. This macro furthermore defines a stack-based gc context to immediately release
169+
objects when the stack frame exits."
170+
[& body]
171+
`(with-manual-gil
172+
(pygc/with-stack-context
173+
~@body)))
174+
175+
149176
(declare ->jvm)
150177

151178
(defn ^:no-doc in-py-ctx

src/libpython_clj2/python/ffi.clj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,14 @@ Each call must be matched with PyGILState_Release"}
737737
(PyGILState_Release gilstate)))
738738

739739

740+
(defn ^:no-doc manual-gil-locker
741+
^java.lang.AutoCloseable []
742+
(let [gil-state (lock-gil)]
743+
(reify java.lang.AutoCloseable
744+
(close [this]
745+
(unlock-gil gil-state)))))
746+
747+
740748
(defmacro with-gil
741749
"Grab the gil and use the main interpreter using reentrant acquire-gil pathway."
742750
[& body]

test/libpython_clj2/classes_test.clj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,23 @@
4848
(is (= {"name" "ACME", "shares" 50, "price" 90}
4949
(edn/read-string (.toString new-instance))))
5050
(is (= 116.0 (py/call-attr-kw new-instance "kw_clj_fn" [1 2 3] {:a 20})))))
51+
52+
53+
(deftest new-kw-init-cls-test
54+
;;The crux of this is making instance functions to get the 'self' parameter
55+
;;passed in.
56+
(let [cls-obj (py/create-class
57+
"Stock" nil
58+
{"__init__" (py/make-kw-instance-fn
59+
(fn [[self :as args] {:as kwargs}]
60+
(py/set-attr! self "kwargs" kwargs)
61+
;;Because we did not use an arg-converter, all the
62+
;;arguments above are raw jna Pointers - borrowed
63+
;;references.
64+
;;If you don't return nil from __init__ that is an
65+
;;error.
66+
nil))})
67+
new-instance (py/cfn cls-obj "ACME" 50 :a 1 :b 2)
68+
dict (py/get-attr new-instance "kwargs")]
69+
(is (= {"a" 1 "b" 2}
70+
(py/->jvm dict)))))

0 commit comments

Comments
 (0)