From 3d66a56851515eb95b5d8c50459880b6993de56e Mon Sep 17 00:00:00 2001 From: aleherbau Date: Tue, 24 May 2011 14:10:19 +0000 Subject: TCF Python: Implemented SysMonitor service proxy --- python/src/tcf/services/remote/SysMonitorProxy.py | 77 +++++ python/src/tcf/services/sysmonitor.py | 402 ++++++++++++++++++++++ python/src/tcf/tests/BasicTests.py | 47 +++ python/todo.twiki | 4 +- 4 files changed, 528 insertions(+), 2 deletions(-) create mode 100644 python/src/tcf/services/remote/SysMonitorProxy.py create mode 100644 python/src/tcf/services/sysmonitor.py diff --git a/python/src/tcf/services/remote/SysMonitorProxy.py b/python/src/tcf/services/remote/SysMonitorProxy.py new file mode 100644 index 000000000..04aad1969 --- /dev/null +++ b/python/src/tcf/services/remote/SysMonitorProxy.py @@ -0,0 +1,77 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. and others. +# * All rights reserved. self program and the accompanying materials +# * are made available under the terms of the Eclipse Public License v1.0 +# * which accompanies self distribution, and is available at +# * http://www.eclipse.org/legal/epl-v10.html +# * +# * Contributors: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +from tcf.services import sysmonitor +from tcf.channel.Command import Command + +class SysMonitorProxy(sysmonitor.SysMonitorService): + def __init__(self, channel): + self.channel = channel + + def getChildren(self, parent_context_id, done): + done = self._makeCallback(done) + service = self + class GetChildrenCommand(Command): + def __init__(self): + super(GetChildrenCommand, self).__init__(service.channel, service, "getChildren", (parent_context_id,)) + def done(self, error, args): + contexts = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + contexts = args[1] + done.doneGetChildren(self.token, error, contexts) + return GetChildrenCommand().token + + def getContext(self, id, done): + done = self._makeCallback(done) + service = self + class GetContextCommand(Command): + def __init__(self): + super(GetContextCommand, self).__init__(service.channel, service, "getContext", (id,)) + def done(self, error, args): + ctx = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + if args[1]: ctx = sysmonitor.SysMonitorContext(args[1]) + done.doneGetContext(self.token, error, ctx) + return GetContextCommand().token + + def getCommandLine(self, id, done): + done = self._makeCallback(done) + service = self + class GetCommandLineCommand(Command): + def __init__(self): + super(GetCommandLineCommand, self).__init__(service.channel, service, "getCommandLine", (id,)) + def done(self, error, args): + arr = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + arr = args[1] + done.doneGetCommandLine(self.token, error, arr) + return GetCommandLineCommand().token + + def getEnvironment(self, id, done): + done = self._makeCallback(done) + service = self + class GetEnvironmentCommand(Command): + def __init__(self): + super(GetEnvironmentCommand, self).__init__(service.channel, service, "getEnvironment", (id,)) + def done(self, error, args): + arr = None + if not error: + assert len(args) == 2 + error = self.toError(args[0]) + arr = args[1] + done.doneGetCommandLine(self.token, error, arr) + return GetEnvironmentCommand().token diff --git a/python/src/tcf/services/sysmonitor.py b/python/src/tcf/services/sysmonitor.py new file mode 100644 index 000000000..0b5c4f71c --- /dev/null +++ b/python/src/tcf/services/sysmonitor.py @@ -0,0 +1,402 @@ +# ******************************************************************************* +# * Copyright (c) 2011 Wind River Systems, Inc. and others. +# * All rights reserved. This program and the accompanying materials +# * are made available under the terms of the Eclipse Public License v1.0 +# * which accompanies this distribution, and is available at +# * http://www.eclipse.org/legal/epl-v10.html +# * +# * Contributors: +# * Wind River Systems - initial API and implementation +# ******************************************************************************* + +""" +This is an optional service that can be implemented by a peer. +If implemented, the service can be used for monitoring system activity and utilization. +It provides list of running processes, different process attributes like command line, environment, etc., +and some resource utilization data. The service can be used by a client to provide functionality +similar to Unix 'top' utility or Windows 'Task Manager'. +""" + +from tcf import services + +NAME = "SysMonitor" + +# Context property names. +# The TCF context ID""" +PROP_ID = "ID" + +# The TCF parent context ID +PROP_PARENTID = "ParentID" + +# Current working directory of the process +PROP_CWD = "CWD" + +# The process's root directory (as set by chroot) +PROP_ROOT = "Root" + +# User ID of the process owner +PROP_UID = "UID" + +# Group ID of the process owner +PROP_UGID = "UGID" + +# User name of the process owner +PROP_USERNAME = "UserName" + +# Group name of the process owner +PROP_GROUPNAME = "GroupName" + +# System process ID +PROP_PID = "PID" + +# Executable file of the process +PROP_FILE = "File" + +# One character from the string "RSDZTW" where R is running, S is +# sleeping in an interruptible wait, D is waiting in uninterruptible +# disk sleep, Z is zombie, T is traced or stopped (on a signal), and W +# is paging. +PROP_STATE = "State" + +# System ID of the parent process +PROP_PPID = "PPID" + +# The process group ID of the process +PROP_PGRP = "PGRP" + +# The session ID of the process +PROP_SESSION = "Session" + +# The tty the process uses +PROP_TTY = "TTY" + +# The process group ID of the process which currently owns the tty that +# the process is connected to. +PROP_TGID = "TGID" + +# ID of a process that has attached this process for tracing or debugging +PROP_TRACERPID = "TracerPID" + +# The kernel flags word of the process. Details depend on the kernel +PROP_FLAGS = "Flags" + +# The number of minor faults the process has made which have not +# required loading a memory page from disk +PROP_MINFLT = "MinFlt" + +# The number of minor faults that the process's waited-for children have made +PROP_CMINFLT = "CMinFlt" + +# The number of major faults the process has made which have required +# loading a memory page from disk +PROP_MAJFLT = "MajFlt" + +# The number of major faults that the process's waited-for children +# have made +PROP_CMAJFLT = "CMajFlt" + +# The number of milliseconds that this process has been scheduled in user mode +PROP_UTIME = "UTime" + +# The number of milliseconds that this process has been scheduled in kernel mode +PROP_STIME = "STime" + +# The number of jiffies that this process's waited-for children have +# been scheduled in user mode +PROP_CUTIME = "CUTime" + +# The number of jiffies that this process's waited-for children have +# been scheduled in user mode +PROP_CSTIME = "CSTime" + +# The standard nice value +PROP_PRIORITY = "Priority" + +# The nice value +PROP_NICE = "Nice" + +# The time in milliseconds before the next SIGALRM is sent to the process +# due to an interval timer +PROP_ITREALVALUE = "ITRealValue" + +# The time in milliseconds the process started after system boot +PROP_STARTTIME = "StartTime" + +# Virtual memory size in bytes +PROP_VSIZE = "VSize" + +# Memory pages size in bytes +PROP_PSIZE = "PSize" + +# Resident Set Size: number of pages the process has in real memory, +# minus used for administrative purposes. This is just the pages which +# count towards text, data, or stack space. This does not include +# pages which have not been demand-loaded in, or which are swapped out +PROP_RSS = "RSS" + +# Current limit in bytes on the rss of the process +PROP_RLIMIT = "RLimit" + +# The address above which program text can run +PROP_CODESTART = "CodeStart" + +# The address below which program text can run +PROP_CODEEND = "CodeEnd" + +# The address of the start of the stack +PROP_STACKSTART = "StackStart" + +# The bitmap of pending signals +PROP_SIGNALS = "Signals" + +# The bitmap of blocked signals +PROP_SIGBLOCK = "SigBlock" + +# The bitmap of ignored signals +PROP_SIGIGNORE = "SigIgnore" + +# The bitmap of caught signals +PROP_SIGCATCH = "SigCatch" + +# This is the "channel" in which the process is waiting. It is the +# address of a system call, and can be looked up in a name list if you +# need a textual name +PROP_WCHAN = "WChan" + +# Number of pages swapped +PROP_NSWAP = "NSwap" + +# Cumulative NSwap for child processes +PROP_CNSWAP = "CNSwap" + +# Signal to be sent to parent when this process exits +PROP_EXITSIGNAL = "ExitSignal" + +# CPU number last executed on +PROP_PROCESSOR = "Processor" + +# Real-time scheduling priority +PROP_RTPRIORITY = "RTPriority" + +# Scheduling policy +PROP_POLICY = "Policy" + + +class SysMonitorContext(object): + """ + A context corresponds to an execution thread, process, address space, etc. + A context can belong to a parent context. Contexts hierarchy can be simple + plain list or it can form a tree. It is up to target agent developers to choose + layout that is most descriptive for a given target. Context IDs are valid across + all services. In other words, all services access same hierarchy of contexts, + with same IDs, however, each service accesses its own subset of context's + attributes and functionality, which is relevant to that service. + """ + def __init__(self, props): + self._props = props or {} + + def __str__(self): + return "[Sys Monitor Context %s]" % self._props + + def getID(self): + """ + Get context ID. + Same as getProperties().get("ID") + """ + return self._props.get(PROP_ID) + + def getParentID(self): + """ + Get parent context ID. + Same as getProperties().get("ParentID") + """ + return self._props.get(PROP_PARENTID) + + def getPGRP(self): + """ + Get process group ID. + Same as getProperties().get("PGRP") + """ + return self._props.get(PROP_PGRP, -1) + + def getPID(self): + """ + Get process ID. + Same as getProperties().get("PID") + """ + return self._props.get(PROP_PID, -1) + + def getPPID(self): + """ + Get process parent ID. + Same as getProperties().get("PPID") + """ + return self._props.get(PROP_PPID, -1) + + def getTGID(self): + """ + Get process TTY group ID. + Same as getProperties().get("TGID") + """ + return self._props.get(PROP_TGID, -1) + + def getTracerPID(self): + """ + Get tracer process ID. + Same as getProperties().get("TracerPID") + """ + return self._props.get(PROP_TRACERPID, -1) + + def getUID(self): + """ + Get process owner user ID. + Same as getProperties().get("UID") + """ + return self._props.get(PROP_UID, -1) + + def getUserName(self): + """ + Get process owner user name. + Same as getProperties().get("UserName") + """ + return self._props.get(PROP_USERNAME) + + def getUGID(self): + """ + Get process owner user group ID. + Same as getProperties().get("UGID") + """ + return self._props.get(PROP_UGID, -1) + + def getGroupName(self): + """ + Get process owner user group name. + Same as getProperties().get("GroupName") + """ + return self._props.get(PROP_GROUPNAME) + + def getState(self): + """ + Get process state. + Same as getProperties().get("State") + """ + return self._props.get(PROP_STATE) + + def getVSize(self): + """ + Get process virtual memory size in bytes. + Same as getProperties().get("VSize") + """ + return self._props.get(PROP_VSIZE, -1) + + def getPSize(self): + """ + Get process virtual memory page size in bytes. + Same as getProperties().get("PSize") + """ + return self._props.get(PROP_PSIZE, -1) + + def getRSS(self): + """ + Get number of memory pages in process resident set. + Same as getProperties().get("RSS") + """ + return self._props.get(PROP_RSS, -1) + + def getFile(self): + """ + Get context executable file. + Same as getProperties().get("File") + """ + return self._props.get(PROP_FILE) + + def getRoot(self): + """ + Get context current file system root. + Same as getProperties().get("Root") + """ + return self._props.get(PROP_ROOT) + + def getCurrentWorkingDirectory(self): + """ + Get context current working directory. + Same as getProperties().get("CWD") + """ + return self._props.get(PROP_CWD) + + def getProperties(self): + """ + Get all available context properties. + @return Map 'property name' -> 'property value' + """ + return self._props + + +class SysMonitorService(services.Service): + def getName(self): + return NAME + + def getContext(self, id, done): + """ + Retrieve context info for given context ID. + + @param id - context ID. + @param done - callback interface called when operation is completed. + """ + raise NotImplementedError("Abstract method") + + def getChildren(self, parent_context_id, done): + """ + Retrieve children of given context. + + @param parent_context_id - parent context ID. Can be null - + to retrieve top level of the hierarchy, or one of context IDs retrieved + by previous getContext or getChildren commands. + @param done - callback interface called when operation is completed. + """ + raise NotImplementedError("Abstract method") + + def getCommandLine(self, id, done): + """ + Get context command line. + """ + raise NotImplementedError("Abstract method") + + def getEnvironment(self, id, done): + """ + Get context environment variables. + """ + raise NotImplementedError("Abstract method") + + +class DoneGetContext(object): + """ + Client callback interface for getContext(). + """ + def doneGetContext(self, token, error, context): + """ + Called when context data retrieval is done. + @param error - error description if operation failed, null if succeeded. + @param context - context data. + """ + pass + +class DoneGetChildren(object): + """ + Client callback interface for getChildren(). + """ + def doneGetChildren(self, token, error, context_ids): + """ + Called when context list retrieval is done. + @param error - error description if operation failed, null if succeeded. + @param context_ids - array of available context IDs. + """ + pass + +class DoneGetCommandLine(object): + def doneGetCommandLine(self, token, error, cmd_line): + pass + +class DoneGetEnvironment(object): + def doneGetEnvironment(self, token, error, environment): + pass diff --git a/python/src/tcf/tests/BasicTests.py b/python/src/tcf/tests/BasicTests.py index 044f94452..fd151f2f2 100644 --- a/python/src/tcf/tests/BasicTests.py +++ b/python/src/tcf/tests/BasicTests.py @@ -55,6 +55,7 @@ def test(): testMemory(c) testMemoryMap(c) testPathMap(c) + testSysMonitor(c) except Exception as e: protocol.log(e) @@ -547,5 +548,51 @@ def testPathMap(c): map = pm.get().get() print "Path map:", map +def testSysMonitor(c): + cmd = sync.CommandControl(c) + try: + sm = cmd.SysMonitor + except AttributeError: + # no SysMonotor service + return + lock = threading.Condition() + from tcf.services import sysmonitor + processes = [] + def getProcesses(): + sm = c.getRemoteService(sysmonitor.NAME) + pending = [] + class DoneGetChildren(sysmonitor.DoneGetChildren): + def doneGetChildren(self, token, error, context_ids): + pending.remove(token) + if error: + protocol.log("Error from SysMonitor.getChildren", error) + else: + class DoneGetContext(sysmonitor.DoneGetContext): + def doneGetContext(self, token, error, context): + pending.remove(token) + if error: + protocol.log("Error from SysMonitor.getContext", error) + else: + processes.append(context) + if not pending: + with lock: + lock.notify() + for id in context_ids: + pending.append(sm.getContext(id, DoneGetContext())) + if not pending: + with lock: + lock.notify() + pending.append(sm.getChildren(None, DoneGetChildren())) + with lock: + protocol.invokeLater(getProcesses) + lock.wait(5000) + print "%d processes found:" % len(processes) + for p in processes: + print p + cmdl = sm.getCommandLine(p.getID()).get() + if cmdl: print "Command line: ", cmdl + envp = sm.getEnvironment(p.getID()).get() + print "Environment: ", envp + if __name__ == '__main__': test() diff --git a/python/todo.twiki b/python/todo.twiki index 94f41f9e3..0d0e9ed2f 100644 --- a/python/todo.twiki +++ b/python/todo.twiki @@ -24,8 +24,8 @@ * [done] Diagnostics * Disassembly * [done] Streams - * Terminals - * SysMonitor + * [done] Terminals + * [done] SysMonitor * Local services: * [incomplete] ZeroCopy * [95%] Locator service (discovery) -- cgit v1.2.3