packages feed

hpc-tracer-0.3.0: src/TracerActor.hs

module TracerActor where

import Trace.Hpc.Mix
import Trace.Hpc.Util

import System.IO
import qualified Data.Set as Set

import TixActor
import TixStreamActor

import Reactive
import Common
import BreakPoint

import Control.Concurrent

-- The main actor

data State = State
  { count :: Integer
  }

type TracerActorState = (Maybe TracerState,TracerState)


tracerActor :: String 
	    -> String 
	    -> Handle -> Handle -> IO (TracerRequest -> IO TracerResponse)
tracerActor hpcDir srcDir d_handle cmd_handle = do 
  starts <- hGetLine d_handle
  mods <- hGetLine d_handle

  getTix <- readTickActor d_handle cmd_handle

  StreamActorResult { counter = count
	   	    , event = tixInfo
		    , threadId = tid
		    , live = isLive
		    } <- getTix 0 (Set.empty)

   -- We actually store a pair of states, 
   --   - the current state according to the GUI,
   --   - and the current state.

  let initState = TracerState 
        { tracerCounter = count
	, tracerThreadID = tid
	, tracerEvent = tixInfo
	, tracerBreakPoints = []
	, tracerRunning = Nothing
	}

--  print mods
  
  let send v = return (v,0)

  let modSizes :: [(String,Int)]
      modSizes = read mods
 
     -- we will need to improve this in the future
  tixActor <- globalTixActor hpcDir srcDir modSizes


  let record Nothing newState = do
      	   	   return ( MultiResponse
			     [ ModuleListResponse (map fst modSizes)
			     , TracerStateResponse (GUIState newState Nothing [])
			     ]
			   , (Just newState,newState)
			   )

      record (Just oldState) newState = do
	   opt_ticked <- 
	       case tracerRunning newState of
	          Nothing -> 
		     case tracerEvent newState of
	               Tick tixNo -> do
		      	  tixInfo <- lookupGlobalTickInfo tixActor tixNo
			  return $ Just tixInfo
                       _ -> return $ Nothing
                  _ -> return $ Nothing
--           print (oldState,newState)
           return ( TracerStateResponse $
	   	       GUIState 
		         { guiTracerState    = newState
			 , guiTracerTicked   = opt_ticked
			 , guiTracerBreakers = checkBreakPoints newState
			 }
	   	  , (Just newState,newState)
		  )


  let setBP bp state0 = do
	   bp' <- normalizeBreakPoint tixActor bp
           let state1 = state0 { tracerBreakPoints = setBreakPoint bp' $ tracerBreakPoints state0 }
--	   print $ tracerBreakPoints state1
	   return state1

  let clearBP bp state0 = do
	   bp' <- normalizeBreakPoint tixActor bp
           let state1 = state0 { tracerBreakPoints = clearBreakPoint bp' $ tracerBreakPoints state0 }
--	   print $ tracerBreakPoints state1
	   return state1

  let dir Forward = 1
      dir Backward = -1

  let step d state0 = do
--      	   print "step(1)"
	   StreamActorResult { counter = count
	   		     , event = tixInfo
			     , threadId = tid
			     } <- getTix (fromIntegral d + tracerCounter state0) 
			       	  	 (tickIdBreakPointSet state0)

--      	   print "step(2)"
--	   print ("284",count,tixInfo)

	   let state1 = state0 { tracerCounter = count
	       	      	       , tracerThreadID = tid
			       , tracerEvent = tixInfo
			       }
           return state1

      searchForBP :: Direction
      		  -> ((TracerActorState -> IO TracerActorState) -> IO ()) 
		  -> TracerActorState
		  -> IO TracerActorState
      searchForBP d action (oldState,state0 @ TracerState { tracerRunning = Nothing }) 
      		= return $ (oldState,state0)

      searchForBP d action (oldState,state0) = do
      		  let steps = 314159 -- large(ish) prime, also pi * 100,000
      		  let target = ((dir d * steps + tracerCounter state0) `div` steps) * steps
		  let next_bp = case nextCounterBreakPoint state0 of
		      	          Nothing -> target
				  Just target' -> min target' target
                  res <- getTix next_bp (tickIdBreakPointSet state0)
      		  case res of
		    StreamActorResult 
		             { counter = count
	   		     , event = tixInfo
			     , threadId = tid
			     } -> do
			 let state1 = state0 { tracerCounter = count
	       	      	     	             , tracerThreadID = tid
					     , tracerEvent = tixInfo
			                     }

                         case tixInfo of
			    _ | isBreakPoint state1   -> return $ (oldState, state1 { tracerRunning = Nothing })
			    Finished                  -> return $ (oldState, state1 { tracerRunning = Nothing })
			    _ | otherwise -> do
		     	           action (searchForBP d action)
		                   return $ (oldState,state1)
	            _ -> error "bad actor"

      initRunToBP d action state0 = do
      		   action (searchForBP d action)
		   let state1 = state0 { tracerRunning = Just $ d }
		   return state1

  mkActor2 (Nothing,initState) $ \ request action req ->  
  	   request $ \ (state0,state1) -> do
	   state2 <- case req of
	               InitRequest          -> return $ state1
	               StepRequest Forward  -> step 1      state1
	               StepRequest Backward -> step (-1)   state1
	               RunRequest Forward   -> initRunToBP Forward action state1
	               RunRequest Backward  -> initRunToBP Backward action state1
	               (SetBreakPoint bp)   -> setBP   bp  state1
	               (ClearBreakPoint bp) -> clearBP bp  state1
	               ContinueRequest      -> return $ state1
	               StopRequest          -> return $ state1 { tracerRunning = Nothing }

           record state0 state2

------------------------------------------------------------------------------

showUsingXml :: [(String,[(String,String)])] -> String
showUsingXml cmds = 
 "<?xml version=\"1.0\"?>" ++
    "<cmds>" ++ 
    unlines [ "<" ++ cmd ++ concatMap showArgs args ++ "/>" | (cmd,args) <- cmds ] ++
    "</cmds>\n"
  where showArgs (nm,val) = " " ++ nm ++ "=\"" ++ val ++ "\""