@@ -15,14 +15,18 @@ module Python.Internal.Eval
1515 -- * PyObject wrapper
1616 , newPyObject
1717 , decref
18+ , incref
1819 , takeOwnership
1920 , ensureGIL
2021 , dropGIL
2122 -- * Exceptions
2223 , convertHaskell2Py
2324 , convertPy2Haskell
2425 , throwPyError
26+ , mustThrowPyError
2527 , throwPyConvesionFailed
28+ -- * Debugging
29+ , debugPrintPy
2630 ) where
2731
2832import Control.Concurrent
@@ -91,6 +95,9 @@ C.include "<inline-python.h>"
9195-- 2. Overhead of `runInBoundThread` is significant for GC (~1μs)
9296-- will this cause problem or if there're only few object on
9397-- haskell heap it would be fine?
98+ --
99+ -- In addition we must not do anything after interpreter shutdown.
100+ -- It already released memory. Most of it at least.
94101
95102
96103
@@ -241,6 +248,9 @@ doFinalizePython = [C.block| void {
241248decref :: Ptr PyObject -> Py ()
242249decref p = Py [CU. exp | void { Py_DECREF($(PyObject* p)) } |]
243250
251+ incref :: Ptr PyObject -> Py ()
252+ incref p = Py [CU. exp | void { Py_INCREF($(PyObject* p)) } |]
253+
244254-- | Ensure that we hold GIL for duration of action
245255ensureGIL :: Py a -> Py a
246256ensureGIL action = do
@@ -266,19 +276,16 @@ takeOwnership p = ContT $ \c -> c p `finallyPy` decref p
266276
267277-- | Wrap raw python object into
268278newPyObject :: Ptr PyObject -> Py PyObject
269- -- We need to use different implementation for different RTS
270279-- See NOTE: [GC]
271- newPyObject p
272- | rtsSupportsBoundThreads = Py $ do
273- fptr <- newForeignPtr_ p
274- GHC. addForeignPtrFinalizer fptr $ runInBoundThread $ unPy $ decref p
275- pure $ PyObject fptr
276- | otherwise = Py $ do
277- fptr <- newForeignPtr_ p
278- PyObject fptr <$ addForeignPtrFinalizer py_XDECREF fptr
279-
280- py_XDECREF :: FunPtr (Ptr PyObject -> IO () )
281- py_XDECREF = [C. funPtr | void inline_py_XDECREF(PyObject* p) { Py_XDECREF(p); } |]
280+ newPyObject p = Py $ do
281+ fptr <- newForeignPtr_ p
282+ -- FIXME: We still have race between check and interpreter
283+ -- shutdown. At least it's narrow race
284+ GHC. addForeignPtrFinalizer fptr $ do
285+ [CU. exp | int { Py_IsInitialized() } |] >>= \ case
286+ 0 -> pure ()
287+ _ -> runPy $ decref p
288+ pure $ PyObject fptr
282289
283290
284291
@@ -348,6 +355,14 @@ throwPyError =
348355 NULL -> pure ()
349356 _ -> throwPy =<< convertPy2Haskell
350357
358+ -- | Throw python error as haskell exception if it's raised. If it's
359+ -- not that internal error. Another exception will be raised
360+ mustThrowPyError :: String -> Py a
361+ mustThrowPyError msg =
362+ Py [CU. exp | PyObject* { PyErr_Occurred() } |] >>= \ case
363+ NULL -> error $ " mustThrowPyError: no python exception raised. " ++ msg
364+ _ -> throwPy =<< convertPy2Haskell
365+
351366throwPyConvesionFailed :: Py ()
352367throwPyConvesionFailed = do
353368 r <- Py [CU. block | int {
@@ -360,3 +375,14 @@ throwPyConvesionFailed = do
360375 case r of
361376 0 -> pure ()
362377 _ -> throwPy FromPyFailed
378+
379+
380+ ----------------------------------------------------------------
381+ -- Debugging
382+ ----------------------------------------------------------------
383+
384+ debugPrintPy :: Ptr PyObject -> Py ()
385+ debugPrintPy p = Py [CU. block | void {
386+ PyObject_Print($(PyObject *p), stdout, 0);
387+ printf(" [REF=%li]\n", Py_REFCNT($(PyObject *p)) );
388+ } |]
0 commit comments