crashanalysercmd/Libraries/Engine/CrashDebuggerLib/Structures/Thread/DThread.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

using System;
using System.Collections.Generic;
using System.Text;
using CrashDebuggerLib.Structures.Common;
using CrashDebuggerLib.Structures.KernelObjects;
using CrashDebuggerLib.Structures.Process;
using CrashDebuggerLib.Structures.NThread;
using SymbianStructuresLib.Debug.Symbols;

namespace CrashDebuggerLib.Structures.Thread
{
    public class DThread : DObject
    {
        #region Enumerations
        [System.ComponentModel.TypeConverter( typeof( SymbianParserLib.TypeConverters.SymbianEnumConverter ) )]
        public enum TThreadState
        {
            EUnknown = -1,
            ECreated = 0,
            EDead,
            EReady,
            EWaitSemaphore,
            EWaitSemaphoreSuspended,
            EWaitMutex,
            EWaitMutexSuspended,
            EHoldMutexPending,
            EWaitCondVar,
            EWaitCondVarSuspended,
        }

        [Flags, System.ComponentModel.TypeConverter( typeof( SymbianParserLib.TypeConverters.SymbianEnumConverter ) )]
        public enum TThreadFlags
        {
            EThreadFlagNone                 = 0x00000000,
            EThreadFlagProcessCritical		= 0x00000001,	// thread panic panics process
            EThreadFlagProcessPermanent		= 0x00000002,	// thread exit of any kind causes process to exit (=main)
            EThreadFlagSystemCritical		= 0x00000004,	// thread panic reboots entire system
            EThreadFlagSystemPermanent		= 0x00000008,	// thread exit of any kind reboots entire system
            EThreadFlagOriginal				= 0x00000010,
            EThreadFlagLastChance			= 0x00000020,
            EThreadFlagRealtime				= 0x00000040,	// thread will be panicked when using some non-realtime functions
            EThreadFlagRealtimeTest			= 0x00000080	// non-realtime functions only warn rather than panic
        }

        public enum TThreadWaitType
        {
            EThreadWaitingUnknown = 0,
            EThreadWaitingReady,
            EThreadWaitingOnSemaphore,
            EThreadWaitingOnMutex,
            EThreadWaitingOnDfc,
            EThreadWaitingOnResumption,
            EThreadWaitingOnRequestSemaphore,
            EThreadWaitingOnRequestSemaphoreInsideSchedulerWaitLoop
        }
        #endregion

        #region Constructors
        public DThread( CrashDebuggerInfo aCrashDebugger )
            : base( aCrashDebugger, TObjectType.EThread )
        {
            iNThread = new CrashDebuggerLib.Structures.NThread.NThread( aCrashDebugger, this );
            iStackInfoSupervisor = new ThreadStackInfo( aCrashDebugger, this, ThreadStackInfo.TType.ETypeSupervisor );
            iStackInfoUser = new ThreadStackInfo( aCrashDebugger, this, ThreadStackInfo.TType.ETypeUser );
        }
        #endregion

        #region API
        #endregion

        #region Properties
        public TThreadState MState
        {
            get { return iState; }
            set { iState = value; }
        }

        public uint WaitObj
        {
            get { return iStateWaitObjectAddress; }
            set { iStateWaitObjectAddress = value; }
        }

        public TThreadFlags Flags
        {
            get { return iFlags; }
            set { iFlags = value; }
        }

        public uint Handles
        {
            get { return iHandles; }
            set { iHandles = value; }
        }

        public long Id
        {
            get { return iId; }
            set { iId = value; }
        }

        public ThreadAllocatorInfo AllocatorInfo
        {
            get { return iAllocatorInfo; }
        }

        public uint Frame
        {
            get { return iFrame; }
            set { iFrame = value; }
        }

        public ThreadPriorities Priorities
        {
            get { return iPriorities; }
        }

        public ExitInfo ExitInfo
        {
            get { return iExitInfo; }
        }

        public ThreadStackInfo StackInfoUser
        {
            get { return iStackInfoUser; }
        }

        public ThreadStackInfo StackInfoSupervisor
        {
            get { return iStackInfoSupervisor; }
        }

        public ThreadHandlers Handlers
        {
            get { return iHandlers; }
        }

        public ThreadTemporaries Temporaries
        {
            get { return iTemporaries; }
        }

        public uint IpcCount
        {
            get { return iIpcCount; }
            set { iIpcCount = value; }
        }

        public DProcess OwningProcess
        {
            get
            {
                DProcess ret = null;
                //
                DObject owner = Owner;
                if ( owner != null && owner is DProcess )
                {
                    ret = (DProcess) owner;
                }
                //
                return ret;
            }
        }

        public NThread.NThread NThread
        {
            get { return iNThread; }
        }

        public bool HasActiveScheduler
        {
            get
            {
                return ( iHandlers.ActiveScheduler != 0 );
            }
        }

