Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit e3f3428

Browse files
authored
Merge pull request #864 from haskell/refactor-dispatcher
Refactor DispatcherEnv our of the Reactor
2 parents fcbf945 + 9e22aa6 commit e3f3428

File tree

12 files changed

+643
-356
lines changed

12 files changed

+643
-356
lines changed

.circleci/config.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ defaults: &defaults
6969

7070
- run:
7171
name: Test
72-
command: stack -j 2 --stack-yaml=${STACK_FILE} test --dump-logs
72+
# Tests MUST run with -j1, since multiple ghc-mod sessions are not allowed
73+
command: stack -j 1 --stack-yaml=${STACK_FILE} test --dump-logs
7374
no_output_timeout: 120m
7475

7576
- store_artifacts:

app/MainHie.hs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@
22
{-# LANGUAGE RankNTypes #-}
33
module Main where
44

5-
import Control.Concurrent.STM.TChan
65
import Control.Monad
7-
import Control.Monad.STM
86
import Data.Monoid ((<>))
97
import Data.Version (showVersion)
108
import qualified GhcMod.Types as GM
11-
import Haskell.Ide.Engine.Dispatcher
129
import Haskell.Ide.Engine.MonadFunctions
1310
import Haskell.Ide.Engine.MonadTypes
1411
import Haskell.Ide.Engine.Options
1512
import Haskell.Ide.Engine.PluginDescriptor
13+
import Haskell.Ide.Engine.Scheduler
1614
import Haskell.Ide.Engine.Transport.LspStdio
1715
import Haskell.Ide.Engine.Transport.JsonStdio
1816
import qualified Language.Haskell.LSP.Core as Core
@@ -145,8 +143,8 @@ run opts = do
145143

146144
-- launch the dispatcher.
147145
if optJson opts then do
148-
pin <- atomically newTChan
149-
jsonStdioTransport (dispatcherP pin plugins' ghcModOptions) pin
146+
scheduler <- newScheduler plugins' ghcModOptions
147+
jsonStdioTransport scheduler
150148
else do
151-
pin <- atomically newTChan
152-
lspStdioTransport (dispatcherP pin plugins' ghcModOptions) pin origDir plugins' (optCaptureFile opts)
149+
scheduler <- newScheduler plugins' ghcModOptions
150+
lspStdioTransport scheduler origDir plugins' (optCaptureFile opts)

docs/Architecture.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,20 @@ fresh data is generated when first requested.
113113
## Dispatcher and messaging
114114

115115
```haskell
116-
dispatcherP :: forall m. TChan (PluginRequest m)
117-
-> IdePlugins
118-
-> GM.Options
119-
-> DispatcherEnv
120-
-> ErrorHandler
121-
-> CallbackHandler m
122-
-> IO ()
116+
runScheduler
117+
:: forall m
118+
. Scheduler m
119+
-> ErrorHandler
120+
-> CallbackHandler m
121+
-> C.ClientCapabilities
122+
-> IO ()
123+
124+
sendRequest
125+
:: forall m
126+
. Scheduler m
127+
-> Maybe DocUpdate
128+
-> PluginRequest m
129+
-> IO ()
123130

124131
type PluginRequest m = Either (IdeRequest m) (GhcRequest m)
125132

@@ -139,8 +146,8 @@ data IdeRequest m = forall a. IdeRequest
139146

140147
```
141148

142-
`dispatcherP`(thread #3) listens for `PluginRequest`s on the `TChan` and executes the
143-
`pinReq`, sending the result to the `pinCallback`. `pinDocVer` and `pinLspReqId` help us
149+
`runScheduler`(thread #3) waits for requests sent through `sendRequest` and executes the
150+
`pinReq`. Sending the result to the `pinCallback`. `pinDocVer` and `pinLspReqId` help us
144151
make sure we don't execute a stale request or a request that has been cancelled by the IDE.
145152
Note that because of the single threaded architecture, we can't cancel a request that
146153
has already started execution.

haskell-ide-engine.cabal

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ flag pedantic
2020
library
2121
hs-source-dirs: src
2222
exposed-modules: Haskell.Ide.Engine.Plugin.Base
23-
Haskell.Ide.Engine.Dispatcher
23+
Haskell.Ide.Engine.Channel
24+
Haskell.Ide.Engine.Scheduler
2425
Haskell.Ide.Engine.LSP.CodeActions
2526
Haskell.Ide.Engine.LSP.Config
2627
Haskell.Ide.Engine.LSP.Reactor
@@ -221,6 +222,39 @@ test-suite dispatcher-test
221222
default-language: Haskell2010
222223
build-tool-depends: hspec-discover:hspec-discover
223224

225+
test-suite plugin-dispatcher-test
226+
type: exitcode-stdio-1.0
227+
hs-source-dirs: test/plugin-dispatcher
228+
test/utils
229+
main-is: Main.hs
230+
other-modules: TestUtils
231+
build-depends: base
232+
, aeson
233+
, containers
234+
, data-default
235+
, directory
236+
, filepath
237+
, ghc
238+
, haskell-lsp
239+
, haskell-ide-engine
240+
-- , hie-test-utils
241+
, hie-plugin-api
242+
, hspec
243+
, stm
244+
, text
245+
, unordered-containers
246+
247+
-- remove these once hie-test-utils is reinstated
248+
, hie-plugin-api
249+
, ghc-mod-core
250+
, hslogger
251+
, unordered-containers
252+
, yaml
253+
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Wredundant-constraints
254+
if flag(pedantic)
255+
ghc-options: -Werror
256+
default-language: Haskell2010
257+
224258
-- library hie-test-utils
225259
-- hs-source-dirs: test/utils
226260
-- exposed-modules: TestUtils

src/Haskell/Ide/Engine/Channel.hs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module Haskell.Ide.Engine.Channel
2+
( InChan
3+
, OutChan
4+
, newChan
5+
, newChanSTM
6+
, readChan
7+
, readChanSTM
8+
, writeChan
9+
, writeChanSTM
10+
)
11+
where
12+
13+
import qualified Control.Concurrent.STM.TChan as TChan
14+
import qualified Control.Concurrent.STM as STM
15+
16+
-- | The writing end of a STM channel, only values of type 'a' cam be written
17+
-- to the channel
18+
newtype InChan a = InChan (TChan.TChan a)
19+
20+
-- | The reading end of a STM channel, values of type 'a' can be expected to
21+
-- be read.
22+
newtype OutChan a = OutChan (TChan.TChan a)
23+
24+
-- | Returns the reading and writing ends of a channel able to trasmit values of
25+
-- a single given type
26+
newChan :: IO (InChan a, OutChan a)
27+
newChan = STM.atomically newChanSTM
28+
29+
-- | STM version of 'newChan', useful for chaining many STM calls inside a single
30+
-- 'atomically' block.
31+
newChanSTM :: STM.STM (InChan a, OutChan a)
32+
newChanSTM = do
33+
chan <- TChan.newTChan
34+
return (InChan chan, OutChan chan)
35+
36+
-- | Consumes and returns the next value of the given channel
37+
readChan :: OutChan a -> IO a
38+
readChan = STM.atomically . readChanSTM
39+
40+
-- | STM version of 'readChan', useful for chaining many STM calls inside a single
41+
-- 'atomically' block.
42+
readChanSTM :: OutChan a -> STM.STM a
43+
readChanSTM (OutChan chan) = STM.readTChan chan
44+
45+
-- | Writes a value to a channel.
46+
writeChan :: InChan a -> a -> IO ()
47+
writeChan chan val = STM.atomically (writeChanSTM chan val)
48+
49+
-- | STM version of 'writeChan', useful for chaining many STM calls inside a single
50+
-- 'atomically' block.
51+
writeChanSTM :: InChan a -> a -> STM.STM ()
52+
writeChanSTM (InChan chan) = STM.writeTChan chan

src/Haskell/Ide/Engine/Dispatcher.hs

Lines changed: 0 additions & 162 deletions
This file was deleted.

0 commit comments

Comments
 (0)