Skip to content

Commit cff34ac

Browse files
committed
Code cleanup
1 parent f204902 commit cff34ac

File tree

2 files changed

+58
-56
lines changed

2 files changed

+58
-56
lines changed

inline-python.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ common language
3333
Default-Extensions:
3434
NoPolyKinds
3535
--
36+
DeriveAnyClass
3637
DerivingVia
3738
PatternSynonyms
3839
ViewPatterns

src/Python/Internal/Eval.hs

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ module Python.Internal.Eval
3636

3737
import Control.Concurrent
3838
import Control.Concurrent.STM
39-
import Control.Exception (AsyncException(..),SomeAsyncException)
4039
import Control.Monad
4140
import Control.Monad.Catch
4241
import Control.Monad.IO.Class
@@ -277,10 +276,7 @@ initializePython = [CU.exp| int { Py_IsInitialized() } |] >>= \case
277276

278277
-- | Destroy python interpreter.
279278
finalizePython :: IO ()
280-
-- See NOTE: [Python and threading]
281-
finalizePython
282-
| rtsSupportsBoundThreads = runInBoundThread $ mask_ doFinalizePython
283-
| otherwise = mask_ $ doFinalizePython
279+
finalizePython = mask_ doFinalizePython
284280

285281
-- | Bracket which ensures that action is executed with properly
286282
-- initialized interpreter
@@ -313,24 +309,7 @@ doInializePython = do
313309
lock_init <- newEmptyMVar
314310
lock_eval <- newEmptyMVar
315311
-- Main thread
316-
tid_main <- forkOS $ do
317-
r <- doInializePythonIO
318-
putMVar lock_init r
319-
case r of
320-
False -> pure ()
321-
True -> mask_ $ do
322-
let loop = takeMVar lock_eval >>= \case
323-
EvalReq py resp -> do
324-
res <- (Right <$> runPy py) `catch` (pure . Left)
325-
putMVar resp res
326-
loop
327-
StopReq resp -> do
328-
[C.block| void {
329-
PyGILState_Ensure();
330-
Py_Finalize();
331-
} |]
332-
putMVar resp ()
333-
loop
312+
tid_main <- forkOS $ mainThread lock_init lock_eval
334313
takeMVar lock_init >>= \case
335314
True -> pure ()
336315
False -> throwM PyInitializationFailed
@@ -346,6 +325,31 @@ doInializePython = do
346325
fini Running1
347326
) `onException` atomically (writeTVar globalPyState InitFailed)
348327

328+
-- This action is executed on python's main thread
329+
mainThread :: MVar Bool -> MVar EvalReq -> IO ()
330+
mainThread lock_init lock_eval = do
331+
r_init <- doInializePythonIO
332+
putMVar lock_init r_init
333+
case r_init of
334+
False -> pure ()
335+
True -> mask_ $ do
336+
let loop
337+
= handle (\InterruptMain -> pure ())
338+
$ takeMVar lock_eval >>= \case
339+
EvalReq py resp -> do
340+
res <- (Right <$> runPy py) `catch` (pure . Left)
341+
putMVar resp res
342+
loop
343+
StopReq resp -> do
344+
[C.block| void {
345+
PyGILState_Ensure();
346+
Py_Finalize();
347+
} |]
348+
putMVar resp ()
349+
loop
350+
351+
352+
349353
doInializePythonIO :: IO Bool
350354
doInializePythonIO = do
351355
-- FIXME: I'd like more direct access to argv
@@ -402,32 +406,26 @@ doFinalizePython = join $ atomically $ readTVar globalPyState >>= \case
402406
InInitialization -> retry
403407
InFinalization -> retry
404408
-- We can simply call Py_Finalize
405-
Running1 -> readTVar globalPyLock >>= \case
406-
LockUninialized -> error "Internal error: Lock not initialized"
407-
LockFinalized -> error "Internal error: Lock is already finalized"
408-
Locked{} -> retry
409-
LockedByGC -> retry
410-
LockUnlocked -> do
411-
writeTVar globalPyLock LockFinalized
412-
writeTVar globalPyState Finalized
413-
pure $ [C.block| void {
414-
PyGILState_Ensure();
415-
Py_Finalize();
416-
} |]
417-
-- We need to call Py_Finalize on main thread specifically
418-
RunningN _ eval tid_main tid_gc -> readTVar globalPyLock >>= \case
419-
LockUninialized -> error "Internal error: Lock not initialized"
420-
LockFinalized -> error "Internal error: Lock is already finalized"
421-
Locked{} -> retry
422-
LockedByGC -> retry
423-
LockUnlocked -> do
424-
writeTVar globalPyLock LockFinalized
425-
writeTVar globalPyState Finalized
426-
pure $ do
427-
resp <- newEmptyMVar
428-
putMVar eval $ StopReq resp
429-
takeMVar resp
430-
killThread tid_gc
409+
Running1 -> checkLock $ [C.block| void {
410+
PyGILState_Ensure();
411+
Py_Finalize();
412+
} |]
413+
-- We need to call Py_Finalize on main thread
414+
RunningN _ eval _ tid_gc -> checkLock $ do
415+
killThread tid_gc
416+
resp <- newEmptyMVar
417+
putMVar eval $ StopReq resp
418+
takeMVar resp
419+
where
420+
checkLock action = readTVar globalPyLock >>= \case
421+
LockUninialized -> error "Internal error: Lock not initialized"
422+
LockFinalized -> error "Internal error: Lock is already finalized"
423+
Locked{} -> retry
424+
LockedByGC -> retry
425+
LockUnlocked -> do
426+
writeTVar globalPyLock LockFinalized
427+
writeTVar globalPyState Finalized
428+
pure action
431429

432430

433431
----------------------------------------------------------------
@@ -438,6 +436,10 @@ data EvalReq
438436
= forall a. EvalReq (Py a) (MVar (Either SomeException a))
439437
| StopReq (MVar ())
440438

439+
data InterruptMain = InterruptMain
440+
deriving stock Show
441+
deriving anyclass Exception
442+
441443
-- | Execute python action. It will take global lock and no other
442444
-- python action could start execution until one currently running
443445
-- finished execution normally or with exception.
@@ -464,13 +466,12 @@ runPyInMain py
464466
Running1 -> error "INTERNAL ERROR"
465467
RunningN _ eval tid_main _ -> do
466468
acquireLock tid_main
467-
pure $
468-
(( do resp <- newEmptyMVar
469-
putMVar eval $ EvalReq py resp
470-
either throwM pure =<< takeMVar resp
471-
) `onException` throwTo tid_main UserInterrupt
472-
) `finally` atomically (releaseLock tid_main)
473-
-- resp <- newEmptyMVar
469+
pure
470+
$ flip finally (atomically (releaseLock tid_main))
471+
$ flip onException (throwTo tid_main InterruptMain)
472+
$ do resp <- newEmptyMVar
473+
putMVar eval $ EvalReq py resp
474+
either throwM pure =<< takeMVar resp
474475
-- Single-threaded RTS
475476
| otherwise = runPy py
476477

0 commit comments

Comments
 (0)