        public TThreadWaitType WaitType
        {
            get
            {
                TThreadWaitType waitType = TThreadWaitType.EThreadWaitingUnknown;
                //
                if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.EWaitDfc )
                {
                    waitType = TThreadWaitType.EThreadWaitingOnDfc;
                }
                else if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.EReady )
                {
                    waitType = TThreadWaitType.EThreadWaitingReady;
                }
                else if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.ESuspended )
                {
                    waitType = TThreadWaitType.EThreadWaitingOnResumption;
                }
                else if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.EBlocked )
                {
                    bool blockdOnSemaphore = IsBlockedOnSemaphore;
                    if ( blockdOnSemaphore )
                    {
                        waitType = TThreadWaitType.EThreadWaitingOnSemaphore;
                    }
                }
                else if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.EWaitFastSemaphore )
                {
                    // Check that the fast semaphore is definitely the NThread's request semaphore.
                    uint nThreadRequestSemaphoreAddress = NThread.RequestSemaphoreAddress;
                    if ( NThread.WaitObj != 0 && NThread.WaitObj == nThreadRequestSemaphoreAddress )
                    {
                        CrashDebuggerLib.Structures.NThread.NThread.TWaitType nThreadWaitType = NThread.WaitType;
                        //
                        if ( nThreadWaitType == CrashDebuggerLib.Structures.NThread.NThread.TWaitType.EWaitTypeUserWaitForAnyRequest )
                        {
                            if ( HasActiveScheduler )
                            {
                                waitType = TThreadWaitType.EThreadWaitingOnRequestSemaphoreInsideSchedulerWaitLoop;
                            }
                            else
                            {
                                waitType = TThreadWaitType.EThreadWaitingOnRequestSemaphore;
                            }
                        }
                        else if ( nThreadWaitType == CrashDebuggerLib.Structures.NThread.NThread.TWaitType.EWaitTypeUserWaitForRequest )
                        {
                            waitType = TThreadWaitType.EThreadWaitingOnRequestSemaphore;
                        }
                    }
                }
                //
                return waitType;
            }
        }

        public bool IsUserThread
        {
            get
            {
                bool ret = false;
                //
                DProcess parent = OwningProcess;
                if ( parent != null )
                {
                    string name = parent.Name.ToLower();
                    ret = ( name != Platform.ProcessNames.KKernel.ToLower() );
                }
                //
                return ret;
            }
        }

        public bool IsCurrent
        {
            get
            {
                bool ret = CrashDebugger.IsCurrentThread( this );
                return ret;
            }
        }
        #endregion

        #region Internal methods
        private bool IsBlockedOnSemaphore
        {
            get
            {
                bool ret = false;
                //
                if ( NThread.NState == CrashDebuggerLib.Structures.NThread.NThread.TNThreadState.EBlocked )
                {
                    Register.RegisterEntry linkReg = NThread.Registers[ "R14_USR" ];
                    if ( linkReg.Symbol != null )
                    {
                        string symbolText = linkReg.Symbol.Name;
                        if ( symbolText.Contains( "RSemaphore::Wait" ) || symbolText.Contains( "RCriticalSection::Wait" ) )
                        {
                            ret = true;
                        }
                        else if ( symbolText.Contains( "Exec::SemaphoreWait" ) )
                        {
                            ret = true;
                        }
                    }
                }
                //
                return ret;
            }
        }
        #endregion

        #region Internal constants
        #endregion

        #region From DBase
        public override string ToClipboard()
        {
            StringBuilder ret = new StringBuilder();
            //
            ret.AppendLine( base.ToClipboard() );
            ret.AppendFormat( "MState: {0}, Id: {1}, ExitInfo: {2}" + System.Environment.NewLine, MState, Id, ExitInfo );
            ret.AppendLine( iNThread.ToClipboard() );
            ret.AppendLine( iStackInfoUser.ToClipboard() );
            ret.AppendLine( iStackInfoSupervisor.ToClipboard() );
            //
            return ret.ToString();
        }
        #endregion

        #region From System.Object
        public override string ToString()
        {
            return base.ToString();
        }
        #endregion

        #region Data members
        private readonly NThread.NThread iNThread;
        private readonly ThreadStackInfo iStackInfoSupervisor;
        private readonly ThreadStackInfo iStackInfoUser;

        private TThreadState iState = TThreadState.EUnknown;
        private TThreadFlags iFlags = TThreadFlags.EThreadFlagNone;
        
        private uint iStateWaitObjectAddress = 0;
        private uint iHandles = 0;
        private long iId = 0;
        private uint iFrame = 0;
        private uint iIpcCount = 0;

        private ThreadAllocatorInfo iAllocatorInfo = new ThreadAllocatorInfo();
        private ThreadPriorities iPriorities = new ThreadPriorities();
        private ExitInfo iExitInfo = new ExitInfo();
        private ThreadHandlers iHandlers = new ThreadHandlers();
        private ThreadTemporaries iTemporaries = new ThreadTemporaries();
        #endregion
    }
}