diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,14 @@
+## 1.4.0
+
+* Providing dequeueSTM, isEmpty and isEmptySTM. Users can compose
+  their own control queue with dequeueSTM and isEmptySTM.
+
+* Removing enqueueControl: it appeared that PriorityTree is not
+  suitable for control frames. 　For example, the dependency of all
+  control frames is stream 0.  So, PSQ does not contain multiple
+  control frames at the same time.  We removed enqueueControl. Users
+  should prepare a queue for control frames by themselves.
+
 ## 1.3.1
 
 * Defining IllegalTableSizeUpdate.
diff --git a/Network/HPACK/HeaderBlock/HeaderField.hs b/Network/HPACK/HeaderBlock/HeaderField.hs
--- a/Network/HPACK/HeaderBlock/HeaderField.hs
+++ b/Network/HPACK/HeaderBlock/HeaderField.hs
@@ -22,13 +22,13 @@
 emptyHeaderBlock = []
 
 -- | Type for representation.
-data HeaderField = ChangeTableSize Int
-                 | Indexed Index
-                 | Literal Indexing Naming HeaderValue
+data HeaderField = ChangeTableSize !Int
+                 | Indexed !Index
+                 | Literal !Indexing !Naming !HeaderValue
                  deriving (Eq,Show)
 
 -- | Whether or not adding to a table.
 data Indexing = Add | NotAdd | Never deriving (Eq,Show)
 
 -- | Index or literal.
-data Naming = Idx Index | Lit HeaderName deriving (Eq,Show)
+data Naming = Idx !Index | Lit !HeaderName deriving (Eq,Show)
diff --git a/Network/HPACK/Huffman/Decode.hs b/Network/HPACK/Huffman/Decode.hs
--- a/Network/HPACK/Huffman/Decode.hs
+++ b/Network/HPACK/Huffman/Decode.hs
@@ -28,7 +28,7 @@
                    {-# UNPACK #-} !Word8 -- a decoded value
          deriving Show
 
-data Way16 = Way16 (Maybe Int) (Array Word8 Pin)
+data Way16 = Way16 !(Maybe Int) !(Array Word8 Pin)
 type Way256 = Array Word8 Way16
 
 next :: Way16 -> Word8 -> Pin
diff --git a/Network/HPACK/Huffman/Encode.hs b/Network/HPACK/Huffman/Encode.hs
--- a/Network/HPACK/Huffman/Encode.hs
+++ b/Network/HPACK/Huffman/Encode.hs
@@ -32,7 +32,7 @@
 
 data Shifted = Shifted !Int  -- Total bytes
                        !Int  -- How many bits in the last byte
-                       ByteString -- Up to 5 bytes
+                       !ByteString -- Up to 5 bytes
                        deriving Show
 
 ----------------------------------------------------------------
diff --git a/Network/HPACK/Huffman/Tree.hs b/Network/HPACK/Huffman/Tree.hs
--- a/Network/HPACK/Huffman/Tree.hs
+++ b/Network/HPACK/Huffman/Tree.hs
@@ -21,13 +21,13 @@
 
 -- | Type for Huffman decoding.
 data HTree = Tip
-             EOSInfo             -- EOS info from 1
+             !EOSInfo            -- EOS info from 1
              {-# UNPACK #-} !Int -- Decoded value. Essentially Word8
            | Bin
-             EOSInfo             -- EOS info from 1
+             !EOSInfo            -- EOS info from 1
              {-# UNPACK #-} !Int -- Sequence no from 0
-             HTree               -- Left
-             HTree               -- Right
+             !HTree              -- Left
+             !HTree              -- Right
            deriving Show
 
 eosInfo :: HTree -> EOSInfo
diff --git a/Network/HPACK/Table.hs b/Network/HPACK/Table.hs
--- a/Network/HPACK/Table.hs
+++ b/Network/HPACK/Table.hs
@@ -42,8 +42,9 @@
 
 -- | Is header key-value stored in the tables?
 data HeaderCache = None
-                 | KeyOnly WhichTable Index
-                 | KeyValue WhichTable Index deriving Show
+                 | KeyOnly  !WhichTable !Index
+                 | KeyValue !WhichTable !Index
+                 deriving Show
 
 ----------------------------------------------------------------
 
diff --git a/Network/HPACK/Table/DoubleHashMap.hs b/Network/HPACK/Table/DoubleHashMap.hs
--- a/Network/HPACK/Table/DoubleHashMap.hs
+++ b/Network/HPACK/Table/DoubleHashMap.hs
@@ -53,7 +53,7 @@
 deleteList :: Ord a => [Header] -> DoubleHashMap a -> DoubleHashMap a
 deleteList hs hp = foldl' (flip delete) hp hs
 
-data Res a = N | K a | KV a
+data Res a = N | K !a | KV !a
 
 search :: Ord a => Header -> DoubleHashMap a -> Res a
 search (k,v) (DoubleHashMap outer) = case H.lookup k outer of
diff --git a/Network/HPACK/Table/Dynamic.hs b/Network/HPACK/Table/Dynamic.hs
--- a/Network/HPACK/Table/Dynamic.hs
+++ b/Network/HPACK/Table/Dynamic.hs
@@ -68,13 +68,13 @@
   --   If 'Nothing', dynamic table size update is not necessary.
   --   Otherwise, dynamic table size update is sent
   --   and this value should be set to 'Nothing'.
-  , limitForEncoding :: IORef (Maybe Size)
+  , limitForEncoding :: !(IORef (Maybe Size))
   -- | The limit size of a dynamic table for decoding
   , limitForDecoding :: !Size
   -- | Header to the index in Dynamic Table for encoder.
   --   Static Table is not included.
   --   Nothing for decoder.
-  , reverseIndex :: Maybe (DHM.DoubleHashMap HIndex)
+  , reverseIndex :: !(Maybe (DHM.DoubleHashMap HIndex))
   }
 
 adj :: Int -> Int -> Int
@@ -113,7 +113,7 @@
 isSuitableSize :: Size -> DynamicTable -> Bool
 isSuitableSize siz tbl = siz <= limitForDecoding tbl
 
-data TableSizeAction = Keep | Change Size | Ignore Size
+data TableSizeAction = Keep | Change !Size | Ignore !Size
 
 needChangeTableSize :: DynamicTable -> IO TableSizeAction
 needChangeTableSize tbl = do
diff --git a/Network/HPACK/Types.hs b/Network/HPACK/Types.hs
--- a/Network/HPACK/Types.hs
+++ b/Network/HPACK/Types.hs
@@ -47,9 +47,9 @@
 -- | Strategy for HPACK encoding.
 data EncodeStrategy = EncodeStrategy {
   -- | Which compression algorithm is used.
-    compressionAlgo :: CompressionAlgo
+    compressionAlgo :: !CompressionAlgo
   -- | Whether or not to use Huffman encoding for strings.
-  , useHuffman :: Bool
+  , useHuffman :: !Bool
   } deriving (Eq, Show)
 
 -- | Default 'EncodeStrategy'.
diff --git a/Network/HTTP2/Encode.hs b/Network/HTTP2/Encode.hs
--- a/Network/HTTP2/Encode.hs
+++ b/Network/HTTP2/Encode.hs
@@ -26,11 +26,11 @@
 -- | Auxiliary information for frame encoding.
 data EncodeInfo = EncodeInfo {
     -- | Flags to be set in a frame header
-      encodeFlags    :: FrameFlags
+      encodeFlags    :: !FrameFlags
     -- | Stream id to be set in a frame header
-    , encodeStreamId :: StreamId
+    , encodeStreamId :: !StreamId
     -- | Padding if any. In the case where this value is set but the priority flag is not set, this value gets preference over the priority flag. So, if this value is set, the priority flag is also set.
-    , encodePadding  :: Maybe Padding
+    , encodePadding  :: !(Maybe Padding)
     } deriving (Show,Read)
 
 ----------------------------------------------------------------
diff --git a/Network/HTTP2/Priority.hs b/Network/HTTP2/Priority.hs
--- a/Network/HTTP2/Priority.hs
+++ b/Network/HTTP2/Priority.hs
@@ -25,8 +25,10 @@
   -- * PriorityTree functions
   , prepare
   , enqueue
-  , enqueueControl
   , dequeue
+  , dequeueSTM
+  , isEmpty
+  , isEmptySTM
   , delete
   ) where
 
@@ -44,9 +46,8 @@
 ----------------------------------------------------------------
 
 -- | Abstract data type for priority trees.
-data PriorityTree a = PriorityTree (TVar (Glue a))
-                                   (TNestedPriorityQueue a)
-                                   (TQueue (StreamId, Precedence, a))
+data PriorityTree a = PriorityTree !(TVar (Glue a))
+                                   !(TNestedPriorityQueue a)
 
 type Glue a = IntMap (TNestedPriorityQueue a, Precedence)
 
@@ -54,8 +55,8 @@
 -- another TNestedPriorityQueue.
 type TNestedPriorityQueue a = TPriorityQueue (Element a)
 
-data Element a = Child a
-               | Parent (TNestedPriorityQueue a)
+data Element a = Child !a
+               | Parent !(TNestedPriorityQueue a)
 
 
 ----------------------------------------------------------------
@@ -76,14 +77,13 @@
 newPriorityTree :: IO (PriorityTree a)
 newPriorityTree = PriorityTree <$> newTVarIO Map.empty
                                <*> atomically Q.new
-                               <*> newTQueueIO
 
 ----------------------------------------------------------------
 
 -- | Bringing up the structure of the priority tree.
 --   This must be used for Priority frame.
 prepare :: PriorityTree a -> StreamId -> Priority -> IO ()
-prepare (PriorityTree var _ _) sid p = atomically $ do
+prepare (PriorityTree var _) sid p = atomically $ do
     q <- Q.new
     let pre = toPrecedence p
     modifyTVar' var $ Map.insert sid (q, pre)
@@ -91,7 +91,7 @@
 -- | Enqueuing an entry to the priority tree.
 --   This must be used for Header frame.
 enqueue :: PriorityTree a -> StreamId -> Precedence -> a -> IO ()
-enqueue (PriorityTree var q0 _) sid p0 x = atomically $ do
+enqueue (PriorityTree var q0) sid p0 x = atomically $ do
     m <- readTVar var
     let !el = Child x
     loop m el p0
@@ -110,18 +110,22 @@
       where
         pid = Q.dependency p
 
--- | Putting an entry to the top of the priority tree.
-enqueueControl :: PriorityTree a -> StreamId -> a -> IO ()
-enqueueControl (PriorityTree _ _ cq) sid x =
-    atomically $ writeTQueue cq (sid,defaultPrecedence,x)
 
+-- | Checking if the priority tree is empty.
+isEmpty :: PriorityTree a -> IO Bool
+isEmpty = atomically . isEmptySTM
+
+-- | Checking if the priority tree is empty.
+isEmptySTM :: PriorityTree a -> STM Bool
+isEmptySTM (PriorityTree _ q0) = Q.isEmpty q0
+
 -- | Dequeuing an entry from the priority tree.
 dequeue :: PriorityTree a -> IO (StreamId, Precedence, a)
-dequeue (PriorityTree _ q0 cq) = atomically $ do
-    mx <- tryReadTQueue cq
-    case mx of
-        Just x  -> return x
-        Nothing -> loop q0
+dequeue = atomically . dequeueSTM
+
+-- | Dequeuing an entry from the priority tree.
+dequeueSTM :: PriorityTree a -> STM (StreamId, Precedence, a)
+dequeueSTM (PriorityTree _ q0) = loop q0
   where
     loop q = do
         (sid,p,el) <- Q.dequeue q
@@ -137,7 +141,7 @@
 --   'delete' and 'enqueue' are used to change the priority of
 --   a live stream.
 delete :: PriorityTree a -> StreamId -> Precedence -> IO (Maybe a)
-delete (PriorityTree var q0 _) sid p
+delete (PriorityTree var q0) sid p
   | pid == 0  = atomically $ del q0
   | otherwise = atomically $ do
         m <- readTVar var
diff --git a/Network/HTTP2/Priority/PSQ.hs b/Network/HTTP2/Priority/PSQ.hs
--- a/Network/HTTP2/Priority/PSQ.hs
+++ b/Network/HTTP2/Priority/PSQ.hs
@@ -55,7 +55,7 @@
 --        In that case, the heap must be re-constructed.
 data PriorityQueue a = PriorityQueue {
     baseDeficit :: {-# UNPACK #-} !Deficit
-  , queue :: Heap a
+  , queue :: !(Heap a)
   }
 
 ----------------------------------------------------------------
diff --git a/Network/HTTP2/Types.hs b/Network/HTTP2/Types.hs
--- a/Network/HTTP2/Types.hs
+++ b/Network/HTTP2/Types.hs
@@ -165,8 +165,8 @@
 ----------------------------------------------------------------
 
 -- | The connection error or the stream error.
-data HTTP2Error = ConnectionError ErrorCodeId ByteString
-                | StreamError ErrorCodeId StreamId
+data HTTP2Error = ConnectionError !ErrorCodeId !ByteString
+                | StreamError !ErrorCodeId !StreamId
                 deriving (Eq, Show, Typeable, Read)
 
 instance E.Exception HTTP2Error
@@ -249,12 +249,12 @@
 
 -- | Cooked version of settings. This is suitable to be stored in a HTTP/2 context.
 data Settings = Settings {
-    headerTableSize :: Int
-  , enablePush :: Bool
-  , maxConcurrentStreams :: Maybe Int
-  , initialWindowSize :: WindowSize
-  , maxFrameSize :: Int
-  , maxHeaderBlockSize :: Maybe Int
+    headerTableSize :: !Int
+  , enablePush :: !Bool
+  , maxConcurrentStreams :: !(Maybe Int)
+  , initialWindowSize :: !WindowSize
+  , maxFrameSize :: !Int
+  , maxHeaderBlockSize :: !(Maybe Int)
   } deriving (Show)
 
 -- | The default settings.
@@ -329,9 +329,9 @@
 
 -- | Type for stream priority
 data Priority = Priority {
-    exclusive :: Bool
-  , streamDependency :: StreamId
-  , weight :: Weight
+    exclusive :: !Bool
+  , streamDependency :: !StreamId
+  , weight :: !Weight
   } deriving (Show, Read, Eq)
 
 -- | Default priority which depends on stream 0.
@@ -563,30 +563,30 @@
 
 -- | The data type for HTTP/2 frames.
 data Frame = Frame
-    { frameHeader  :: FrameHeader
-    , framePayload :: FramePayload
+    { frameHeader  :: !FrameHeader
+    , framePayload :: !FramePayload
     } deriving (Show, Read, Eq)
 
 -- | The data type for HTTP/2 frame headers.
 data FrameHeader = FrameHeader
-    { payloadLength :: Int
-    , flags         :: FrameFlags
-    , streamId      :: StreamId
+    { payloadLength :: !Int
+    , flags         :: !FrameFlags
+    , streamId      :: !StreamId
     } deriving (Show, Read, Eq)
 
 -- | The data type for HTTP/2 frame payloads.
 data FramePayload =
-    DataFrame ByteString
-  | HeadersFrame (Maybe Priority) HeaderBlockFragment
-  | PriorityFrame Priority
-  | RSTStreamFrame ErrorCodeId
-  | SettingsFrame SettingsList
-  | PushPromiseFrame StreamId HeaderBlockFragment
-  | PingFrame ByteString
-  | GoAwayFrame StreamId ErrorCodeId ByteString
-  | WindowUpdateFrame WindowSize
-  | ContinuationFrame HeaderBlockFragment
-  | UnknownFrame FrameType ByteString
+    DataFrame !ByteString
+  | HeadersFrame !(Maybe Priority) !HeaderBlockFragment
+  | PriorityFrame !Priority
+  | RSTStreamFrame !ErrorCodeId
+  | SettingsFrame !SettingsList
+  | PushPromiseFrame !StreamId !HeaderBlockFragment
+  | PingFrame !ByteString
+  | GoAwayFrame !StreamId !ErrorCodeId !ByteString
+  | WindowUpdateFrame !WindowSize
+  | ContinuationFrame !HeaderBlockFragment
+  | UnknownFrame !FrameType !ByteString
   deriving (Show, Read, Eq)
 
 ----------------------------------------------------------------
diff --git a/http2.cabal b/http2.cabal
--- a/http2.cabal
+++ b/http2.cabal
@@ -1,5 +1,5 @@
 Name:                   http2
-Version:                1.3.1
+Version:                1.4.0
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
 License:                BSD3
